Quarkus with custom main method - quarkus

Is it possible to provide a custom main(String[] args) method for a Quarkus application? Or is there any other way to access the command line arguments?
The use case would be to build a native image to be used as a command line tool.

This is now officially supported :) https://quarkus.io/guides/lifecycle
import io.quarkus.runtime.annotations.QuarkusMain;
import io.quarkus.runtime.Quarkus;
#QuarkusMain
public class Main {
public static void main(String ... args) {
System.out.println("Running main method");
Quarkus.run(args);
}
}

Currently Quarkus doesn't support this use case, however it is definitely on the roadmap, see: https://github.com/quarkusio/quarkus/issues/284
Update: see https://stackoverflow.com/a/61665893/2504224 for the supported way of doing this

Related

How to write script in gradle that execute particular methods?

I am writing a gradle script that runs all tests before making a build.
test {
filter {
includeTestsMatching "*TestAll*"
includeTestsMatching "*ExtensionValidatorTest*"
........
}
}
I have three tests of different versions(v1,v2,v3).
TestAll.java
package .....v1;//v2 for version 2 and v3 for version 3
#RunWith(Suite.class)
#Suite.SuiteClasses({
A.class,
B.class,
......
})
public class TestAll {
#BeforeClass
public static void setUp() {//connection to database
........
}
#AfterClass
public static void tearDown() {//close database connection
........
}
}
When I run gradle test connection to database is broken after execution of a particular TestAll. I do not want to change the TestAll files of any version as they can be run and tested independently. How can I make gradle run only setUp once(of any version)which establishes connection, then run all the TestAll method in v1,v2 and v3 and finally teardown(of any version) which terminates database connection.
Gradle won't help you with this. There are following methods in Gradle DSL:
test {
beforeSuite{...}
afterSuite{...}
}
However, they execute outside of the test runtime scope and intended for logging. You only can achieve this using a testing framework.
TestNG provides a simple solution - #BeforeSuite and #AfterSuite annotations, that are actually run once before and after the entire suite.
Unfortunately, JUnit doesn't have a built-in solution for that, since test isolation is its core concept. Nevertheless, you still can make your own. You need to encapsulate database-related API into a singleton class:
public class DbContainer() {
private static DbContainer container;
private DbContaner() {}
public DbContainer getInstance() {
if (container == null) {
container = new DbContainer()
}
return container;
}
public void openConnection() {
// ...
}
public void closeConnection() {
// ...
}
// here is your database API methods
}
Then you can share this instance between test methods and classes using #ClassRule annotation:
#ClassRule
public static DbContainer db = DbContainer.getInstance();
#Test
public void someTest() {
db.query(...)
}
Note: provided solution is not thread-safe and doesn't suit the parallel execution. Some additional effort is required to achieve it.

Logging with XQuery

I'm using XQuery 3.0 to transform an incoming message to fit my system.
The XQuery is called from an Apache Camel Route via the transform EIP.
Example:
transform().xquery("resource:classpath:xquery/myxquery.xquery",String.class)
While the transformation works without problems it would be nice, since it's partly very complex, to be able to log some informations directly during the transformation process.
So I wanted to ask if it is possible to log "into" logback directly from XQuery?
I already searched stackoverflow and of course https://www.w3.org/TR/xquery-30-use-cases/ and other sources, but I just couldn't find any information about how to log in Xquery.
My project structure is:
Spring-Boot 2 application
Apache-Camel as Routing framework
Logback as Logging framework
Update: For the integration of XQuery in the Apache-Camel Framework I use the org.apache.camel:camel-saxon-starter:2.22.2.
Update: Because the use of fn:trace was kind of ugly I searched further and now I use the extension mechanism from Saxon to provide different logging functions which can be accessed via xquery:
For more information see the documentation: http://www.saxonica.com/documentation/#!extensibility/integratedfunctions/ext-full-J
Here is what I did for logging (tested with Saxon-HE, Camel is not mandatory, I just use it by coincidence):
First step:
Extend the class net.sf.saxon.lib.ExtensionFunctionDefinition
public class XQueryInfoLogFunctionDefinition extends ExtensionFunctionDefinition{
private static final Logger log = LoggerFactory.getLogger(XQueryInfoLogFunctionDefinition.class);
private final XQueryInfoExtensionFunctionCall functionCall = new XQueryInfoExtensionFunctionCall();
private static final String PREFIX = "log";
#Override
public StructuredQName getFunctionQName() {
return new StructuredQName(PREFIX, "http://thehandofnod.com/saxon-extension", "info");
}
#Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[] { SequenceType.SINGLE_STRING };
}
#Override
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
return SequenceType.VOID;
}
#Override
public ExtensionFunctionCall makeCallExpression() {
return functionCall;
}
}
Second step:
Implement the FunctionCall class
public class XQueryInfoExtensionFunctionCall extends ExtensionFunctionCall {
private static final Logger log = LoggerFactory.getLogger(XQueryInfoLogFunctionDefinition.class);
#Override
public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
if (arguments != null && arguments.length > 0) {
log.info(((StringValue) arguments[0]).getStringValue());
} else
throw new IllegalArgumentException("We need a message");
return EmptySequence.getInstance();
}
}
Third step:
Configure the SaxonConfiguration and bind it into the camel context:
public static void main(String... args) throws Exception {
Main main = new Main();
Configuration saxonConfig = Configuration.newConfiguration();
saxonConfig.registerExtensionFunction(new XQueryInfoLogFunctionDefinition());
main.bind("saxonConfig", saxonConfig);
main.addRouteBuilder(new MyRouteBuilder());
main.run(args);
}
Fourth step:
Define the SaxonConfig in your XQueryEndpoint:
.to("xquery:test.xquery?configuration=#saxonConfig");
Fifth step:
Call it in your xquery:
declare namespace log="http://thehandofnod.com/saxon-extension";
log:info("Das ist ein INFO test")
Original post a.k.a How to overwrite the fn:trace Funktion:
Thanks to Martin Honnen I tried the fn:trace function. Problem was that by default it logs into the System.err Printstream and that's not what I wanted, because I wanted to combine the fn:trace function with the Logback Logging-Framework.
So I debugged the net.sf.saxon.functions.Trace methods and came to the following solution for my project setup.
Write a custom TraceListener which extends from net.sf.saxon.trace.XQueryTraceListener and implement the methods enter and leave in a way that the InstructionInfo with constructType == 2041 (for user-trace) is forwarded to the SLF4J-API. Example (for only logging the message):
#Override
public void enter(InstructionInfo info, XPathContext context) {
// no call to super to keep it simple.
String nachricht = (String) info.getProperty("label");
if (info.getConstructType() == 2041 && StringUtils.hasText(nachricht)) {
getLogger().info(nachricht);
}
}
#Override
public void leave(InstructionInfo info) {
// no call to super to keep it simple.
}
set the custom trace listener into your net.sf.saxon.Configuration Bean via setTraceListener
Call your xquery file from camel via the XQueryEndpoint because only there it is possible to overwrite the Configuration with an option: .to("xquery:/xquery/myxquery.xquery?configuration=#saxonConf"). Unfortunately the transform().xquery(...) uses it's own objects without the possibility to configure them.
call {fn:trace($element/text(),"Das ist ein Tracing Test")} in your xquery and see the message in your log.

How to access same ClassPathXmlApplicationContext instance from 2 main methods

I've to write a quartz scheduler to run a job in Spring. I've to also add another function to pause the same job. This code is present inside a single standalone batch.
To trigger these 2 functions:
1. start the job
2. pause the job
I've written 2 classes with main() which does the execution.
The issue is when I trigger the main() for pauseJob, it starts the different applicationContext instead of using the same one. I've used a Singleton pattern for applicationContext initialization.
Singleton class for ApplicationContext initialization
public class AppContext {
private static ApplicationContext INSTANCE = null;
private AppContext() {
}
public static ApplicationContext getIntance() {
if (INSTANCE == null) {
String[] contexts = new String[] {"classpath:/applicationContext.xml"};
INSTANCE = new ClassPathXmlApplicationContext(contexts);
}
return INSTANCE;
}
}
Class to start the Job
public class StartJobQuartzMain {
public static void main(String[] args) throws Exception {
AppContext.getIntance();
}
}
Class to pause the job
public class PauseJobQuartzMain {
public static void main(String[] args) throws Exception {
((TestPauseJob) AppContext.getIntance().getBean("testPauseJob")).pauseJob();
}
}
Kindly guide me on how to fetch the same applicationContext instance in PauseJobQuartzMain.java. Thanks.
Making it a singleton has nothing to do with it (it is in a way required)... The two 'java' main classes will run independent of each other, as in, they are two different programs, with their own Java Virtual Machine, and will not be able to share your application context with each other.
You can use database or an external file (accessible by both) or something to achieve this...
Hope this helps...
You can’t do that from another main class because you run it definitely from a fresh JVM. So each of them has their own Singleton. You can consider to use some shared resource between two these apps: db, file, JMS queue finally etc. or you can call some managed operation over JMX. But two JVMs can’t share memory, especially Java objects, when application context is one of them.

#Lock(LockType.READ) Singleton Ejb in java 8

Using Java 7 with Jboss7 the following code used to work.
#Singleton
public class OperacaoServiceImpl implements OperacaoService {
private Operacao operacaoEmAndamento;
#Override
#Lock(LockType.READ)
public Operacao getOperacaoEmAndamento() {
return operacaoEmAndamento;
}
#Override
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void geraEIniciaOperacao() throws CoreException {
geraOperacao();
iniciaOperacao();
}
}
Now I've migrated to Java 8 with Wildfly it stopped working. If geraEIniciaOperacao is still running, I can't access getOperacaoEmAndamento.
" javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0241: EJB 3.1
PFD2 4.8.5.5.1 concurrent access timeout on OperacaoServiceImpl -
could not obtain lock within 5000MILLISECONDS at
org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:106)
..."
I couldn't understand why something like this used to work. But what I've found is: with container managed concurrency the semantics is "concurrent reads are allowed as long as no writing is going on". What I need is "concurrent reads are allowed, also while writing goes on, but only one thread will be writing at a time". To achieve that I've changed the class to
#Lock(LockType.READ)
#Singleton
public class OperacaoServiceImpl implements OperacaoService {
and the method
public void geraEIniciaOperacao() throws CoreException {
to
syncronized public void geraEIniciaOperacao() throws CoreException {
Reference: EJB 3.1 container managed concurrency vs. synchronized

Server-side schema validation with JAX-WS

I have JAX-WS container-less service (published via Endpoint.publish() right from main() method). I want my service to validate input messages. I have tried following annotation: #SchemaValidation(handler=MyErrorHandler.class) and implemented an appropriate class. When I start the service, I get the following:
Exception in thread "main" javax.xml.ws.WebServiceException:
Annotation #com.sun.xml.internal.ws.developer.SchemaValidation(outbound=true,
inbound=true, handler=class mypackage.MyErrorHandler) is not recognizable,
atleast one constructor of class
com.sun.xml.internal.ws.developer.SchemaValidationFeature
should be marked with #FeatureConstructor
I have found few solutions on the internet, all of them imply the use of WebLogic container. I can't use container in my case, I need embedded service. Can I still use schema validation?
The #SchemaValidation annotation is not defined in the JAX-WS spec, but validation is left open. This means you need something more than only the classes in the jdk.
As long as you are able to add some jars to your classpath, you can set this up pretty easily using metro (which is also included in WebLogic. This is why you find solutions that use WebLogic as container.). To be more precise, you need to add two jars to your classpath. I'd suggest to
download the most recent metro release.
Unzip it somewhere.
Add the jaxb-api.jar and jaxws-api.jar to your classpath. You can do this for example by putting them into the JAVA_HOME/lib/endorsed or by manually adding them to your project. This largely depends on the IDE or whatever you are using.
Once you have done this, your MyErrorHandler should work even if it is deployed via Endpoint.publish(). At least I have this setup locally and it compiles and works.
If you are not able to modify your classpath and need validation, you will have to validate the request manually using JAXB.
Old question, but I solved the problem using the correct package and minimal configuration, as well using only provided services from WebLogic. I was hitting the same problem as you.
Just make sure you use correct java type as I described here.
As I am planning to expand to a tracking mechanism I also implemented the custom error handler.
Web Service with custom validation handler
import com.sun.xml.ws.developer.SchemaValidation;
#Stateless
#WebService(portName="ValidatedService")
#SchemaValidation(handler=MyValidator.class)
public class ValidatedService {
public ValidatedResponse operation(#WebParam(name = "ValidatedRequest") ValidatedRequest request) {
/* do business logic */
return response;
}
}
Custom Handler to log and store error in database
public class MyValidator extends ValidationErrorHandler{
private static java.util.logging.Logger log = LoggingHelper.getServerLogger();
#Override
public void warning(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void error(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void fatalError(SAXParseException exception) throws SAXException {
handleException(exception);
}
private void handleException(SAXParseException e) throws SAXException {
log.log(Level.SEVERE, "Validation error", e);
// Record in database for tracking etc
throw e;
}
}

Resources