Setting per application properties on Wildfly - java

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

Related

Setting a JBoss / Wildfly webservice endpoint correctly (jboss-web.xml)

I made a little SOAP web service using Spring Boot, with the following files (only relevant files are shown):
WebServiceConfig.Java
#EnableWs
#Configuration
public class WebServiceConfig {
#Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(context);
messageDispatcherServlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<MessageDispatcherServlet>(messageDispatcherServlet, "/ws/*");
}
#Bean(name = "consultas")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema consultasSchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setPortTypeName("ConsultasPort");
definition.setTargetNamespace("http:/site.com/consultas");
definition.setLocationUri("/ws");
definition.setSchema(consultasSchema);
return definition;
}
#Bean
public XsdSchema consultasSchema() {
return new SimpleXsdSchema(new ClassPathResource("consultas.xsd"));
}
}
application.properties
server.port=9090
Main.Java
#SpringBootApplication
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
System.setProperty("org.jboss.logging.provider", "slf4j2");
SpringApplication.run(Main.class, args);
}
}
Problem description:
When I run Main.Java from Eclipse, a Tomcat instance is deployed. Visiting the address http://localhost:9090/ws/consultas.wsdl. shows the WSDL description file, and SOAPUI is able to consume the web services without a problem.
The problem starts when I pack the .war and deploy it on wildfly-23.0.2.Final. The context root is always set to /soap-web-service-0.0.1-SNAPSHOT.
Edit 2021 05 17
I was able to change the WildFly endpoint by creating a jboss-web.xml file in the folder src\main\webapp\WEB-INF, with the following contents:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.jboss.com/xml/ns/javaee
http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
<context-root>/ws/*</context-root>
</jboss-web>
Steps I tried
I tried setting
to:
/
/ws/*
But I'm still unable to reach the endpoint
Any input will be greatly appreciated.
UPDATE Months later I just found the answer by accident, answered by user #pascal-thivent
...you access the WSDL at:
http://localhost:8080//services/hello?wsdl
A B C D
A is the host and port of the servlet container.
B is the name of the war file.
C comes from the url-pattern element in the web.xml file.
D comes from the ending stem of the url-pattern attribute in the sun-jaxws.xml file

How to load external properties file through OSGi blueprint property-placeholder and Java DSL

I have a bundle installed in Apache servicemix that is using apache blueprint for configuration. I am using an external properties file abc.cfg located in /config folder and is being loaded as follows:
via blueprint
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel-cxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core"
xsi:schemaLocation="
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/blueprint/cxf/camel-cxf.xsd"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0">
<cm:property-placeholder id="myProperties" persistent-id="abc" />
via java DSL
public class MyActivator implements BundleActivator {
#Override
public void start(final BundleContext context) throws Exception {
final ServiceReference serviceReference = context.getServiceReference(ConfigurationAdmin.class.getName());
if (serviceReference != null) {
final ConfigurationAdmin admin = (ConfigurationAdmin) context.getService(serviceReference);
final Configuration configuration = admin.getConfiguration("abc");
final Dictionary<String, Object> configurations = configuration.getProperties();
if (configurations == null) {
throw new CustomException("Exception in loading properties file");
}
populateProperties(configurations);
}
}
}
Everything works fine but now i need to move the property file in custom location to segregate property files from different bundles. So i moved abc.cfg in /config/myFolder/ but i am unable to specify the new location to my bundle in either ways. I tried using ext:property-placeholder but it didn't work, probably because i am using it wrong(couldn't find anything comprehensive to understand it).
So please guide me on how can i specify location for my properties file in cm:property-placeholder and through configuration admin service in java DSL. Also, i am not sure if it is ok to load the same properties file in two different ways in my bundle.
Neither the blueprint cm:property-placeholde nor the configuration-admin service use the file you added to the etc folder. The cm is just another way of using the configuration admin service.
The felix FileInstaller does read cfg files from the etc folder of your ServiceMix instance and does propagate those properties to the Configuration Admin service.
So in your case you'll need to add another configuration to the FileInstaller to read from another path.
This can be done by adding a new configuration file:
org.apache.felix.fileinstall-mySpecialDir.cfg
where you add the new folder to be watched:
felix.fileinstall.dir = myNewSpecialDirectory-to-be-watched
plus some more if needed.
Documentation for it can be found here

CodeSource on Liberty Profile 8.5.5.5

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.

How to disable Tomcat JARScanner

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

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