Glassfish4 + EJB + Spring, deploy fails - java

I am upgrading an application from Java7 on Glassfish 3.1.2.2, to Java8 on Glassfish 4.1. The application is packaged as an ear file, containing a jar-file with remote EJBs and Spring beans, as well as a war-file with a couple of servlets and some webservices.
There are only some minor changes done to the actual application, compared to how it was with Glassfish 3.x, the total changes made are:
Built with Java8 instead of Java7.
Deployed on Glassfish 4.1 instead of 3.1.2.2
Newer version of Hibernate
Newer version of ActiveMQ (client)
I can't see any difference between the previous ear-file and the new one (except the abovementioned lib-jars), but still when I try to deploy I get errors like this for all my EJBs:
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type SomethingLogic with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject private com.my.application.server.service.SomethingServiceSession.somethingLogic
Where SomethingService is an EJB, SomethingLogic is a Spring bean.
My EJBs are defined like this:
#Stateless
#RolesAllowed("secure")
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class SomethingServiceSession implements SomethingService {
#Inject
private SomethingLogic somethingLogic; //Spring bean
SomethingLogic is an interface.
I have a beanRefContext.xml containing:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanFactory" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="classpath*:applicationContext-glassfish.xml"/>
</bean>
</beans>
The EJB services are defined in glassfish-ejb-jar.xml, like this:
<ejb>
<ejb-name>SomethingServiceSession</ejb-name>
<ior-security-config>
<as-context>
<auth-method>USERNAME_PASSWORD</auth-method>
<realm>AD</realm>
<required>true</required>
</as-context>
</ior-security-config>
</ejb>
I have tried adding a beans.xml with the following content to the resources\META-INF folder of my EJB-project:
<?xml version="1.0"?>
<beans 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://jboss.org/schema/cdi/beans_1_0.xsd" />
No luck.
I have also tried adding #LocalBean to all my EJBs, also with no luck.
In addition, I have tried to disable CDI all together, using this command:
asadmin set configs.config.server-config.cdi-service.enable-implicit-cdi=false
This actually allows my EJB services to be deployed, but I'm suspecting that it has the not so good side effect of my webservices not being discovered, so I want to be able to deploy with CDI enabled to rule this out.
Update:
I have tried changing #Inject with #Autowired in all my non-Spring-handled classes (EJBs, webservices and servlets). Now I get the same error for actual Spring beans. It seems that Glassfish will try to look for EJB beans when encountering #Inject, no matter where they occur.

Fixed my problem by adding bean-discovery-mode="none" to my various beans.xml files.
<?xml version="1.0"?>
<beans 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://jboss.org/schema/cdi/beans_1_2.xsd"
bean-discovery-mode="none" />

Related

How can I pass spring application.yaml file to spring context created in Java project using spring boot project as dependency?

I am using spring boot project as a dependency in another non spring java project. The problem is I am getting error when spring processes #Value() annotation.
According to this article
In order to get instances of the beans managed in spring I created ClassPathXmlApplicationContext and created applicationcontext.xml,
but I am getting error from #Value("${proper}") anotation that
the resource cannot be resolved to URL because it does not exist
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"spring-application.xml"});
context.getBean("mybean");
applicationcontext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example" />
</beans>
The application.yaml is located outside the project in /opt/myapp/config/application.yaml and contains:
proper: file:/path/to/some/file/that/exists
I am expecting that spring will initialize the value of proper in component using the default application.yaml. since I can run spring boot project stand alone and it works fine.
Any Ideas?

Junit in spring based project where multiple projects are involved

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="commonBean" class="commonBean">
</bean>
</beans>
#Configuration
#ImportResource({
"classpath:"commonConfig.xml"
})
public class CommonBeanConfiguration{
}
We have a common project as above.We are using this as jar in another project(Main Project).
We are using commonBean bean from another project(Main Project).
When we deploy Main Project(including jar of common project) on server.It works fine.
But we get "commonBean not found exception" if we try to run junit classes from Main Project. seems like beans from commonConfig.xml is
not being created in junit.
we are using spring for testing.
RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration.
Use this:
#ContextConfiguration(locations = "classpath:commonConfig.xml")
instead of #import as it loads the bean during runtime while #ContextConfiguration loads bean before invoking test cases.

What happens behind the scenes when a property placeholder is defined in a Spring context (JNDI-wise)?

I have a Java web application using Spring and JSF, deployed in Tomcat.
For the record, in web.xml, only the Faces servlet is configured; there is no Spring servlet.
The entry point to my Spring context is applicationContext.xml, which looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<context:component-scan base-package="my.pack" annotation-config="true" />
<context:property-placeholder location="file:${admin.config.path}/database.properties"/>
<context:spring-configured />
<context:annotation-config />
<aop:aspectj-autoproxy />
</beans>
In the property-placeholder definition one can see that I'm injecting an external property, which, in this case, is an environment variable. This property is passed via Tomcat context configuration, like this:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/cntxt">
<Environment name="admin.config.path" value="d:/conf/"
type="java.lang.String" override="false"/>
</Context>
I'm also injecting this environment variable in one of my Spring-managed beans, like this:
#Value("${java:comp/env/admin.config.path}")
private String confDir;
(This is because I'm also using that directory for some other configuration files, which are not .properties files).
With the configuration above, everything works just fine - all the wirings are performed without any flaw.
But, at some moment, I stopped needing injecting properties via the property placeholder configurer from database.properties (but I still need the other files from the admin.config.path), therefore I removed the <context:property-placeholder> line from applicationContext.xml.
At that moment, the injection using #Value stopped working in my Spring-managed bean.
Does anybody know what actually happened? It seems like the JNDI injection fails if the property placeholder configurer is not defined in the Spring context.
Is there any way I can re-enable this kind of injection (without defining a dummy property placeholder pointing to an empty properties file)?
You need a property placeholder configurer instance, the sole purpose of it is to replace placeholders with actual values. If you remove it no placeholders will be replaced.
Either add a <context:property-placeholder /> and leave out the location field or add a bean of the type PropertySourcesPlaceholderConfigurer. Either way will re-enable your placeholder support.
Small suggestion remove the java:comp/env part of the property, by default it will do a JNDI lookup if the property cannot be resolved in other locations (servlet context, properties, system properties etc.).

Trying out Spring 3 MVC, Getting a page error

Trying to configure spring 3 MVC, here is what I did so far:
I added all the spring 3.0 libraries to my netbeans project.
My web.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<servlet>
<servlet-name>WebApplication1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WebApplication1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Next I created a WebAppliation1-servlet.xml, also in my /web-inf folder:
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<!--
- The controllers are autodetected POJOs labeled with the #Controller annotation.
-->
<context:component-scan base-package="org.springframework.Hi"/>
<!--
- The form-based controllers within this application provide #RequestMapping
- annotations at the type level for path mapping URLs and #RequestMapping
- at the method level for request type mappings (e.g., GET and POST).
- In contrast, ClinicController - which is not form-based - provides
- #RequestMapping only at the method level for path mapping URLs.
-
- DefaultAnnotationHandlerMapping is driven by these annotations and is
- enabled by default with Java 5+.
-->
<!--
- This bean resolves specific types of exceptions to corresponding logical
- view names for error views. The default behaviour of DispatcherServlet
- is to propagate all exceptions to the servlet container: this will happen
- here with all other types of exceptions.
-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.servlet.PageNotFound">pageNotFound</prop>
<prop key="org.springframework.dao.DataAccessException">dataAccessFailure</prop>
<prop key="org.springframework.transaction.TransactionException">dataAccessFailure</prop>
</props>
</property>
</bean>
<!--
- The BeanNameViewResolver is used to pick up the visits view name (below).
- It has the order property set to 2, which means that this will
- be the first view resolver to be used after the delegating content
- negotiating view resolver.
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="1"/>
<!--
- This bean configures the 'prefix' and 'suffix' properties of
- InternalResourceViewResolver, which resolves logical view names
- returned by Controllers. For example, a logical view name of "vets"
- will be mapped to "/WEB-INF/jsp/vets.jsp".
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" p:order="2"/>
</beans>
I then created a simple welcome.jsp in the folder /WEB-INF/jsp/welcome.jsp
I then created a package:
org.springframework.Hi
And I created a TestController.java file:
package org.springframework.Hi;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class TestController {
#RequestMapping("/")
public String welcomeHandler(){
return "welcome";
}
}
I wanted this to work w/o any file extensions, so I don't have to end my urls with xxx.htm etc.
So when I run the netbeans project I get the error:
type Status report
message Servlet WebApplication1 is not available
description The requested resource (Servlet WebApplication1 is not
available) is not available.
What exactly am I missing here?
Tomcat logs
Thanks for the feedback
My tomcat logs show this:
SEVERE: Servlet /WebApplication1 threw load() exception
java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1387)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1233)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:316)
at org.springframework.web.servlet.DispatcherServlet.<clinit>(DispatcherServlet.java:207)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
I'm asuming that error message you quoted was the error message the browser sees when it tries to access the application. This is because it didn't deploy properly.
You need to look through the web server startup logs, that will give you much more information as to why it didn't deploy.
edit: OK, that helps a lot... you need to add Apache Commons Logging to your classpath.
I used to encounter a similar problem... except it happened only when I try to run the Spring Web MVC app via the STS IDE (version 2.3.2). However, if I packaged as a WAR and deployed it to a running instance of tcServer or even Tomcat, the app worked just fine.
I ended up adding commons-logging and some other JARs to the server's launch configuration in STS IDE, in the User Entries section under the Classpath tab. This solved my problem. Why some JARs don't get added to the Java EE module dependency while running within STS, I don't still understand.
Hope this helps.

Tomcat vs Weblogic JNDI Lookup

The Weblogic servers we are using have been configured to allow JNDI datasource names like "appds".
For development (localhost), we might be running Tomcat and when declared in the <context> section of server.xml, Tomcat will hang JNDI datasources on "java:comp/env/jdbc/*" in the JNDI tree.
Problem: in Weblogic, the JNDI lookup is "appds" whilst in Tomcat, it seems that that I must provide the formal "java:comp/env/jdbc/appds". I'm afraid the Tomcat version is an implicit standard but unfortunately, I can't change Weblogic's config ... so that means we end up with two different spring config files (we're using spring 2.5) to facilitate the different environments.
Is there an elegant way to address this. Can I look JNDI names up directly in Tomcat? Can Spring take a name and look in both places? Google searches or suggestions would be great.
How to use a single JNDI name in your web app
I've struggled with this for a few months myself. The best solution is to make your application portable so you have the same JNDI name in both Tomcat and Weblogic.
In order to do that, you change your web.xml and spring-beans.xml to point to a single jndi name, and provide a mapping to each vendor specific jndi name.
I've placed each file below.
You need:
A <resource-ref /> entry in web.xml for your app to use a single name
A file WEB-INF/weblogic.xml to map your jndi name to the resource managed by WebLogic
A file META-INF/context.xml to map your jndi name to the resource managed by Tomcat
This can be either in the Tomcat installation or in your app.
As a general rule, prefer to have your jndi names in your app like jdbc/MyDataSource and jms/ConnFactory and avoid prefixing them with java:comp/env/.
Also, data sources and connection factories are best managed by the container and used with JNDI. It's a common mistake to instantiate database connection pools in your application.
spring
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup jndi-name="jdbc/appds"
id="dataSource" />
</beans>
web.xml
<resource-ref>
<description>My data source</description>
<res-ref-name>jdbc/appds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
weblogic.xml
<?xml version="1.0" encoding="UTF-8" ?>
<weblogic-web-app
xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.oracle.com/weblogic/weblogic-web-app http://http://www.oracle.com/technology/weblogic/weblogic-web-app/1.1/weblogic-web-app.xsd">
<resource-description>
<jndi-name>appds</jndi-name>
<res-ref-name>jdbc/appds</res-ref-name>
</resource-description>
</weblogic-web-app>
META-INF/context.xml (for Tomcat)
<Context>
<ResourceLink global="jdbc/appds" name="jdbc/appds" type="javax.sql.DataSource"/>
</Context>
JndiLocatorSupport has a property resourceRef. When setting this true, "java:comp/env/" prefix will be prepended automatically. So I believe it would be correct to differentiate this parameter when moving from Tomcat to Weblogic.
I've managed the trick with Tomcat and WebLogic using Spring. Here is a description of how it worked for me.
The following config works in Tomcat and Weblogic for me.
In Spring:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<!-- This will prepend 'java:comp/env/' for Tomcat, but still fall back to the short name for Weblogic -->
<property name="resourceRef" value="true" />
<property name="jndiName" value="jdbc/AgriShare" />
</bean>
In Weblogic Admin Console create a JDBC resource named jdbc/AgriShare. Under 'Targets', MAKE SURE YOU TARGET THE DATASOURCE TO THE SERVER YOU ARE DEPLOYING YOUR APP TO!. This particular point cost me some time just now...
How about an evironment variable? Set developers machines with the tomcat name and production with the Weblogic name. You can even set your code to use a default one (WebLogic) in case the variable don't exist.
How are you referencing the resource in spring?
This is what we have for tomcat:
context:
<Resource name="jms/ConnectionFactory" auth="Container" type="org.apache.activemq.ActiveMQConnectionFactory" description="
JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory" brokerURL="tcp://localhost:61615" brokerName="StandaloneAc
tiveMQBroker"/>
spring:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<jee:jndi-lookup jndi-name="jms/ConnectionFactory" id="connectionFactory" resource-ref="true"
expected-type="javax.jms.ConnectionFactory" lookup-on-startup="false"/>
The jee namespace comes from:
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
Setting up DataSource in the application itself is not that crazy :) I would say that is even mandatory if application is meant to be deployed on a grid. River, GigaSpaces, or similar.
Note: I do not say connection settings have to be hardcoded inside of WAR, they need to be supplied at deployment time/runtime. This simplifies management of cloud instances since there is only on place to configure.
Configuring resources at the container makes sense only if multiple applications are deployed there and they can use shared resource.
Again, in cloud type of deployments there is only one application per servlet container instance.
My application also had a similar problem and this is how I solved it:
1) WEB-INF/classes/application.properties contains the entry:
ds.jndi=java:comp/env/jdbc/tcds
2) On the WLS machine, I have an entry in the /etc/sysenv file:
ds.jndi=wlsds
3) I configured spring to lookup the JNDI vis the property ${ds.jndi}, using a PropertyPlaceholderConfigurer bean with classpath:application.properties and file:/etc/sysenv as locations. I also set the ignoreResourceNotFound to true so that developers need not have /etc/sysenv on their machines.
4) I run an integration test using Cargo+Jetty and I could not properly set up a JNDI environment there. So I have a fallback BasicDataSource configured too using the defaultObject property of JndiObjectFactoryBean.

Categories

Resources