Spring Boot Datasource JNDI lookup on Websphere 9 - java

I have a Spring Boot application that I usually deploy on a Tomcat server. Now I want to be able to also deploy it on Websphere 9, though it will still be deployed on the usual Tomcat server most of the time. I packaged the app as a war and deployed it on Websphere through the admin interface, then ran the application. And as pointed out in many other posts, it did not work because JNDI lookup does not work the same way. I tried solutions offered here and there, but nothing worked.
My datasource is defined in Websphere with name jdbc/foobar. My lookup is done in my Spring Boot app with:
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource ds = dataSourceLookup.getDataSource("java:comp/env/jdbc/foobar");
This works on Tomcat but does not on Websphere. Many answers on other SO posts about this say that for Websphere, one must lookup "jdbc/foobar" without the prefix (for instance here in the answer's comments), which is true (I could get it to work), but I want to have code that remains compatible with the usual deployment on tomcat.
As a side note, the getDataSource method automatically adds the prefix if it is absent, which means I needed to do this instead:
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
dataSourceLookup.getJndiTemplate().getContext().lookup("jdbc/foobar");
This still is useful because, since it worked well, it proved that my problem is not a wrong datasource definition at server side.
Since I want my code to remain the same tomcat-compatible code, I kept the "java:comp/env/jdbc/foobar" lookup and I looked into the answers advising to add some configuration, most notably this one. I located the ibm-web-bnd.xml file, which is created by Websphere at deployement time and put in the WEB-INF folder. I added the advised resource-ref tag there:
<?xml version="1.0" encoding="UTF-8"?>
<web-bnd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://websphere.ibm.com/xml/ns/javaee"
xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-bnd_1_0.xsd" version="1.0">
<virtual-host name="default_host"/>
<resource-ref name="jdbc/foobar" binding-name="jdbc/foobar" />
</web-bnd>
Then, since I don't have a web.xml in my war, I tried the #Resource trick:
#Component
#Resource(name = "jdbc/foobar",type = javax.sql.DataSource.class)
public class MyServlet extends HttpServlet {
I could verify the servlet is loaded correctly but the Resource annotation does no seem to do the trick. Then I noticed a web.xml is also created by Websphere beside the ibm-web-bnd.xml file, so I supposed I might give it a try and I added the resource-ref tag inside (the rest was already here, added by Websphere):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<env-entry>
<env-entry-name>logback/context-name</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>main</env-entry-value>
</env-entry>
<listener>
<listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
</listener>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<resource-ref>
<description />
<res-ref-name>jdbc/foobar</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
</web-app>
This still did not work. I also noticed that Websphere created another file named web_merged.xml, which seems to merge the automatically created web.xml with the real one (which in my case does not exist). I tried to add the same code shown above to this file too, but it did not work better.
Now, I am out of clue. Does someone have any other idea, or maybe noticed an obvious mistake I made?

What you tried in the bindings file looks like it should have worked, assuming that you are performing the lookup from within the same web module in which you specified the binding (because it is java:comp scoped).
Even so, you ought to be able to do this in a completely standard way without a bindings file at all (where it can be difficult to get all of the syntax correct), by just using the #Resource annotation alone,
#Resource(name = "java:comp/env/jdbc/foobar", lookup = "jdbc/foobar", type = javax.sql.DataSource.class)
I'd recommend getting rid of the extra bindings/deployment descriptor that you were experimenting with and try with just the annotation, at least to start with. If it turns out that you aren't in the same module, you could use java:app (if in the same app) or otherwise java:global instead of java:comp, which you would need to update in both places.

Related

Specify application name for Apache TomEE

I was needing to use JPA in standalone application, so I've found the example http://tomee.apache.org/latest/examples/jpa-hibernate.html as starter.
They create EJB Context via
final Context context = EJBContainer.createEJBContainer(p).getContext();
Then there's a log line:
INFO - Enterprise application "/Users/dblevins/examples/jpa-hibernate" loaded
You need to know that application name to wizard out the search string for lookup:
context.lookup("java:global/jpa-hibernate/Movies");
What makes me worry that I've found out no information on where those 'jpa-hibernate' part comes from. It either comes from artifact id, or, even worse, from the current directory name, which makes the code using it terribly dependend on context, that the developer doesn't control.
I've totally find to google out how to specify that application name so that I could use lookup that will work no matter who invokes my code and where it is copied.
How can I configure this application name?
The Embedded EJB container used in this unit test example allows to run EJBs outside a Java EE container. A good introduction/tutorial can be found here: https://docs.oracle.com/javaee/7/tutorial/ejb-embedded002.htm
It supports the same configuration files as regular EJB-jars, namely it supports the ejb-jar.xml configuration file (the module deployment descriptor). It is possible to configure the module name there, e.g.
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<module-name>myapp</module-name>
</ejb-jar>
This file needs to go into the jar's META-INF directory.

Marking application without web.xml distributable for Tomcat session replication

I have Spring based application and using programmatic approach (AbstractAnnotationConfigDispatcherServletInitializer) for app configuration.
To make tomcat session replication work I need to 'mark' app distributable using <distributable/> tag in web.xml, however as I mentioned I am using programmatic style, e.g.
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
String activeProfile = activeProfile();
if (isNotEmpty(activeProfile)) {
servletContext.setInitParameter("spring.profiles.active", activeProfile);
}
super.onStartup(servletContext);
}
}
I can't find any docs about how to do it using Spring configs, so my question here is that, Is it possible to have distributable app without having web.xml? I can't move all configs to the web.xml, so any help is appreciated.
There are several option you cannot set from Java based configuration, one of them is <distributable /> another is the error-pages.
For that you still need a web.xml, just create an as empty as possible web.xml and only include <distributable />. Everything else can remain in Java based configuration.
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<distributable />
</web-app>
This appears to already be answered here... Mixing web.xml and AbstractAnnotationConfigDispatcherServletInitializer in Spring
Unless I am misunderstanding the question/answer.
It is not possible to configure the Cluster programmatically using Spring. One solution is to have a mix of XML and Java based configuration. So that the Web.xml entries can be maintained.
An example is here to do this.

EJB3 annotations get ignored when ejb-jar.xml is present

I have an application that currently consists of EJB 2.1 Session Beans. I want to transport them to EJB 3.1 annotations where possible.
Unfortunately that is not possible for all so I need to maintain the ejb-jar.xml file for the ones where I can't use the annotations.
I have added the beans.xml file but as long as I have the ejb-jar.xml file present, the annotations are ignored. As soon as I remove it, the annotations work.
How can I configure my application to use the annotations where present and use the ejb-jar.xml file only for stuff thats configured inside it. As far as I understood the documentation, this should be the normal case anyway.
When you shift your application from EJB-2.1 to EJB-3.1 you have to check that you set the version of the ejb-jar.xml to 3.1 as well.
Use this header from the the xsd:
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
Then your annotations are considered then as well.
The beans.xml is not needed for this at all. It is required for enabling CDI (which you don't need if you only refer to your beans from other beans), have a look at this post about what it is and when you need it.
You might need other settings to your ejb-jar.xml as well but that is a topic for another question.

WebService is not "visible" in WebLogic 10.3

I am currently trying to let my application provide a webservice.
The application uses spring and is running under a Weblogic 10.3 instance.
I built the webservice following the "contract first" approach.
So what I basicaly have is a generated WS-Interface, my implementation of that interface, a web.xml defining the servlet-bindings and a sun-jaxws.xml defining the endpoint.
(more or less similar to this: http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat/).
Now, after deploying my application to weblogic, actualy everything is workign fine.
I can type the URL of the WebService into my browser, I see the WSDL, I can call it's methods.
If the weren't a small cosmetic fact:
In the deployments overview of WL when I click on the deployment, it shows me a list of WebServices...which is empty. So my webservice is NOT listed there.
So, can anyone tell me, what I have to do to get the webservice to show up there?
Though it's not really essential to have a webservice descriptor for JAX-WS, Weblogic at times fails to identify the WebServices(was not able to find a reason for this)
Below is what I did to get it working. Add the WebService implementation class as a Servlet in web.xml
<?xml version='1.0' encoding='UTF-8'?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" id="WebApp_ID">
<display-name>MyWebService</display-name>
<servlet>
<servlet-name>serviceServlet</servlet-name>
<servlet-class>com.aneesh.WebServiceImpl</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>serviceServlet</servlet-name>
<url-pattern>/Service</url-pattern>
</servlet-mapping>
</web-app>
and add the webservice descriptor (webservices.xml)
<?xml version='1.0' encoding='UTF-8'?>
<webservices xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<webservice-description>
<webservice-description-name>MyWebService</webservice-description-name>
<port-component>
<port-component-name>MyWebServiceSoapPort</port-component-name>
<wsdl-port xmlns:an="http://www.aneesh.com/service">an:MyWebServiceSoapPort</wsdl-port>
<service-endpoint-interface>com.aneesh.WebService</service-endpoint-interface>
<service-impl-bean>
<servlet-link>serviceServlet</servlet-link>
</service-impl-bean>
</port-component>
</webservice-description>
</webservices>
Depending on the developer that created the Web Service, deployment descriptors such as webservices.xml and weblogic-webservices.xml were added to the application. Descriptors are used for configuration, overriding default settings, and adding metadata. For Web Services this can be the endpoint, port configuration, linkage of the Web Service to EJB components, and so on. When deployed, the WSDL location of Web Services is listed in the WebLogic Console and the WSDL can be retrieved at runtime.
From the Trenches 2 | Patching OSB and SOA Suite to PS5
See also:
WebLogic Web Service Deployment Descriptor Element Reference
Developing Spring-Based Applications for Oracle WebLogic Server

Migration from Weblogic to Apache Tomcat

I am migrating my project(uses servlets / jsp / jdbc / jndi) build on Weblogic 10c to an Apache Tomcat 7.0.22. I have managed to configure the ldap authentication server and also to replace the xxx-jdbc.xml used by weblogic. Now my problem is that i am trying to migrate the weblogic.xml file found in web Content/WEB-INF directory. The contents of the xml file are the following:
<?xml version = '1.0' encoding = 'UTF-8'?>
<weblogic-web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd"
xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
<security-role-assignment>
<role-name>REGISTERED_USER</role-name>
<principal-name>GROUP_NAME_FROM_LDAP</principal-name>
</security-role-assignment>
<session-descriptor>
<debug-enabled>false</debug-enabled>
<tracking-enabled>true</tracking-enabled>
<cookie-name>nameOfCookie</cookie-name>
<cookie-max-age-secs>-1</cookie-max-age-secs>
<url-rewriting-enabled>false</url-rewriting-enabled>
<encode-session-id-in-query-params>false</encode-session-id-in-query-params>
<sharing-enabled>false</sharing-enabled>
</session-descriptor>
<context-root>my_app_context_root</context-root>
<servlet-descriptor>
<servlet-name>FileDownload</servlet-name>
</servlet-descriptor>
</weblogic-web-app>
From top to bottom i have the security-role-assignment which maps users from an ldap group to have the REGISTERED_USER. The tag session-descriptor i think is self explained. Then there is my apps context root context-root. And then some servlet definition that is used to register the servlet to Weblogic (this is also defined in web.xml and i think this will not need any more handling).
So what is the best way to migrate this weblogic.xml file in my application?
In Tomcat, these things can be defined in a couple of different places.
For the security-role re-mapping, use the standard <security-role-ref> in web.xml to re-map role names.
If you are using a servlet-3.0-spec webapp, then many of your session- and cookie-related items are available via web.xml:
<session-config>
<cookie-config>
<name>nameOfCookie</name>
<max-age>-1</max-age>
</cookie-config>
<!-- just don't use "URL" to disable rewriting -->
<tracking-mode>COOKIE</tracking-mode>
</session-config>
Otherwise, you'll have to resort to some acrobatics. First, I'll assume that you are using a META-INF/context.xml file within your webapp for deployment to Tomcat.
Session cookie name
<Context sessionCookieName="nameOfCookie" />
Cookie max-age
Use the standard <session-config><session-timeout /> in web.xml. (Technically, this configures the max-age of the session, but the effect is the same: the cookie will essentially become invalid after the session expires. If you really need cookie max-age, read this thread: http://markmail.org/thread/u2ysiz3uxays2w4i)
Cookie debug/tracking are not supported by configuration. You will have to write your own Filter(s) to duplicate these features.
Disabling URL rewriting will require that you write a Filter that overrides HttpServletResponse.encodeURL and HttpServletResponse.encodeRedirectURL to be no-ops on their String arguments.

Categories