How to extend/customize a WAR with another project - java

We have the following scenario with our project:
A core web application packaged as a
war file (call it Core project).
The need to "customize" or "extend" the core app
per customer (call it Customer project). This mostly includes
new bean definitions (we're using
Spring), ie. replacing service
implementations in the core.war with
customer-specific implementations.
We want to develop the Core and Customer projects independently
When the Customer project is developed, we need to be able to run/debug it in Eclipse (on Tomcat) with the Core project as a dependency
When the Customer project is built, the resulting war file "includes" the core and customer projects. So this .war is the customer-specific version of the application
I'm looking for suggestions as to the best way to do this in terms of tooling and project configuration.
We're using Ant currently, but would like to avoid getting buried in more ant. Has anyone done this with Maven?
I've seen a lot of posts on how to build a web application that depends on a java application, but nothing on a web application depending on another web app.
Thanks!

Sounds like Maven WAR overlay does what you want.

In Eclipse there is a "native" WTP way to do this. It mainly using linked folders and a little hack in .settings/org.eclipse.wst.common.component file. You can read the article about it at http://www.informit.com/articles/article.aspx?p=759232&seqNum=3 the chapter called "Dividing a Web Module into Multiple Projects". The problem with this is that the linked folder must be relative to some path variable can be defined in Window/Preferences/General/Workspace/Linked Resources tab. Otherwise the linked folder definition (can be found in .project file in project root) will contain workstation specific path. The path variable practicly should be the workspace root. This solution works great with WTP, deploy and everything else works like it should.
The second solution is to use ant for it. Forget it. You will deeply regret it.
The third solution is to use maven for it. You can forget the comfort of WTP publishing if you dont do some tricks. Use war overlays like others suggested. Be sure to install both m2eclipse, m2eclipse extras. There is an extension plugin released recently, that can help you. Described at this blog. I did not try it, but looks ok. Anyway Maven have nothing to do with linked folders, so I think even the first solution and this maven overlay can live together if necessary.
As for headless builds you can use HeadlessEclipse for the first solution. It is dead (by me) now, but still works :). If you use the maven overlay + eclipse stuff, headless builds are covered by maven.

This is little bit more involved but at a high-level we do it as below. We have the core platform ui divided to multiple war modules based on the features (login-ui,catalog-mgmt-ui etc). Each of these core modules are customizable by the customer facing team.
We merge all of these modules during build time into 1 single war module. The merge rules are based on maven's assembly plugin.

You usually start from the Java source code. WARs don't include the Java source code, just the compiled classes under WEB-INF/classes or JARs under WEB-INF/libs.
What I would do is use Maven and start a brand new empty webapp project with it: http://maven.apache.org/guides/mini/guide-webapp.html
After you have the new empty project structure, copy the Java source code to it (src/main/java) and fill out the dependencies list in pom.xml.
Once you've done all this you can use mvn clean package to create a standard WAR file that you can deploy to Tomcat.

You might want to look into designing your core app with pluggable features based on interfaces.
For example say your core app has some concept of a User object and needs to provide support for common user based tasks. Create a UserStore interface;
public interface UserStore
{
public User validateUser(String username, String password) throws InvalidUserException;
public User getUser(String username);
public void addUser(User user);
public void deleteUser(User user);
public void updateUser(User user);
public List<User> listUsers();
}
You can then code your core app (logon logic, registration logic etc) against this interface. You might want to provide a default implementation of this interface in your core app, such as a DatabaseUserStore which would effectively be a DAO.
You then define the UserStore as a Spring bean and inject it where needed;
<bean id="userStore" class="com.mycorp.auth.DatabaseUserStore">
<constructor-arg ref="usersDataSource"/>
</bean>
This allows you to customise or extend the core app depending on specific customer's needs. If a customer wants to integrate the core app with their Active Directory server you write a LDAPUserStore class that implements your UserStore interface using LDAP. Configure it as a Spring bean and package the custom class as a dependant jar.
What you are left with is a core app which everyone uses, and a set of customer specific extensions that you can provide and sell seperately; heck, you can even have the customer write their own extensions.

Related

Override Class loader "Parent First"

I have Java web application running on a web application server single node setup, in which I am using a liberary the I included in my Web-Inf and using in my code.
The issue is that I have another application that added its liberaries to the WebSphere parent lib folder, one of which are the same liberary I am using but with an older version, creating conflict and jamming my code.
The server class loader is configured Parent first unfourtunatly and I cannot change that fact. My question is, how can I make my app use my liberary, ignoring the one used by the class loader?
The solution is to move the conflicting package to a shared library, configure the library to use an isolated class loader, and associate that library with your application or module. The "isolated class loader" setting creates a separate parent-last class loader for the shared library, so you get that behavior targeted to only the artifacts that need it rather than having to apply it to the entire application or module.
https://www.ibm.com/support/knowledgecenter/en/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tcws_sharedlib.html
I'm specifically referencing the "Use an isolated class loader for this shared library" setting.
If you can't change your application server setup there are basically three things you can do:
Downgrade your application dependency to lower version used by WebSphere server and keep it in sync. This is preferable as it's least hassle.
Shade the dependency during build to your own package to prevent package clash. This can be done with Maven Shade Plugin, see Relocating Classes usage example.
Write a new custom classloader to work around the problem.
I'd try them in 1 -> 2 -> 3 order. Option 3 is possible but is an error-prone nightmare. I'd rather deploy to another server than do it.

Nested modules with Spring

I am developing project with Spring Framework.
I have created about 5 modules, sometimes one depend on other, but they are all on top level, and up to this point everything works fine.
Example:
Database module has only external dependencies
Identity module depends on database module
Facebook stuff module depends on identity module
Now, I have created directory in root of project called modules, and moved all modules into it (so they all were, and still are on same relative distance to each other).
All tests passes and I can build/compile and inspect classes without any problem.
However, now when I try to run only identity module (that does not require facebook stuff) spring throws me an exception, that it cannot find facebook beans. Of course it cannot, because there is no dependency, but I do not want to add this dependency. #Configuration is #Lazy so there is no point creating such #Bean anyway.
Code:
new AnnotationConfigApplicationContext(Application.class);
Application class is #Lazy #Configuration and does #ComponentScan from whole application, and as I understand it finds also #Configuration's from other modules and then - I do not know why - tried to create those #Bean's from other modules but fails as expected.
I have verified with git, that the only between working and not working states are moving those modules into new folder.
So to clarify, working/default structure is:
/.gradle
/.idea
/DatabaseModule
/IdentityModule
/FacebookModule
/.out
/.gitignore
and not working one is:
/.gradle
/.idea
/modules/DatabaseModule
/modules/IdentityModule
/modules/FacebookModule
/.out
/.gitignore
Code stays the same.
I think, that if I will add all dependencies to all modules then it will work but for obvious reasons I do not want to do this.
Am I doing something wrong?
Is there any convention, that I am breaking?
Bonus question: how are nested modules different, from ordinary folder containing modules?
EDIT:
I should also note, that all tests pass in both scenarios, however I am not using spring in tests (no dependency injection) - just new or Mock() everything

ClassLoader For frameworkspring 4.3 with tomcat 8

The problem consist some strategies!
The project this manager dependencies "maven" and "Sonatype Nexus"
There are same artifact, in this case call: core.
That core contains twos class special called SysSpringBoot and SysSpringConfig
This one special class SysSpringConfig, it's need rewrite for last project to use this artifact.
This artifact use for many projects, where each project that use should say which packages scan.
when start this project has one directory it's seems
--webapp
-- pages .xhtml (web pages)
-- WEB_INF
-- web.xml
-- classes
-- SysSpringConfig.class
-- lib
-- my-artifact-core-1.0.0.0.jar
(in my file .jar also contains SysSpringConfig.class (old version))
The classLoader tomcat 8(last version, in old version not has this problem), ready first
../classes/SysSpringConfig.class, then not found all dependencies for use,
at now, find in files *.jar, but in *.jar also find SysSpringConfig.class that time ready another class with the first time!
Same suggest kind implement personality MyClassLoader to solve this problem with Spring classLoader.
sorry with my English

What is the difference between javax.faces-2.1.14.jar from jsf-api-2.2.0-m05.jar and jsf-impl-2.2.0-m05.jar

I am confused between the difference of javax.faces-2.1.14.jar from jsf-api-2.2.0-m05.jar and jsf-impl-2.2.0-m05.jar
I am trying to make a jsf project without using maven and while searching for examples I saw different jar dependencies on different tutorials. The tutorial from coreservlets uses javax.faces-2.1.14.jar and the other tutorial I saw from a different site uses 2 jar files jsf-api-2.2.0-m05.jar and jsf-impl-2.2.0-m05.jar
Id like to know the difference of these two set of dependencies.
Thanks in advance guys.
The jsf-api-xxx.jar contains classes that are under packages java package javax.faces. The classes in this jar are implementation of standard API defined by JSF specification. The jsf-impl-xxx.jar contains classes that are under java package com.sun.faces, which as the java package indicates, is Sun's own class for JSF implementation.
The javax.faces-xxx.jar actually merges the previous two jar files together. In the Maven repository, it is under org.glassfish groupId. You will find both javax.faces and com.sun.faces java package inside.
So what should you use for your development? Actually you can use both. But the recommended way is to include jsf-api-xxx.jar only in the compilation classpath. Thus your own application does not depend on any classes under com.sun.faces package to achieve the portability to other JSF implementations. If you are using an application such as GlassFish, the container should already provide the JSF implementation at runtime. You should not package the above JSF jar files with your war or ear file, as server will provide all of them. If you use a container that does not come with a JSF implementation by default such as Tomcat, you need to package javax.faces-xxx.jar or (jsf-api-xxx.jar + jsf-impl-xxx.jar) in the WEB-INF/lib.
They are different versions.
javax.faces-2.1.14.jar is a combined JAR file for 2.1.14
jsf-api-2.2.0-m05.jar and jsf-impl-2.2.0-m05.jar are separate JARs for 2.2.0-m05.
The differences between the versions can be found in the release notes, but 2.2 and 2.1 are non-trivially different.

How do I create a non-EJB super simple web-service .war for Java in Eclipse?

I have been attempting to create a super simple web-service (non-SOAP wsdl Server) within Eclipse Java EE (Juno) using Java 1.6. I want the web-service war to be as simple as possible, as in this simple (first reply in the thread).
IOW, I want the war file to just have the class I have defined (which includes the #WebService and #WebMethod annotations) and possibly a web.xml file which can then be deployed in Eclipse Java EE to the JBoss 6.0 server I have set up.
I must be missing some simple step somewhere. Each time I have tried, I either cannot get the web-service to deploy, or Eclipse wants to auto-generate and add a huge number of useless classes to the deployment.
I have Eclipse Java EE set up and I created a File -> New-> Dynamic Web Project and call it ProjectHelloService. I then create a single class in the project under Java Resources/src in its own package, ws.simple. The class looks like this:
package ws.simple;
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class HelloService
{
#WebMethod
public String sayHello(String name)
{
return "Hello, " + name;
}
}
I then start up the JBoss server and "Add" the project to JBoss. I see the "...deploy, ctxPath=/ProjectHelloService" message indicating that my project has deployed. However, when I go to the default JBoss page -> JBoss Web Services Console -> View a list of deployed services, I see "There are currently no endpoints deployed ". When I dig around and try to see what was deployed in JBoss's server/default folder, I cannot find anything in the deploy folder.
Again, I must be missing some step somewhere. For example, I don't see a .war (or even .jar) file being generated, in Eclipse nor in the JBoss deploy folder. However, I am not deeply versed in the nuances of how Eclipse works with JBoss 6.0, so I might be missing some configuration subtlety here.
Is there something simple I can do to get a super stupid simple .war file to deploy to the Eclipse contained JBoss 6.0 so that I can see my web-service? And since JBoss is able to do all the auto-file generation automatically from the annotations in the .war file, I don't want Eclipse to do all the extra file stub generation crap. That's CORBA old school style, and makes for a much less manageable project (at least for the area I am working in right now).
And I don't suppose there is some way that I can have the above in Eclipse while having the convenience of the Netbeans approach to creating and managing Java web-services. If there is, I sure would like to know what it is.
Thank you for any guidance and/or assistance you can over here.

Categories