I have a Liberty JAX-RS 2.0 Application on Bluemix. My goal is to use the Bluemix Session Cache Service as a central session storage.
In my interface, I inject the HttpRequest object like this:
#Path("/resource")
public class MyResource {
#Post
public Response myOperation(..., #Context final HttpServletRequest httpRequest) {
...
}
}
This runs fine with just Liberty on its own (without Session Cache Binding on Bluemix). I do not even access the httpRequest in my test app, nor do I access httpRequest.getSession(). Once I bind the Session Cache service to the Liberty App and restage the app, I get the following upon calling the API:
java.lang.NullPointerException:
at com.ibm.ws.xs.sessionmanager.IBMHttpSessionListener.attributeAdded(IBMHttpSessionListener.java:265)
at com.ibm.ws.session.http.HttpSessionAttributeObserver.sessionAttributeSet(HttpSessionAttributeObserver.java:141)
at [internal classes]
at org.jboss.weld.context.AbstractConversationContext.copyConversationIdGeneratorAndConversationsToSession(AbstractConversationContext.java:188)
at org.jboss.weld.context.AbstractConversationContext.sessionCreated(AbstractConversationContext.java:196)
at org.jboss.weld.servlet.ConversationContextActivator.sessionCreated(ConversationContextActivator.java:190)
at [internal classes]
As requested, the server.xml - which is generated by Bluemix on deployment.
<server>
<featureManager>
<feature>jaxrs-2.0</feature>
<feature>jsonp-1.0</feature>
<feature>couchdb-1.0</feature>
<feature>ejb-3.2</feature>
<feature>cdi-1.2</feature>
<feature>icap:managementConnector-1.0</feature>
<feature>appstate-1.0</feature>
<feature>cloudAutowiring-1.0</feature>
<feature>eXtremeScale.webapp-1.1</feature>
</featureManager>
<application name='myapp' location='myapp.war' type='war' context-root='some-app'>
<classloader commonLibraryRef='cloudantNoSQLDB-library'/>
</application>
<cdi12 enableImplicitBeanArchives='false'/>
<httpEndpoint id='defaultHttpEndpoint' host='*' httpPort='${port}'/>
<webContainer trustHostHeaderPort='true' extractHostHeaderPort='true'/>
<include location='runtime-vars.xml'/>
<logging logDirectory='${application.log.dir}' consoleLogLevel='INFO'/>
<httpDispatcher enableWelcomePage='false'/>
<applicationMonitor dropinsEnabled='false' updateTrigger='mbean'/>
<config updateTrigger='mbean'/>
<appstate appName='myapp' markerPath='${home}/../.liberty.state'/>
<couchdb id='cloudantNoSQLDB-ith-auth-db' jndiName='couchdb/ith-auth-db' libraryRef='cloudantNoSQLDB-library' username='${cloud.services.ith-auth-db.connection.username}' password='${cloud.services.ith-auth-db.connection.password}' url='${cloud.services.ith-auth-db.connection.url}' enableSSL='true' host='${cloud.services.ith-auth-db.connection.host}' port='${cloud.services.ith-auth-db.connection.port}'/>
<library id='cloudantNoSQLDB-library'>
<fileset id='cloudantNoSQLDB-fileset' dir='${server.config.dir}/lib' includes='commons-codec-1.6.jar commons-io-2.0.1.jar commons-logging-1.1.3.jar httpclient-4.3.6.jar httpclient-cache-4.3.6.jar httpcore-4.3.3.jar jackson-annotations-2.2.2.jar jackson-core-2.2.2.jar jackson-databind-2.2.2.jar jcl-over-slf4j-1.6.6.jar org.ektorp-1.4.2.jar slf4j-api-1.6.6.jar slf4j-jdk14-1.6.6.jar'/>
</library>
<xsWebApp id='session-cache' objectGridName='${cloud.services.session-cache.connection.gridName}' catalogHostPort='${cloud.services.session-cache.connection.catalogEndPoint}' credentialGeneratorClass='com.ibm.websphere.objectgrid.security.plugins.builtins.UserPasswordCredentialGenerator' credentialGeneratorProps='${cloud.services.session-cache.connection.username} ${cloud.services.session-cache.connection.password}' objectGridType='REMOTE' securityEnabled='true'/>
So I guess something goes wrong with injecting the HttpRequest... how can I solve this?
Related
I run Red Hat middleware with CodeReady Studio 12.16.0.GA on standalone Spring-boot environment as local Camel context. I have local RabbitMQ running in Docker.
I have failed to setup any scenario using tutorials on web in/out JMS using Camel.
All tutorials don't use camel-context.xml configuration only pure java spring.
Please help me to configure camel-context.xml and all resource to use RabbitMQ or just any JMS.
Thanks in advance.
Here is simple camel-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring https://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route id="simple-route">
<from id="_to1" uri="jms:myQeue?connectionFactory=#myConnectionFactory&jmsMessageType=Text"/>
<log id="route-log" message=">>> ${body}"/>
</route>
</camelContext>
</beans>
and simple spring application to run it
package org.mycompany;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
#SpringBootApplication
#ImportResource({"classpath:spring/camel-context.xml"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But it went to exception
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jms://myQeue?connectionFactory=%23myConnectionFactory&jmsMessageType=Text due to: No bean could be found in the registry for: myConnectionFactory of type: javax.jms.ConnectionFactory
I have added registration of ConnectionFactory
ConnectionFactory myCF = new ConnectionFactory();
myCF.setUsername("guest");
myCF.setPassword("guest");
myCF.setVirtualHost("/");
myCF.setHost("localhost");
myCF.setPort(5672);
SimpleRegistry reg = new SimpleRegistry();
reg.put("myConnectionFactory", myCF);
CamelContext camContext = new DefaultCamelContext(reg);
but new exception arose I think because of using com.rabbitmq.client.ConnectionFactory
Caused by: org.apache.camel.FailedToCreateRouteException: Failed to create route simple-route: Route(simple-route)[[From[jms:queue:myQeue?connectionFactory... because of connectionFactory must be specified
How to define javax.jms.ConnectionFactory to registry?
I have a Java webapp where a REST call triggers a mail sent through a javax.mail.Session. The application is deployed as a .war archive that I want to test inside a JBoss EAP 7.2 server.
I am using Arquillian 1.5.0.Final and Citrus Framework version 2.8.0. My build system is Gradle 5.x and everything is using a Java 8 runtime.
I would like to create a Citrus mail endpoint and use Arquillian to provide this inside the JEE container. My experience with these frameworks is limited to a few days, so I'm starting with a sample application to gain more knowledge:
I have the following working against a simple web endpoint (The HelloServlet from https://guides.gradle.org/building-java-web-applications/):
#RunWith(Arquillian.class)
public class HelloServletTest {
#CitrusFramework
private Citrus citrusFramework;
#ArquillianResource
private URL baseUri;
private String serviceUri;
#Deployment(testable = false)
public static WebArchive createDeployment() {
final WebArchive war = ShrinkWrap.create(WebArchive.class)
.addClass(HelloServlet.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
// [...]
return war;
}
#Before
public void setUp() throws Exception {
serviceUri = new URL(baseUri, "hello").toExternalForm();
}
#Test
#CitrusTest
public void smokeTest(#CitrusResource TestDesigner designer) throws InterruptedException {
System.err.println("ServiceURI: " + serviceUri);
designer.send(serviceUri)
.message(new HttpMessage("?name=Jacob")
.method(HttpMethod.POST));
designer.receive(serviceUri).message(new HttpMessage("").status(HttpStatus.OK));
citrusFramework.run(designer.getTestCase());
}
}
I use #Deployment(testable=false) as this example runs a client-side test. However, my end goal is to use Citrus inside the container so my understanding is that I need to have #Deployment(testable=true). But when I run the test with testable=true a NPE is thrown:
java.lang.NullPointerException
at com.consol.citrus.annotations.CitrusAnnotations.injectAll(CitrusAnnotations.java:61)
at com.consol.citrus.arquillian.enricher.CitrusTestEnricher.enrich(CitrusTestEnricher.java:57)
at org.jboss.arquillian.junit.RulesEnricher.enrichInstances(RulesEnricher.java:85)
at org.jboss.arquillian.junit.RulesEnricher.enrichStatement(RulesEnricher.java:77)
[...]
at org.jboss.arquillian.core.impl.EventContextImpl.invokeObservers(EventContextImpl.java:103)
at org.jboss.arquillian.core.impl.EventContextImpl.proceed(EventContextImpl.java:90)
at org.jboss.arquillian.container.test.impl.client.ContainerEventController.createContext(ContainerEventController.java:128)
at org.jboss.arquillian.container.test.impl.client.ContainerEventController.createBeforeContext(ContainerEventController.java:114)
[...]
at org.jboss.arquillian.test.impl.EventTestRunnerAdaptor.fireCustomLifecycle(EventTestRunnerAdaptor.java:159)
at org.jboss.arquillian.junit.Arquillian$7.evaluate(Arquillian.java:273)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
[...]
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
[...]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.lang.Thread.run(Thread.java:748)
My arquillian.xml is
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 3.0"/>
<engine>
<property name="deploymentExportPath">build/deployments</property>
</engine>
<container qualifier="wildfly-managed" default="true">
</container>
<extension qualifier="citrus">
<property name="autoPackage">false</property>
<property name="citrusVersion">2.8.0</property>
</extension>
</arquillian>
My citrus-context.xml is
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus-mail="http://www.citrusframework.org/schema/mail/config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/mail/config http://www.citrusframework.org/schema/mail/config/citrus-mail-config.xsd">
<!-- Mail server mock -->
<citrus-mail:server id="mailServer"
auto-start="true"
port="2222"/>
</beans>
My questions are:
Does my approach make sense? Is it feasible to use Citrus and Arquillian in this way?
Is the NPE exception to be expected or am I missing some dependency or configuration?
In my project I have the following project structure:
I have a module that is producing a war file and can be deployed inside a Tomcat application server. This module has dependencies on Axis2 libraries:
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-http</artifactId>
</dependency>
<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-webapp</artifactId>
<type>war</type>
</dependency>
And this class contains an axis2.xml file in the conf folder under WEB-INF.
Now this module has a dependency on a unit module, that has the package type of a jar.
Now in my web-module, in the code for my stub I have following code:
GazelleObjectValidator.getInstance().validateObject();
The XcpdValidationService is a class in the jar module (dependency) and this method calls an external web service over SSL and using a proxy.
This web service client is generated by JAX WS RI
BUT this class doesn't use the axis2.xml configuration from the parent module and uses it's own axis configuration, being the default one, where my proxy is not configured...
#WebEndpoint(name = "GazelleObjectValidatorPort")
public GazelleObjectValidator getGazelleObjectValidatorPort() {
return super.getPort(new QName("http://ws.validator.sch.gazelle.ihe.net/", "GazelleObjectValidatorPort"), GazelleObjectValidator.class);
}
The method itself looks like this:
#WebMethod
#WebResult(name = "validationResult", targetNamespace = "")
#RequestWrapper(localName = "validateObject", targetNamespace = "http://ws.validator.sch.gazelle.ihe.net/", className = "net.ihe.gazelle.schematron.ValidateObject")
#ResponseWrapper(localName = "validateObjectResponse", targetNamespace = "http://ws.validator.sch.gazelle.ihe.net/", className = "net.ihe.gazelle.schematron.ValidateObjectResponse")
public String validateObject(
#WebParam(name = "base64ObjectToValidate", targetNamespace = "")
String base64ObjectToValidate,
#WebParam(name = "xmlReferencedStandard", targetNamespace = "")
String xmlReferencedStandard,
#WebParam(name = "xmlMetadata", targetNamespace = "")
String xmlMetadata)
throws SOAPException_Exception
;
My GazelleObjectValidatorService is generated by following plugin:
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-aar-maven-plugin</artifactId>
<version>${axis2.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>package-aar</id>
<phase>prepare-package</phase>
<goals>
<goal>aar</goal>
</goals>
</execution>
</executions>
<configuration>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/resources/wsdl</directory>
<outputDirectory>META-INF</outputDirectory>
<includes>
<include>**/*.xsd</include>
</includes>
</fileSet>
</fileSets>
<servicesXmlFile>${project.build.outputDirectory}/axis2/services.xml</servicesXmlFile>
<wsdlFile>${project.build.outputDirectory}/wsdl/ClientConnectorService.wsdl</wsdlFile>
</configuration>
</plugin>
I tried to override the transportSender in my axis2.xml configuration with my own defined MyCommonsHttpTransportSender:
<transportSender name="http"
class="eu.epsos.pt.cc.MyCommonsHTTPTransportSender">
<parameter name="PROTOCOL">HTTP/1.1</parameter>
<parameter name="Transfer-Encoding">chunked</parameter>
and
<transportSender name="https"
class="eu.epsos.pt.cc.MyCommonsHTTPTransportSender">
<parameter name="PROTOCOL">HTTP/1.1</parameter>
<parameter name="Transfer-Encoding">chunked</parameter>
</transportSender>
that knows about the proxy.
but unfortunately since the web service client is inside the jar that is a dependency of the war, it doesn't seem to use my axis2.xml configuration, but uses it's own axis configuration, which doesn't know about the proxy.
This causes the following error where you see clearly that it uses the default CommonsHTTPTransportSender and therefore throwing the error:
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.commons.httpclient.protocol.ReflectionSocketFactory.createSocket(ReflectionSocketFactory.java:140)
at org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory.createSocket(SSLProtocolSocketFactory.java:130)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.axis2.transport.http.AbstractHTTPSender.executeMethod(AbstractHTTPSender.java:621)
at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:193)
at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:404)
at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:231)
at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:443)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:406)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at org.apache.axis2.jaxws.core.controller.impl.AxisInvocationController.execute(AxisInvocationController.java:578)
at org.apache.axis2.jaxws.core.controller.impl.AxisInvocationController.doInvoke(AxisInvocationController.java:127)
at org.apache.axis2.jaxws.core.controller.impl.InvocationControllerImpl.invoke(InvocationControllerImpl.java:93)
at org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler.invokeSEIMethod(JAXWSProxyHandler.java:373)
... 40 common frames omitted
Is there a way to let the WS client in the child jar make use of the same axis2 configuration of the parent module (that is a deployable war and has the axis2 dependencies?)
UPDATE:
My WAR file has an axis2 configuration, from the source code of this war, a service generated with wsimport is called which is in a JAR that is a dependency of the parent WAR. This service calls an external WebService and this happens over Axis (although doesn't use the axis2.xml configuration file, since this one is in the WEB-INF folder of the JAR.
Wouldn't there be any possibility to make the external WebService call in the JAR without Axis and use just JAXWS? This would solve my problems...
Axis2 provides a convenient method to configure the HTTP Transport. So, following from your sample code:
HttpTransportProperties.ProxyProperties proxyProperties = new HttpTransportProperties.new ProxyProperties();
proxyProperties.setProxyHostName("hostName");
proxyProperties.setProxyPort("hostPort");
proxyProperties.setUsername("User");
proxyProperties.setPassword("pw");
//set the properties
objectValidatorService.getServiceClient().getOptions().setProperty(HttpConstants.PROXY, proxyProperties);
The above wouldn't work for you because you're using the stock JAX-WS implementation, not the Axis2-specific client.
Based on your stacktrace, it appears you're connecting to a TLS-secured endpoint. There's a solution for that
I've done a lot of research, and there's no access to the underlying HTTPUrlConnection using stock JAX-WS. What we do have, is a way to set a custom SSLContextFactory. So we start by creating a custom factory, that will connect to the proxy first:
public class CustomSocketFactory extends SSLProtocolSocketFactory {
private static final CustomSocketFactory factory = new CustomSocketFactory();
static CustomSocketFactory getSocketFactory(){
return factory;
}
public CustomSocketFactory() {
super();
}
#Override
public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) {
Socket socket = null;
try {
int proxyPort = 1000;
InetSocketAddress proxyAddr = new InetSocketAddress("proxyAddr", proxyPort);
Socket proxyConn = new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddr));
proxyConn.connect(new InetSocketAddress("endHost", 443));
socket = (SSLSocket) super.createSocket(proxyConn, "proxyEndpoint", proxyPort, true);
} catch (IOException ex) {
Logger.getLogger(CustomSocketFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return socket;
}
}
we'll now register this custom socket factory with the Apache HTTPClient runtime (Axis does not use the stock java HTTPUrlConnection, as is evidenced by your stacktrace):
Protocol.registerProtocol("https",new Protocol("https", new CustomSocketFactory(), 443));
This works only for TLS connections. (although, a custom socket factory is applicable to non-https endpoints also). You also need to set the timeout to 0 so we can guarantee that your overriden createSocket gets invoked
I am trying to implement a module to send messages from a CXF client to a server (SOAP endpoint) using HTTPS. I am able to achieve this by following the guide here: https://camel.apache.org/how-to-switch-the-cxf-consumer-between-http-and-https-without-touching-the-spring-configuration.html
The following configuration is key:
<ctx:property-placeholder location="classpath:orderEntry.cfg" />
<!-- other properties -->
<http:conduit name="{http://www.company.com/product/orderEntry/service/1}OrderEntry.http-conduit">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers>
<sec:keyStore type="JKS" password="${trustStore.password}" file="${trustStore.file}"/>
</sec:trustManagers>
<!-- other config -->
</http:tlsClientParameters>
</http:conduit>
The above configuration refers to a config file that has these properties stored:
orderEntry.cfg
--------------
endpointUri=https://localhost:8181/OrderEntry
trustStore.password=password
trustStore.file=etc/myApp.ts
As noted earlier, I am able to send messages via https when I follow the guide.
But I am concerned about the password being stored in plain text here. Is there a way that I can have the password wired from Java code (which can probably read the password from an encrypted source) and provide it to the http conduit when it needs it?
Have you tried location attribute value with file prefix?
E.g. location="file:/my/custom/location/orderEntry.cfg"
See: https://stackoverflow.com/a/17303537
Update:
If it works with your custom bean, you can try create trust managers as a bean and inject it into the conduit configuration like bellow:
blueprint.xml
<bean id="serviceTrustManager"
class="my.app.security.KeyStores" factory-method="loadTrustManagers">
<argument index="0" value="${my.app.service.trustStorePath}"/>
<argument index="1" value="${my.app.service.trustStoreEncryptedPassword}"/>
</bean>
<http:conduit name="{http://www.company.com/product/orderEntry/service/1}OrderEntry.http-conduit">
<http:tlsClientParameters disableCNCheck="true">
<sec:trustManagers ref="serviceTrustManager"/>
</http:tlsClientParameters>
</http:conduit>
Java code:
public class KeyStores {
public static TrustManager[] loadTrustManagers(String trustStorePath, String trustStoreEncryptedPassword) {
String trustStoreDecryptedPassword = PasswordDescriptor.decryptPassword(trustStoreEncryptedPassword); //Password decryption logic here
KeyStore trustStore = KeyStores.loadKeyStore("JKS", trustStorePath, trustStoreDecryptedPassword); //IO logic here
TrustManagerFactory trustFactory;
try {
trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
} catch (NoSuchAlgorithmException | KeyStoreException ex) {
throw new IllegalStateException(ex);
}
return trustFactory.getTrustManagers();
}
}
I'm trying to configure sl4j/logback under Weblogic12.
I deploy ear file, which has war file, which has WEB-INF\classes\logback.xml
Here is the config:
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
My code to log :
private static final Logger logger = LoggerFactory.getLogger(FrontEndServlet.class);
//......
logger.info("info test");
logger.debug("debug test");
logger.error("error test");
What I see in the standart output is :
ьрщ 14, 2012 5:09:29 PM .....FrontEndServlet doPost
INFO: info test
ьрщ 14, 2012 5:09:29 PM .....FrontEndServlet doPost
SEVERE: error test
So, it looks like config file is not picked up.
What am I doing wrong?
The problem is discussed here in detail: https://stagingthinking.wordpress.com/2012/06/02/annoying-slf4j-problem-in-weblogic-server-12c/
The exact package you need to put to the prefer-application-packages mechanism is org.slf4j, like this:
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-application>
<prefer-application-packages>
<package-name>org.slf4j</package-name>
</prefer-application-packages>
</weblogic-application>
Note: Also this question is already answered, I want to add that you should also add prefer-application-resources.
Answer: Add a file called META-INF/weblogic-application.xml to your ear, containing both prefer-application-packages and prefer-application-resources!
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-application
xmlns="http://xmlns.oracle.com/weblogic/weblogic-application"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-application http://xmlns.oracle.com/weblogic/weblogic-application/1.5/weblogic-application.xsd"
version="6">
<!-- http://www.torsten-horn.de/techdocs/jee-oracleweblogic.htm -->
<prefer-application-packages>
<package-name>org.slf4j.*</package-name>
</prefer-application-packages>
<!-- if not using prefer-application-resources you will get a warning like this: -->
<!-- Class path contains multiple SLF4J bindings -->
<!-- SLF4J: Found binding in [jar:file:/C:/wls1211/modules/org.slf4j.jdk14_1.6.1.0.jar!/org/slf4j/impl/StaticLoggerBinder.class] -->
<prefer-application-resources>
<resource-name>org/slf4j/impl/StaticLoggerBinder.class</resource-name>
</prefer-application-resources>
</weblogic-application>
The problem was - sl4j did not pick up logback and used Weblogic's slf4j-jdk logging instead. Can be fixed with Weblogic's config weblogic-application.xml, option prefer-application-packages
Alternatively or if you have problems with more than just slf4j, you could use
<wls:container-descriptor>
<wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>
</wls:container-descriptor>
Instead of
<prefer-application-packages>
<package-name>org.slf4j.*</package-name>
</prefer-application-packages>
Source: Oracle
Environment: Weblogic 12.2.1
Logging Framework : Slf4j and Logback
Requirement : Log to a file of my choosing (per application) as well as Weblogic server logs
Using the <prefer-application-packages/> or <prefer-web-inf-classes> in weblogic.xml did not satisfy the requirement. In my testing, using one or the other tags (you can't use both) will result in the application logback.xml to be picked up and logging will go to the file defined in logback.xml. However, the typical STDOUT defintion using logback's ConsoleAppender will not log to the server logs.
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
Removing the following from weblogic.xml
<wls:prefer-application-packages>
<wls:package-name>org.slf4j.*</wls:package-name>
</wls:prefer-application-packages>
will result in using the bundled SLF4j binding, which in Weblogic 12.2.1, is Java Util logging. In this case, log statements will go to the server logs and not to the file definition in the application level logback.xml. In my research, it appears at one time, some version of Weblogic 12 allowed the internal SLF4j to be bound to Log4j but was removed in one of the minor releases. This was my case; I did not have the option of enabling Log4j as the primary logging Framework in Weblogic through the Admin console. I am fairly sure this wouldn't have helped me, but I did want to note it because several documents I read indicated this would be available.
After much research and fighting configuration with weblogic.xml, configuration of POM (exclusions etc) and trying to use different bindings and bridges, I was unable to achieve the logging configuration that I wanted. It appears that Weblogic's slf4j is bound to Java utility logging, for better or worse. If you choose your own implementation of slf4j and binding (in my case Logback), there is no way that I could find to route those messages to Weblogic server logs through configuration. There can only be one binding in slf4j, and although many frameworks can be routed to that one binding, (I found this diagram useful) Weblogic 12.2.1 only employs Java util logging binding, there is no way to (at the application configuration level) to wire Weblogic to use the Logback binding that you provide to log to its server logs. There might be some way to use log4j and bridges to accomplish this, but for me that's entirely too much bloat and configuration to accomplish a simple logging task.
Giving up on trying to conquer this by configuration, I decided to simply write my own logback appender that translates a logging event into a JUL logging event. I replaced the standard STDOUT definition seen in many Logback examples with my own implementation of Logback's AppenderBase. At this point I can now log using per application logging configuration and also log to the Weblogic Server log.
Relevant POM Dependencies:
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
weblogic.xml (Note here that Hibernate comes with JbossLogging which will bridge to slf4j automatically)
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/2.0/weblogic-web-app.xsd">
<jsp-descriptor>
<keepgenerated>true</keepgenerated>
<debug>true</debug>
</jsp-descriptor>
<context-root>YourContextRoot</context-root>
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>ch.qos.logback.*</wls:package-name>
<wls:package-name>org.jboss.logging.*</wls:package-name>
<wls:package-name>org.slf4j.*</wls:package-name>
</wls:prefer-application-packages>
<wls:prefer-application-resources>
<wls:resource-name>org/slf4j/impl/StaticLoggerBinder.class</wls:resource-name>
</wls:prefer-application-resources>
</wls:container-descriptor>
Logback AppenderBase implementation
import java.util.logging.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
public class WeblogicAppender extends AppenderBase<ILoggingEvent> {
private final Logger logger = Logger.getLogger(WeblogicAppender.class.getName());
ILoggingEvent event = null;
#Override
protected void append(ILoggingEvent event) {
this.event = event;
logger.log(getJULLevel(), event.getFormattedMessage());
}
private java.util.logging.Level getJULLevel() {
if (this.event == null) {
return java.util.logging.Level.SEVERE;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.ALL) {
return java.util.logging.Level.ALL;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.DEBUG) {
return java.util.logging.Level.FINE;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.ERROR) {
return java.util.logging.Level.SEVERE;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.INFO) {
return java.util.logging.Level.INFO;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.TRACE) {
return java.util.logging.Level.FINEST;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.WARN) {
return java.util.logging.Level.WARNING;
} else if (this.event.getLevel() == ch.qos.logback.classic.Level.OFF) {
return java.util.logging.Level.OFF;
} else {
return java.util.logging.Level.INFO;
}
}
}
Logback.xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="com.your.package.WeblogicAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger: LineNumber:%L - %message%n</pattern>
</encoder>
</appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>yourlog.log
</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>yourlog.%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxFileSize>25MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger: LineNumber:%L - %message%n</pattern>
</encoder>
</appender>
<root level="TRACE">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
Hopefully I can save others some of the pain that I went through trying to get this working the way I wanted.