I'm trying to deploy a dropwizard (dw) application using wizard-in-a-box (wiab) on IBM Liberty Profile 8.5.5.5, but I'm encountering som issues with the io.dropwizard.util.JarLocation class. wiab will try to get the location of the Listener class wrapping the dw application but fails to do so since the CodeSource object in the class' ProtectionDomain is null.
klass.getProtectionDomain().getCodeSource().getLocation()
However, I've tried to deploy on Tomcat 8 and the latest Liberty Profile v9 beta, and they both work fine.
Both server.xml files on the Liberty servers look exaktly the same in terms of features.
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
<!-- Enable features -->
<featureManager>
<feature>servlet-3.1</feature>
<feature>jsp-2.3</feature>
<feature>el-3.0</feature>
<feature>websocket-1.1</feature>
<feature>localConnector-1.0</feature>
</featureManager>
<!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
<httpEndpoint id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443" />
<applicationMonitor updateTrigger="mbean" />
<application id="moshpit_war_war_exploded" location="D:\code\moshpit\moshpit-war\target\moshpit" name="moshpit_war_war_exploded" type="war" context-root="/" />
</server>
I've tried deploying both the ordinary war and the exploded war from inside IntelliJ, as well as using the dropin folder with a pre-built war. The v9 beta version will play nice, but not 8.5.5.5.
This is the Listener class wrapping the dw app:
#WebListener
public class MoshpitWebApplication extends WebApplication<MoshpitConfiguration> {
private static final Logger LOGGER = LoggerFactory.getLogger(MoshpitWebApplication.class);
public MoshpitWebApplication() {
super(new MoshpitApplication(), "/configuration/moshpit.yml");
}
}
and this is my dw Application class
public class MoshpitApplication extends Application<MoshpitConfiguration> {
public MoshpitApplication() {
}
public static void main(String[] args) throws Exception {
new MoshpitApplication().run(args);
}
#Override
public String getName() {
return "moshpit";
}
#Override
public void initialize(Bootstrap<MoshpitConfiguration> bootstrap) {
bootstrap.setConfigurationSourceProvider(new FileConfigurationSourceProvider());
// nothing to do yet
}
#Override
public void run(MoshpitConfiguration configuration, Environment environment) throws Exception {
final Template template = configuration.buildTemplate();
environment.healthChecks().register("template", new TemplateHealthCheck(template));
environment.jersey().register(new HelloWorldResource(template));
}
}
Update:
This seems to be a general problem with Liberty 8.5.5.5. Tried deploying a completely different application and I observed the same behaviour. The CodeSource is null for application classes.
The Liberty profile doesn't currently set the CodeSource for application classes. As you note this is addressed in the current beta and will be addressed when 8.5.5.6 is released on June 26th.
Related
Recently I tried Tomcat 10.0.10 and when trying to inject the connection pool as a JNDI resource find out that the #Resource annotation doesn't work.
Then I tried obtain it programmatically by creating a InitialContext and it worked. Initially I thought it was only for the java:comp/env/jdbc so I tried with a simple bean like below and tried to inject it with the #Resource annotation it didn't work again. When I try to obtain it programmatically by creating a InitialContext and it works. Then I check whether the #PostConstruct or #PreDestroy annotation works and found out that they also don't work.
package lk.ijse.test.tomcatdbcp;
public class Something {
}
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="bean/Something" auth="Container"
type="lk.ijse.test.tomcatdbcp.Something"
factory="org.apache.naming.factory.BeanFactory"
/>
</Context>
<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="false" xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<resource-env-ref>
<resource-env-ref-name>bean/Something</resource-env-ref-name>
<resource-env-ref-type>lk.ijse.test.tomcatdbcp.Something</resource-env-ref-type>
</resource-env-ref>
</web-app>
package lk.ijse.test.tomcatdbcp;
import java.io.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import javax.naming.InitialContext;
import javax.naming.NamingException;
#WebServlet(name = "helloServlet", value = "/hello", loadOnStartup = 1)
public class HelloServlet extends HttpServlet {
private String message;
#Resource(name= "java:comp/env/bean/Something")
private Something something;
#PostConstruct
public void doSomething(){
System.out.println("Does it work?");
}
public void init() {
message = "Hello World!";
try {
InitialContext ctx = new InitialContext();
Something lookup = (Something) ctx.lookup("java:comp/env/bean/Something");
System.out.println(lookup);
System.out.println(something); // null
} catch (NamingException e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
public void destroy() {
}
}
To reproduce the same issue, I created a sample repo here: https://github.com/sura-boy-playground/play-with-tomcat10
(Complete code can be found there)
At first, I had used javax.annotation.Resource annotation, so I thought that was the reason because of the javax.* to jakarta.* namespace change. Then I tried it with jakarta.annotation.Resource but the result was same.
I tried the same application with Tomcat 9.0.41 plus javax.* namespace, it works perfectly.
Is there any extra stuff that I need to do on Tomcat 10.0.10 to enable these annotations? I dug the Tomcat 10 documentation but I wasn't able to find out any thing related to my issue.
I found out that there was a similar case in Tomcat 7 previously, but I don't like that kind of workaround now.
Tomcat #Resource annotations API annotation stops working in Tomcat 7
You should declare the scope of your jakarta.annotation dependency as provided:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
If you have two copies of jakarta.annotation.Resource (one in the common classloader and one in your application's classloader), the two classes are different. The InstanceManager will look for fields annotated with the common classloader's copy of #Resource, while the something field is annotated with your webapp's copy of #Resource.
Edit: this problem was fixed in Tomcat 10.0.17 (cf. changelog), 9.0.59 and 10.1.0-M11.
Remark: You will have the same problem in Tomcat 9.0 if you use Java 11 or later. Before Java 11 the javax.annotation.* classes where included in the JRE. Servlet containers are required to look in the bootstrap/JRE classloader before looking in the webapp classloader (overriding javax.* classes is a breach of Java's licence), therefore Tomcat would never find the additional copy of the classes.
I am normally the Tomcat guy but we use Widlfly on one of our client project.
With Tomcat, I can set "per application" properties by creating a separate context for each application, just as Tomcat documentation very nicely says.
This way, my WebApp1.war can run with my.property.value=Cat and WebApp2.war can run with my.property.value=Dog at the same time.
I haven't found any similar documentation / feature with Wildfly. Could you please advice me how to set properties to applications individually, or point me to the documentation?
Thank you. :-)
In Wildfly, you can create modules holding properties:
Under the ${JBOSS_HOME}/modules, add a directory like my/group/app1/conf/main.
Under the ${JBOSS_HOME}/modules/my/group/app1/conf/main, create the file module.xml with content:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="my.group.app1.conf">
<resources>
<resource-root path="." />
<!-- Insert resources here -->
</resources>
</module>
Copy your *.properties file(s) under the ${JBOSS_HOME}/modules/my/group/app1/conf/main
Add as dependency <module name="my.group.app1.conf" export="true" /> in the jboss-deployment-structure.xml of the WebApp1.war
In a Spring XML, assuming you have in the configuration module a file named my-app.properties the properties can be loaded into the context with:
<context:property-placeholder
location="classpath*:*my-app.properties"
local-override="false"
ignore-unresolvable="false"/>
To have a configuration module for the WebApp2.war, just repeat the steps above but the new module must have its own unique name.
I think, I found a workaround for this problem. A asume, that app1.war and app2.war are different wars and not the same with different names.
Then you can use the Application initialization process at runtime to define per application a different spring.config.name. Instead of application.properties then every WAR (and of corse every jar) looks for a application specific called properties file.
/** Main Entry Point for this Application */
#SpringBootApplication(scanBasePackages = "de.mach.selfservices")
public class Application extends SpringBootServletInitializer implements WebApplicationInitializer {
// JAR init
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
if (!System.getProperties().containsKey("spring.config.name")) {
builder = builder.properties("spring.config.name:app1");
}
builder.run(args);
}
// WAR init
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
if (!System.getProperties().containsKey("spring.config.name")) {
builder = builder.properties("spring.config.name:app1");
}
return builder.sources(Application.class);
}
}
The second application has then app2 in spring.config.name. In both cases the default behaviour of SpringBoot is like expected. It looks inside and outside the WAR/JAR for app1.properties or app2.properties. So you can put two files in wildfly/standalone/configuration and can configure both WARs independently.
For me the following approach worked.
First i changed name of application properties.
Second i changed the path to configuration file using Wildfly configuration path.
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
String configPath = System.getProperties().getProperty("jboss.server.config.dir") + "/";
return builder
.properties("spring.config.name:my-app")
.properties("spring.config.location:" + configPath)
.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Previously I was using alfresco 4.1.3 in which I have done too many customization Like. policy,custom action etc.
Now I have migrated my code to alfresco 5.01 and deployed it successfully. almost functionality are working fine but I am not able to call custom policy/behaviour.
Below is sample code.
public class OnCreateObjectPolicy extends AbstractConfigurablePolicy implements NodeServicePolicies.OnCreateNodePolicy{
#Override
public void onCreateNode(ChildAssociationRef childAssocRef) {
System.out.println("************Create node called successfully");
}
#Override
public void bindBehavior() {
System.out.println("************bindBehavior called successfully");
}
}
Any one can help?
You need to register your policy/class in (any of) the context xml files as well. Just having them in your module/jar/class does not register them yet automatically.
I'm sure you did that in your 4.1.3 installation, just copy it over.
Sample:
<bean id="onCreateNodePolicy" class="com.mycompany.alfresco.repo.policies.OnCreateNodePolicy" init-method="init">
<property name="ServiceRegistry" ref="ServiceRegistry" />
...
</bean>
We use JNDIRealm (Tomcat 6) for LDAP authentication. May be due to LDAP flakiness, one thread gets lock on JNDIRealm.authenticate method and causing thread dump. To solve this, added CustomJNDIRealm class that extends JNDIRealm as shown below
package com.gop.it.msoft;
import org.apache.catalina.realm.JNDIRealm;
public class CustomJNDIRealm extends JNDIRealm {
protected String readTimeout;
#Override
protected Hashtable<String,String> getDirectoryContextEnvironment() {
Hashtable<String,String> env = new Hashtable<String,String>();
if(readTimeout != null) env.put("com.sun.jndi.ldap.read.timeout", readTimeout);
return env;
}
}
Now, how do I configure in Server.xml ? By doing below, I get ClassNotFoundException. Please help.
<Realm allRolesMode="authOnly" className="com.gop.it.msoft.CustomJNDIRealm" connectionURL="ldaps://ldap.gop.com:636" referrals="follow" userPattern="uid={0},ou=People,o=gop.com" readTimeout="5000" userSubtree="false"/>
Thanks a bunch
The Realm implementation has to be available before the webapp is loaded. So, it has to be in a JAR file in Tomcat's lib directory. Putting it into the webapp's own WEB-INF/lib can't work.
The problem is, whenever you change the log4j.properties/log4j.xml, you need to restart the tomcat [ or say any other server ]. Is there any workaround of reloading the log4j configuration?
From http://logging.apache.org/log4j/1.2/faq.html#3.6
Is there a way to get log4j to
automatically reload a configuration
file if it changes?
Yes. Both the DOMConfigurator and the
PropertyConfigurator support automatic
reloading through the
configureAndWatch method. See the API documentation for more
details.
Because the configureAndWatch launches
a separate wathdog thread, and because
there is no way to stop this thread in
log4j 1.2, the configureAndWatch
method is unsafe for use in J2EE
envrironments where applications are
recycled.
Said that, I've successfully used PropertyConfigurator#configureAndWatch method in a Java EE environment (Sun One Web Server, not Tomcat).
As of log4j 2.x you can reload the config periodically, in this example every 30 seconds:
<configuration monitorInterval="30">
Please take a look here for more information on log4j 2.x configuration:
You can write a little initializer code with the following short steps:
listen for the "BEFORE_START_EVENT",
when the event happens (once per Tomcat restart), start log4j using the configureAndWatch method
also don't forget to install a shutdown hook to cleanup the watcher thread
See this blog post for details - reload log4j configuration in tomcat
They also moved it to github.
Update:If you are using lg4j2.xml, the configuration is the only thing you will need for log4j to be managed at runtime
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO" monitorInterval="30">
<Loggers>
-------
</Loggers>
</Configuration>
Monitor interval 30 loads the log4j changes every 30 seconds.
Below solution is if you are on older version of log4j.
Yes you can change the log4j level at run time without the need to restart the server provided you are using spring.
public class OptionalLog4jConfigurer extends Log4jConfigurer implements
InitializingBean {
public static final Long DEFAULT_REFRESH = 30000L;
private static final Log LOG = LogFactory
.getLog(OptionalLog4jConfigurer.class);
private String configLocation;
private Long refreshInterval;
public OptionalLog4jConfigurer(final String configLocation,
final Long refreshInterval) {
this.configLocation = configLocation;
if (refreshInterval == null) {
this.refreshInterval = DEFAULT_REFRESH;
}
else {
this.refreshInterval = refreshInterval;
}
}
public void afterPropertiesSet() throws Exception {
if (!StringUtils.isEmpty(this.configLocation)) {
LOG.info("Log4J configuration is being customized.");
this.initLoggingInternal();
}
else {
LOG
.info("Using default Log4J configuration. No customization requested");
}
}
public String getConfigLocation() {
return this.configLocation;
}
public Long getRefreshInterval() {
return this.refreshInterval;
}
}
Then do these changes to applicationContext.
<bean id="optionalLog4jInitialization" class="com.skg.jetm.OptionalLog4jConfigurer">
<constructor-arg index="0" type="java.lang.String" value="${log4j.configuration}" />
<constructor-arg index="1" type="java.lang.Long" value="100" />
</bean>
Full code and explanation can be found here
Changing log4j Level dynamically
You can create a strut action or a servlet which reload the properties file. So after editing the log4j.properties file, you will need to call the servlet to reload it.
For example:
public class Log4JServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
protected static Logger log = Logger.getLogger(Log4JTestServlet.class);
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Reload Log4J prop file");
String path = "C:\\GlassFishESBv22\\glassfish\\domains\\domain1\\config\\log4j.properties";
PropertyConfigurator.configure(path);
/*
log.debug("debug message");
log.info("info message");
log.warn("warn message");
log.error("error message");
log.fatal("fatal message");
*/
}
}
Another way is to configure Spring Framework's Log4jConfigListener in web.xml
The Guido Garcia answer is quite on target.
Log4j 1 offers a way of reloading log4j configuration in a non JEE thread safe maner.
So if you are in a JEE continer, you can solve your problem trivially by:
(A) Create your #Singleton ejb timer to periodically scan your log4j.properties file
(b) Look at the implementaiton of the log4j log watch given by log4j.
What it does when it is time to relaoad a file is quite simply and conveniently, the following:
new PropertyConfigurator().doConfigure(filename,LogManager.getLoggerRepository());
Just do the same, if the time stamp on you configuration file changes.
That is it.
Another Method is to configure a file watcher using Java File WatcherService as explained below link and reload Log4J configuration on any file Modifications.
https://dzone.com/articles/how-watch-file-system-changes
Reloading can be done using DOMConfigurator's APIs
https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/DOMConfigurator.html