How to read external properties files in WebSphere? - java

I developed a sample web application which will read the data from an external properties file. The properties file is in the source folder in my system and is not included inside the WAR file.
The property file is accessed like this:
Properties prop = new Properties();
//File f1 = new File("Property.properties");
prop.load(getClass().getClassLoader().getResourceAsStream("Property.properties"));
How do I access this property file externally inside the WAR file?
What changes have to be made in the code to read it in the WAR file?

I think the most versatile approach is to define a simple environment entry as described in the section EE.5.4 Simple Environment Entries of Java™ Platform, Enterprise Edition (Java EE) Specification, v5.
From the section (page 68):
A simple environment entry is a configuration parameter used to
customize an application component’s business logic. The environment
entry values may be one of the following Java types: String,
Character, Byte, Short, Integer, Long, Boolean, Double, and Float.
You may also use URL connection factory as described in the section EE.5.6.1.4 Standard Resource Manager Connection Factory Types of the specification.
The Application Component Provider must use the java.net.URL resource
manager connection factory type for obtaining URL connections.
Both require a definition of a resource reference in the deployment descriptor WEB-INF/web.xml of your web application so you can inject the value using #Resource or use JNDI API with java:comp/env as the entry point.
The benefit is that you can change the configuration of your web application without having to recompile the code as well as let you change it using an application server's administrative tools your admins are accustomed with.
In web.xml you define the resource reference.
<resource-ref>
<res-ref-name>propertiesURL</res-ref-name>
<res-type>java.net.URL</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<resource-ref>
<res-ref-name>propertiesPath</res-ref-name>
<res-type>java.lang.String</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
Then in your code you use the following to access the values:
#Resource
String propertiesPath;
#Resource
URL propertiesURL;
With this you met the requirements of Java EE and you can use propertiesPath or propertiesURL as if they were passed as input parameters to your methods.
Now, it's time to meet expectations of WebSphere Application Server.
What you defined are logical names that need to be mapped to their administered names (an application server knows about and can provide to the application).
In WebSphere Application Server you use WebSphere Binding descriptor WEB-INF/ibm-web-bnd.xml with the following configuration:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_1.xsd"
version="1.1">
<virtual-host name="default_host" />
<resource-ref name="propertyURL" binding-name="propertyURL" />
<resource-ref name="propertyURL" binding-name="propertyURL" />
</web-bnd>
When the application gets deployed WAS allows you to map these mappings to its administered resources. Use the ISC console to define values of the environment entries and map them to the application.
It has became easier with WebSphere Liberty Profile. I described the mechanism as offered by WLP in my article Using #Resource to access JNDI in WebSphere AS 8.5 Liberty Profile.

You have three options:
configure the Websphere to include the directory which contains the property file in the classpath. Don't know how to do it, but I'm sure it is possible, since our application does the same thing
include the property file in the war archive. You probably don't want to do that.
instead using the classloader to load the property file use the file api with an absolute path. I'm not completely sure WAS does allow that, but it is a bad idea anyway, because it makes your application very dependent on things that it really shouldn't care about, such as the installation path of your application.

WebSphere has two folders on the classpath, properties can be loaded from there:
Enterprise Applications > myear > Manage Modules > myjar.jar > Class loader viewer
4 - Extension - com.ibm.ws.bootstrap.ExtClassLoader
file:/projekte/IBM/WebSphere/AppServer-8.5/classes/
file:/projekte/IBM/WebSphere/AppServer-8.5/lib/

Related

Make <resource-ref/> optional in the sense that deployment does not fail when a JNDI name is not pointing to a valid resource

We have an EJB application with a jboss-ejb3.xml which defines resource-refs for JNDI mapped resources. In our use-case not all resources are available in all environments. Since jboss-ejb3.xml cannot be externalized, I was hoping if there was a way the definitions can be somehow marked optional so the deployment does not fail when a mapped resource is not configured?
For example, we have our jboss-ejb3.xml defined as:
<resource-ref>
<res-ref-name>cache/ErrorDataCache</res-ref-name>
<res-type>java.util.Map</res-type>
<jndi-name>java:jboss/infinispan/cache/ejb/ErrorDataCache</jndi-name>
<!-- what to add to make this optional ?? -->
</resource-ref>
In our DEV JBOSS EAP 7.2 server, we are configuring a back-end cache so when server starts up and deploys the application, it registers the JNDI context (java:comp/env/cache/ErrorDataCache) to the mapped resource (java:jboss/infinispan/cache/ejb/ErrorDataCache).
However, in our production servers of same EAP version, we are forbidden to cache these values. Also we are forbidden to change the EAR archive to maintain a separate jboss-ejb3.xml.
I also tried using system properties substitution/placeholder, but there has to be a default fall-back otherwise it still fails with error "unresolved property value of app.module.env.${mappedjndi.errordatacache}"
<resource-ref>
<res-ref-name>cache/ErrorDataCache</res-ref-name>
<res-type>java.util.Map</res-type>
<jndi-name>${mappedjndi.errordatacache:"what default value??"}</jndi-name>
</resource-ref>
I have read that there is an <ignore-dependency/> tag which I tried, but it fails with error: invalid tag , not defined in the XSD.

how to add a parameter to spring project before <projectname>/login and after <localhost>:<portnumber> without hardcode?

I'm working on a Spring MVC project. When I run the application the URL is:
http://localhost:8080/insureYou/login
but I want:
http://localhost:8080/contextroot/insureYou/login
Is there any way of doing it without hardcoding?
In a spring-boot project you can set the context-root by specifying the following property in the application.properties file:
server.servlet.context-path=/yourcontextroot
Without spring-boot, it depends on the webserver and Tomcat offers a number of options.
I would personally opt for a META-INF/context.xml file in your war file containing the necessary information but you can also include the information in the server.xml file or in a ROOT.xml file.
See the following links for further guidance:
How to set the context path of a web application in Tomcat 7.0
https://tomcat.apache.org/tomcat-8.0-doc/config/context.html
https://www.baeldung.com/tomcat-root-application
This type of deployment however sometimes is handled separately, through an Apache server reverse-proxy or through URL rewriting.
I recommend you ascertain whether this type of need is already taken care of by your company's deployment procedures, as you may not need to deal with it at all.

Websphere change JNDI name in EAR

I got a legacy EJB 2 application which I deploy to Websphere 8.5. The application has dependencies, which define JNDI bindings to a DataSource in /META-INF/ejb-jar.xml and /META-INF/ibm-ejb-jar-bnd.xml.
I'm not allowed to change the code in those dependencies and neither can I change the Websphere's config. But I could make changes to the config files in the jar files.
I want to override the effective JNDI bindings in my application. Is it possible to define a file that will be added to the Ear to override those bindings?
snippet of the ejb-jar.xml:
<resource-ref id="ResourceRef_1248968390265">
<res-ref-name>jdbc/CentralDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
ibm-ejb-jar-bnd.xml:
<session name="FooJob">
<resource-ref name="jdbc/CentralDS" binding-name="jdbc/VeryCentralDs" />
</session>
Is it possible to override this JNDI name (VeryCentralDs) somewhere?
Yes, it is possible to override resource reference bindings at deployment time. This knowledge center article steps through deploying an application. Watch for the step "Map resource references to resources" which is documented here. This is where you can fill in the target JNDI name that you want the resource reference bound to.

Set Spring profile in Tomcat web app with no web.xml file

I have a webapp that is a RestEASY JAX-RS application and that uses the latest servlet specifications, such as Java EE annotations so that I don't need to create a web.xml file.
The webapp is bundled as foobar.war and dumped into the webapps directory in Tomcat. In fact the same foobar.war is deployed twice in the same Tomcat instance, once as foobar.war and the other as foobar#demo.war (which maps it to foobar/demo as you know).
I configure each mounted webapp by placing conf/Catalina/localhost/foobar.xml and conf/Catalina/localhost/foobar#demo.xml files, that look like this:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Environment name="foo" type="java.lang.String" value="bar"/>
</Context>
In my JAX-RS application I pull in the value of foo from JNDI using java:comp/env/foo.
So now I added a Java-based Spring configuration named FooBarConfiguration. I load it in my JAX-RS application using new AnnotationConfigApplicationContext(FooBarConfiguration.class). That all works fine.
So now I've added two profiles to FooBarConfiguration, one named foo and one named bar. But now... how do I tell the webapp which Spring profile to use? (Remember that I have no web.xml file.) Obviously I have to set spring.profiles.active somewhere. But where?
Because the documentation spoke of "environment" and "JNDI", I crossed my fingers and added an environment variable to conf/Catalina/localhost/foobar.xml:
<Environment name="spring.profiles.active" type="java.lang.String" value="foo"/>
No luck.
I can't set a system property, because that will apply to all the webapps, and the idea here is that each foobar.war instance (foobar.war and foobar#demo.war) could each have a different profile specified.
I suppose I could manually pull it out of the Tomcat environment myself, using java:comp/env/spring.profiles.active, but then where do I set the value? (I thought maybe AnnotationConfigApplicationContext would have a constructor where I could set the profile, or at least have a profile setting, but that also seems to be missing.)
(Plus if I'm manually pulling out the setting from JNDI and setting it myself, I might as well switch to the more lightweight Guice and manually load the modules I want. I'm only using the humongous, clunky Spring because it promised to allow easy selection of profiles.)
How can I indicate, external to my WAR file, on a per-webapp basis, which Spring profile I'm using?
You can set active profiles in many ways. Since you were searching for it via AnnotationConfigApplicationContext constructor, the one described here in spring docs might suit you.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development");
ctx.refresh();
The solution is to use AnnotationConfigWebApplicationContext instead of StandardServletEnvironment.
The trick is to get Spring to use a StandardServletEnvironment, which looks in several places including JNDI java:comp/env/... for spring.profiles.active. See http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-property-source-abstraction .
My problem is that AnnotationConfigApplicationContext uses a StandardEnvironment, which only looks in a few places for the profile designation. Switching to a AnnotationConfigWebApplicationContext made Spring use a StandardServletEnvironment:
final AnnotationConfigWebApplicationContext webContext =
new AnnotationConfigWebApplicationContext();
webContext.register(FooBarConfiguration.class);
webContext.refresh();
Now my webapp environment configuration in conf/Catalina/localhost/foobar.xml works:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Environment name="spring.profiles.active" type="java.lang.String" value="foo"/>
</Context>

Why is Realm setting required in Server.xml and not web.xml

I am working on a Java application for a while. I primarily work on .NET Platform. Although I feel lot of concepts are common between these two platforms but there are few areas where I am finding some issues related to the configuration.
I am working on Authentication and Authorization and thought I would get something similar to Membership APIs of .NET in JAVA. Closest which I got was using j_security_check. I also got to know about JAAS but think it is little too deep for me to dive into.
I have created the user and role tables in the database and now I have to specify the JDBC Realm settings somewhere. I am using Tomcat 7.0. In most places, it's mentioned that I need to specify the realm setting in the server.xml.But wouldn't that apply to all web application deployed on that server since it would become a server level configuration ?.
On a site I even saw a developer mentioning about context.xml but again can't see a standard document that mention about using this XML file for setting JDBC realm
In.NET, We always put Membership settings at the web.config level and not Machine.config.
Totally Confused on this. Looking for some light on this.
Why is Realm setting required in Server.xml and not web.xml
This is not true, you can define it in your webapp as well, but then only in a servletcontainer-specific configuration file, such as /META-INF/context.xml in case of Tomcat. It cannot be definied in /WEB-INF/web.xml because it's specific to the standard Servlet API, not the servletcontainer implementation.
But wouldn't that apply to all web application deployed on that server since it would become a server level configuration ?.
That's correct. This is not recommended if you have no control over the server or if you don't want to publish the realm through other webapps.
On a site I even saw a developer mentioning about context.xml but again can't see a standard document that mention about using this XML file for setting JDBC realm
You can specify it in webapp's /META-INF/context.xml. See also Tomcat's own documentation on the <Context> element:
Defining a context
It is NOT recommended to place <Context> elements directly in the server.xml file. This is because it makes modifying the Context configuration more invasive since the main conf/server.xml file cannot be reloaded without restarting Tomcat.
Individual Context elements may be explicitly defined:
In an individual file at /META-INF/context.xml inside the application files. Optionally (based on the Host's copyXML attribute) this may be copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to application's base file name plus a ".xml" extension.
In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The context path and version will be derived from the base name of the file (the file name less the .xml extension). This file will always take precedence over any context.xml file packaged in the web application's META-INF directory.
Inside a Host element in the main conf/server.xml.
(emphasis is not mine, it is already as such in Tomcat's documentation)

Categories

Resources