Multi module project.
In my ejb module I have the highlighted files. I would like to use the same files running a arquillian test in the web module.
In the pom.xml file in web module I have a dependency to the ejb module, but with scope provided as I do not want the get the "real" persistence.xml from ejb module.
<dependency>
<groupId>com.comp</groupId>
<artifactId>g4tc-ejb</artifactId>
<type>ejb</type>
<!-- Use scope provided as we are creating an ear file, and we do not want the packaged jar file in test, as we want the test-persistence.xml -->
<scope>provided</scope>
</dependency>
So in the RestTest class I want to include the files from the ejb module..
#Deployment
public static WebArchive getDeployment() {
File[] files = Maven.resolver().loadPomFromFile("pom.xml")
.importRuntimeAndTestDependencies().resolve().withTransitivity().asFile();
WebArchive war = ShrinkWrap.create(WebArchive.class, "g4tcRestWebservice.war")
.addAsLibraries(files)
.addPackages(true, "com.comp.g4tc.web")
.addPackages(true, "com.comp.g4tc.ejb") /* Load the classes from the ejb module instead of through dependency to avoid getting
the g4tc-ejb/src/java/resources/META-INF/persistence.xml, we want the one from the test package */
.addAsResource( "HERE AT THE test-persistence.xml FROM THE EJB MODULE", "META-INF/persistence.xml");
System.out.println(war.toString(true));
return war;
}
What is the best approach to do that. ?? Thanks
A quick and dirty way would be to check if these files can be found on the classpath, by checking ejb/target/classes. If this is the case, simply add:
.addAsResource(g4TravelCenterTest-ds.xml)
.addAsResource(import.sql)
.addAsResource(META-INF/test-persistence.xml)
Related
I created a EAR application in Eclipse to run in Glassfish 3.1. The used projects are: BibliotecaEAR2 (the main EAR. 'Biblioteca' means 'Library'), BibliotecaEJB (with EJBs), BibliotecaModel (with entities and DAOs) and BibliotecaWeb (The Web application). The application.xml has this structure:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>BibliotecaEAR2</display-name>
<module>
<web>
<web-uri>BibliotecaWeb.war</web-uri>
<context-root>biblioteca</context-root>
</web>
</module>
<module>
<ejb>BibliotecaEJB.jar</ejb>
</module>
</application>
In BibliotecaWeb, the META-INF/MANIFEST.MF is written this:
Manifest-Version: 1.0
Class-Path: lib/google/guava-18.0.jar
// other JARs in BibliotecaEAR2 project
BibliotecaEJB.jar
When I start the glassfish I get this warning message:
2014-10-20T14:34:31.691-0200|WARNING: PWC6351: In TLD scanning, the supplied resource file:/C:/dev/glassfish3/glassfish/domains/biblioteca-glass3/eclipseApps/BibliotecaEAR2/BibliotecaEJB.jar does not exist
java.io.FileNotFoundException: C:\dev\glassfish3\glassfish\domains\biblioteca-glass3\eclipseApps\BibliotecaEAR2\BibliotecaEJB.jar (O sistema nao pode encontrar o arquivo especificado)
Although it does not stop me from running the application, I would like to eliminate it.
Googling for PWC6351 warning, I perceived that it happens when a used JAR is not found in the Manifest File. However the request JAR is not simply a external library, but a sub-project in same EAR. Is there any additional configuration that should I do?
Thanks,
Rafael Afonso
From Packaging libraries with EARs:
When packaging applications in an EAR file, the library JARs need to
be placed in the archive lib directory (jars at the archive root level
are not added to the classpath and thus available from other EAR
artifacts.)
The library jars placed in the "/lib" directory of the EAR (the
directory name can be overridden in application.xml) will be visible
to all sub-modules (JARs, WARs, and RARs) with no further
configuration. No need to add Class-Path entries in the EAR manifest.
In fact you don't need to reference the jars in the lib folder, and it looks like it will not work if you reference a jar on the EAR root level, like your BibliotecaEJB.jar.
If you don't have a real dependency from your WAR module classes to your EJB module classes you can just remove all the entries from the MANIFEST.MF and it should work.
If you instead have a real dependency from WAR to EJB, you may have to think about your project structure and if you really need an EAR. You can also package all the stuff into a single WAR.
The right way to use an EAR with WAR and EJB modules requires a little bit of work if your current WAR classes directly depend on classes from the EJB module:
1. Step
You have to create interfaces for all your "service" classes which should be available to classes in the web application (WAR).
Here is a simple example:
public interface FileService {
public void showFileInformation(File file);
}
and
#Stateless
#Local(FileService.class)
#Remote(FileService.class)
public class FileServiceImpl implements FileService {
#Override
public void showFileInformation(File file) {
// here
// is
// the
// real
// stuff
}
}
2. Step
The next step is to package all your new interfaces into a new jar. Your model jar looks similar to this approach. If this can't be used for this purpose, create a simple java application project which gets packaged as jar and put all the interfaces into this project. This jar has to be in the lib folder of the EAR.
BibliotecaEAR2
-- BibliotecaEJB
-- BibliotecaWeb
-- /lib/interfaces.jar
Then you have to add a dependency to this new jar in your WAR and EJB modules, so that they can find the interface classes.
3. Step
The services can be injected into the managed classes of your web applications (and into other service classes) like this:
#RequestScoped
public class FileHandler {
// make sure to use the interface
#EJB
FileService fileService;
}
Maybe you already have something similar to this, but then it should work without any entries in the MANIFEST.MF.
See also:
Maven2: Best practice for Enterprise Project (EAR file)
Java EE - EAR vs separate EJB+WAR
Packaging EJB in JavaEE 6 WAR vs EAR
I had a similar issue and solved by customizing module location, like this
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" id="Application_ID" version="6">
<display-name>BibliotecaEAR2</display-name>
<module>
<web>
<web-uri>BibliotecaWeb.war</web-uri>
<context-root>biblioteca</context-root>
</web>
</module>
<module>
<ejb>BibliotecaEJB.jar</ejb>
<bundleDir>/lib</bundleDir> <!-- ADD THIS OPTION TO THE MODULE -->
</module>
</application>
This solution is taken from the Maven EAR plugin documentation, which uses Maven 3 syntax, but I think you can use it too (or you can migrate to Maven 3).
Hope that helps.
Based on the advice to use JSF, the following sample would like to be run in order to learn more about JSF and to implement this technique into the servlet. However, a number of libraries is unable to be imported:
package tobedefinedservlet;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class Hello {
final String world = "Hello World!";
public String getworld() {
return world;
}
}
javax.faces
The import javax.faces cannot be resolved
ManagedBean
ManagedBean cannot be resolved to a type
You have to include a JSF library like for example Mojarra in the classpath of your application.
First of all have a look at the Primefaces user guide (especially chapter 2.2). You can download e.g. Mojarra here and include the JAR or add the dependency to your POM.xml if you are using Maven. Hope that helps.
If you're using maven for build automation, add the latest jsf-api dependency to your pom.xml:
<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1</version>
</dependency>
Or the latest javax.faces-api implementation:
<dependency>
<groupId>javax.faces</groupId>
<artifactId>javax.faces-api</artifactId>
<version>2.3</version>
</dependency>
However, note that JSF is integrated into most Java EE application servers, such as JBoss.
See also this answer.
in my case ...I went to project properties and in the search engine I wrote facets ... I went to the right of the window and selected the runtime tab and select wildfly ... then apply and apply and close and solve ...
If you're not using maven you have to manually install the jar. You can download it at this link:
javax.faces
If you're using eclipse you can right click your Web App project and click properties at the bottom. Then under the java build path make sure the libraries panel at the top is selected then select the Web App library and on the right click Add External JARS. You can go to your downloads folder and select the jsf-api-2.1.jar and refresh the project and you can now import that annotation.
I tried to follow Spring Getting Started Guide for "Serving Web Content with Spring MVC" which uses Spring Boot and Gradle in addition to Maven.
I installed Gradle plugins to Eclipse.
I want to run the application using the Tomcat server in Eclipse because of that I also followed "Converting a Spring Boot JAR Application to a WAR" guide and changed the "build.gradle" file as mentioned in the guide. Basically, I added lines "apply plugin: 'eclipse-wtp'", "apply plugin: 'war'", configurations {providedRuntime}, and providedRuntime("org.springframework.boot:spring-boot-starter-tomcat"); and changed jar settings to war settings. Here is the build.gradle file:
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-milestone" }
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.2.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'war'
eclipse.project {
natures 'org.springsource.ide.eclipse.gradle.core.nature'
}
war {
baseName = 'gs-serving-web-content'
version = '0.1.0'
}
repositories {
mavenCentral()
maven { url "http://repo.spring.io/libs-milestone" }
}
configurations {
providedRuntime
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
testCompile("junit:junit")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
I also added HelloWebXml class as they mention. Here is the class:
package hello;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class HelloWebXml extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
In addition to these I needed to change pom.xml a little because it was complaining about Java SE 7 features. Added the lines below to the pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<showWarnings>true</showWarnings>
<compilerVersion>1.7</compilerVersion>
<fork>true</fork>
</configuration>
</plugin>
The rest is the same as the getting started guide.
For building, I run
gradlew eclipseWtp
gradlew clean build
commands. After this the war file is created in build/libs folder of the project. If I copy the war file to my local Tomcat server and start the server, everything works as expected.
If I drag the project to the Tomcat server under the Servers tab (which is created using the same local Tomcat) and run the server, a ClassCastException is thrown with the complaint:
"Cannot cast org.springframework.web.SpringServletContainerInitializer to javax.servlet.ServletContainerInitializer".
I checked the folder structure of the project in both of the deployment locations.
In the local (non-Eclipse) deployment location, after the server starts a folder with the name of the war file is created as expected. In the WEB-INF folder, there is a lib-provided directory. I checked the deployment location of the Tomcat of Eclipse, it didn't include a directory named lib-provided. I guess the problem is about this directory not being created but I couldn't find a solution.
I was already using Spring MVC, and I know how to create MVC projects with web.xml but I am new to Spring Boot. The Tomcat server of Eclipse runs my previous Spring MVC projects fine. So the problem is about the Spring Boot project.
I checked several related questions but they were not the same one as mine. I couldn't find a solution to my problem.
What am I missing here?
Thanks in advance.
I imagine that you are getting a clash with the servlet-api JARs. If you are developing with embedded Tomcat (creating a JAR) you need to include the servlet-api JAR on your classpath in the compile scope. When you are deploying to an existing Tomcat installation (creating a WAR) you must declare the servlet-api jar in provided scope, otherwise it will end up in web-inf/lib and cause conflicts with the version provided by your container.
Here is the POM from the sample Spring Boot WAR project:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-traditional/pom.xml
Note how the spring-boot-starter-tomcat uses the provided scope.
Spring Boot does some special handling to allow executable WARs that run both embedded or in a container. Specific attention has to be payed to dependencies in provided scope since these might conflict with the container. The details are described in the Spring Boot reference guide. The reason your build works when deployed via a built WAR but not via Eclipse is that Eclipse WTP doesn't actually use Maven to perform the build, so a Maven build and a WTP build won't exactly match.
I'm working on addressing the same issue myself. What I plan to do is create a seperate 'dev' maven module specifically for this purpose, and use tags to switch (some of) the provided entries to runtime.
#meribald you can configure your pom.xml in that whay:
<profiles>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<packaging-profile>jar</packaging-profile>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>prod</id>
<properties>
<packaging-profile>war</packaging-profile>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
and on the top of your pom.xml
<packaging>${packaging-profile}</packaging>
So, when you are developing you run you application as a Java Application, and maven will generate a jar file. When you want to package a war file to deploy on a server, you run on a maven command line
mvn -Pprod package
or in Eclipse run as >> Maven Build ..., and put "package" on the goals field, and "prod" (without quotes) on profiles field.
I've got an JavaEE6 app with following structure:
app.ear
META-INF
application.xml
lib
commmon-server-lib.jar
webapp1.war
webapp2.war
services-ejb.jar
Both webapps have common-server-lib.jar in Class-Path entry of their MANIFEST.MF (skinny war's).
application.xml:
<application>
<module>
<ejb>services-ejb.jar</ejb>
</module>
<module>
<web>
<web-uri>webapp1.war</web-uri>
<context-root>/webapp1</context-root>
</web>
</module>
<module>
<web>
<web-uri>webapp2.war</web-uri>
<context-root>/webapp2</context-root>
</web>
</module>
<library-directory>lib</library-directory>
</application>
In common-server-lib.jar there is a web filter that should have few EJBs and other CDI managed beans injected. This filter is defined in web.xml's of both webapps.
common-server-lib.jar and war's have beans.xml in appropriate place.
Now the problem is, that when I try to deploy this app to Glassfish I get errors like this:
Class [ Lcom/acme/UserService; ] not found. Error while loading
[ class com.acme.filter.MyFilter ]
UserService service is located in services-ejb.jar
So my question is: what am I doing wrong...? Is there something wrong in defining web components (that use injections for it's dependencies) in a shared library?
Edit:
In section 15.5 of JSR-315 (Servlets 3.0 final spec) one can find:
In a web application, classes using resource injection will have their annotations
processed only if they are located in the WEB-INF/classes directory, or if they are
packaged in a jar file located in WEB-INF/lib.
I've moved common-server-lib.jar to WEB-INF/lib directories of both webapps but I'm still having same issue ;/...
After many hours of struggling with this puzzle I've found a solution:
Add web-fragment.xml to commmon-server-lib.jar with my filter
Remove filter specification from webapps web.xml's
Change maven fonfiguration to remove all jar's from WEB-INF/lib
directory except commmon-server-lib.jar
Remove commmon-server-lib.jar from EAR /lib directory
The error is:
SEVERE: Servlet.service() for servlet [jsp] in context with path [] threw exception [Unable to compile class for JSP] with root cause
java.lang.ClassCastException: de.odysseus.el.ExpressionFactoryImpl cannot be cast to javax.el.ExpressionFactory
at javax.el.ExpressionFactory.newInstance(ExpressionFactory.java:180)
at javax.el.ExpressionFactory.newInstance(ExpressionFactory.java:107)
at org.apache.jasper.compiler.PageInfo.<init>(PageInfo.java:79)
at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:110)
.....
The project is using a war overlay, in which the overlaid project has the juel-impl jar, which is necessary for its use of shindig. Any way to use jstl in the child project jsp pages?
Seems you have two rivaling EL APIs in your class path, tomcat's and another one from your application. Your war file must not contain an el-api.jar or juel-api.jar. Make sure to exclude those dependencies.
The Juel 2.1.3 jar is a combination of the following Jars juel-impl.jar, juel-spi.jar and juel-api.jar.
We had the same issue when we included juel 2.1.3 jar in the pom and deployed in tomcat 7.
The issue is resolved by removing Juel 2.1.3 from pom and by adding only juel-impl.
<dependency>
<groupId>de.odysseus.juel</groupId>
<artifactId>juel-impl</artifactId>
<version>2.2.6</version>
</dependency>
you need to also add
<dependency>
<groupId>de.odysseus.juel</groupId>
<artifactId>juel-api</artifactId>
<version>2.2.6</version>
</dependency>
The juel 2.1.3 jar contains the javax/el interfaces and are also a part of jsp-api jar.
I hope this will help.