How to disable Tomcat JARScanner - java

How: To disable Tomcat JARScanner?
Why: To stop Tomcat scan every .jar in my LIB folder.
According to documentation it says that it is possible to disable it within context.xml. But it seems to not be working. (May be I am missing something)
I made an exhaustive search in forums and could not find the solution.
This is in context.xml (not working yet):
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"></JarScanner>
Thanks in advance.

You should add the JarScanner element as a child of the root Context element in the context.xml file.
I have this kind of META-INF/context.xml file in the war file for disabling the JarScanner:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<JarScanner scanClassPath="false" scanAllFiles="false" scanAllDirectories="false"/>
</Context>

you can disable the JarScanner globally for user-definted patterns by opeining the file at
%TOMCAT_HOME%/conf/catalina.properties
and add a filename pattern to tomcat.util.scan.StandardJarScanFilter.jarsToSkip list.
For example, if you want to disable jar scanning completely you could add:
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\
*.jar,\
NOTE: this may of course lead to issues if you're employing JSTL, as templates won't be found by the scanner

in your java app add this :
#Bean
public TomcatServletWebServerFactory tomcatServletFactory() {
return new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(final Context context) {
((StandardJarScanner) context.getJarScanner()).setScanManifest(false);
}
};
}

This is what I did for Spring Boot.
Basically, append a new ignored jar file to the existing list of jars to ignore. This way, you don't totally disable the scanner, affecting who knows what else.
#Configuration
public class Config {
#Bean
public ServletWebServerFactory servletContainer() {
return new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(Context context) {
// db2 puts a ref to pdq.jar in the manifest, and tomcat then tries to find it, but it doesn't exist.
// The jar isn't needed, so we just disable looking for it. You could also remove it from the manifest,
// but that prob needs to be done after the build process.
JarScanFilter jarScanFilter = context.getJarScanner().getJarScanFilter();
if (jarScanFilter instanceof StandardJarScanFilter) {
StandardJarScanFilter filter = (StandardJarScanFilter) jarScanFilter;
String oldTldSkip = filter.getTldSkip();
String newTldSkip = oldTldSkip == null || oldTldSkip.trim().isEmpty() ? "pdq.jar" : oldTldSkip + ",pdq.jar";
filter.setTldSkip(newTldSkip);
} else {
logger.warn("Unable to disable the tomcat jar scanner for pdq.jar. You may see a FileNotFound exception complaining of not finding a db2 pdq.jar file. You can probably ignore the error. Ref: https://stackoverflow.com/questions/11656596/how-to-disable-tomcat-jarscanner");
}
}
};
}
}

Related

Splitting resources.groovy (Grails 2.5) to make it modular

resources.groovy of my Grails project is growing, so I am thinking of splitting it in some logical files that will be easier to mantain. After reading some questions, blogs, i got to know about importBeans or loadBeans. This works well only when application is run using grails run-app. However we I create a war and deploy it on JBoss, the custom bean files are not accessible.
Also tried below with no luck - mentioned here -
Load spring beans from custom groovy files in grails app
grails.war.resources = { stagingDir, args ->
copy(todir: "${stagingDir}/WEB-INF/classes/spring") {
fileset(dir:"grails-app/conf/spring") {
include(name: "datasourceDefinitions.groovy")
exclude(name: "resources.groovy")
}
}
}
I have added datasourceDefinitions.groovy in grails-app/conf/spring.
Please help.
The problem is due to the Spring bean configuration files are moved into the folder "WEB-INF/classes/spring/"(make sure the file is packaged in the.war) inside the WAR file. As what I did was locate the resource path in resources.groovy.
def loadFromFile = { name ->
importBeans("file:grails-app/conf/spring/"+name)
}
def loadFromWar = { name ->
def resource = application.parentContext.getResource("WEB-INF/classes/spring/"+name)
loadBeans(resource)
}
def loadResource = application.isWarDeployed() ? loadFromWar : loadFromFile
loadResource "datasourceDefinitions.groovy"
loadResource "anotherBean.groovy"

Setting per application properties on Wildfly

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);
}
}

How to configure Custom JNDIRealm (added read timeout for LDAP) in Tomcat Server.xml

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.

Changing the log path on fly

I am using log4j for logging activities in my application.I want to take the log path from data base.
now I need to configure my log4j properties dynamically.
can we do it on the fly we change the log4h logging path..
Please suggest.
Thanks
You should create a class what loads at the startup and configurate the log4j.
Here is a code what I used in a JavaEE project, what loads the configuration file from an outer directory:
public class InitListener implements ServletContextListener {
public InitListener() {
}
public void contextInitialized(ServletContextEvent sce) {
try {
File file = null;
file = new File(System.getProperty("catalina.base") + "/conf/query-log4j.xml");
DOMConfigurator.configure(file.toURL());
System.out.println("Log4J successfully configured!");
} catch(Exception e) {
System.out.println("There was an error when initialize the Log4J config!");
e.printStackTrace();
throw new RuntimeException(e);
}
}
public void contextDestroyed(ServletContextEvent sce) {
}
}
If you were using MentaLog, all you have to do was that:
yourLogger.setFilename("newfilenamehere.log");
Your log would be automatically re-opened with the new name. In my personal opinion, programmatic configuration is the way to go over XML and/or annotations. It provides unmatched flexibility and easy of use.
Create seperate properties file to hold Specific Enviroment related settings example:
**uatLog4j.properties**
#######################
UAT Settings
#######################
{Add your Settings here}
And another for sy production enviroment.
**productionLog4j.properties**
########################
PRODUCTION settings
########################
{Add your Settings here}
And then using say the IP Address or the Server Name to determine the deployed platform, pass the path from the database to the required enviroment properties file as required.
Alternatively you can use LogManager to retreive Logger instances or to operate on the current LoggerRepository. See Javadoc and a RepositorySelecter example.
NOTE:
You can achieve the same using XML.

Is it possible to reload log4j.xml / log4j.properties file dynamically in Tomcat?

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

Categories