1

I will try to explain my question with an example. Let us say that we are writing a hotel reservation system which is web based using Java. We will have different payment methods, say Paypal, Master Card and Visa Card. Different customers of our product will use different payment methods only. (Hotel XYZ, who is our customer, will only want to use Paypal and hotel ABC will only want to show the Master Card and Visa options).

In this kind of scenario, the normal way of doing things would be to have the different payment methods as plugins. And install only the needed plugins in a customer environment.

My question is, how to achieve this in a web application? From my understanding, the folder structure for a Java web application is as shown here. But if we have pluggable payment methods, the plugins themselves should be able to register the user interface components rather than having them in the main application. (For example let us say there is master_card.jsp file which handles the master card payments and visa.jsp etc..). With the above linked kind of folder structure, it seems to me that we would have to put in those jsp files in the webapp even though some customers might not need it.

Can someone please let me know whether

  • if my above observation is correct
  • how to have above kind of plugin structure with Java/Java EE?
  • are there any frameworks in Java that supports above kind of thing?
2
  • Who cares about a jsp more or less is in the directory? Just hide it as payment options on the page, that should do it. And if the user still tries to access it directly somehow, just block it with "Sorry, this payment method is not available". Isn't that enough?
    – dagnelies
    Oct 30, 2014 at 17:09
  • @arnaud Things will not be modular if I do it that way. The whole product will be one single unit. If I have the above mentioned separation, I will be able to re-use the modules without having to pick the corresponding jsp files from the jsp folder.
    – Can't Tell
    Oct 31, 2014 at 7:46

3 Answers 3

3
+100

if my above observation is correct

It depends. You may as well include everything in distribution and only configure each installation to use what it needs. Possible reasons for going with plugins are:

  1. You charge your plugins separately and don't want to give away features for free
  2. Your plugins are "heavy" in some way, e.g. there are lots of them or they have a significant size.

If those reasons do not apply to your case, you may think of a simpler solution.


how to have above kind of plugin structure with Java/Java EE?

If you're OK with rolling your own simplest solution, here is the general scheme:

  1. In app's configuration (which can be *.properties file or a record in DB, whichever works better for your users, because they should be able to change it), add a property which contains a path to plugins directory
  2. Define and expose plugin API - a set of interfaces which a plugin must implement to allow application to invoke this plugin
  3. Write custom ClassLoader which uses the property from #1 and maybe checks if each plugin properly implements your API
  4. Load your plugins' classes and resources using this class loader
  5. Invoke plugins' functions via interfaces of plugin API or, if plugin consists of resources only, include those as needed

are there any frameworks in Java that supports above kind of thing?

Yes. Googling for "java plugin framework" reveals some.


Other questions on the topic:


Update:

To load JSP files (or any files), use classloader as described above: see getResource and getResourceAsStream methods.

Update 2:

After meditating some more, I see you just need to conditionally include a JSP into another JSP. This is not "pluggable UI components" or anything like that, it's just conditional inclusion. There are no frameworks for that since it's just about 4-6 lines of code. It seems like you think it's more complex than it actually is.

I think this will do:

  • have a property in a file (or in DB) which tells which plugin should be used
  • assign a value of this property to a variable, say String plugin = ...
  • pass it to your JSP: request.setAttribute("plugin", plugin); or something similar
  • use it like <jsp:include page="${plugin}" flush="true" />

Could be wrong in syntax, but the point should be clear. Hope it helps.

4
  • My question was more about how to handle UI elements (jsp files) in a plug-in-able way. Can you explain how that can be achieved?
    – Can't Tell
    Oct 30, 2014 at 6:43
  • Use classloader to load anything. See getResource and getResourceAsStream methods.
    – scriptin
    Oct 30, 2014 at 20:49
  • Shouldn't this be easier than that? I thought this is a very valid scenario and that there should be existing solutions/frameworks to get this done.
    – Can't Tell
    Oct 31, 2014 at 10:38
  • It is just one property and one class - very simple solution. You can even go w/o custom classloader if you just include all your plugins in your app - then just include the one you need based on property value (or some "settings" value from DB). There is no frameworks to conditionally include a JSP into another JSP - it's to simple of a task to build a framework for it.
    – scriptin
    Oct 31, 2014 at 19:57
2

Here is one possible solution. There are others, but this seems like quite a simple way of doing it to me. I assume your site will be built using an MVC architecture, and that plugins provide three kinds of content: Java classes to implement controllers, JSP views, and static resource files that must be served.

  • Deploy your application as an expanded directory structure rather than a WAR file. This means users will be able to drop plugins as JAR files in the WEB-INF/lib directory. The server will automatically add any JAR file deployed in this directory to the classpath.
  • Use the Spring MVC framework, and enable its options to scan the classpath for components.
  • Each plugin can have one or more classes with the Spring annotation @Component, which will cause Spring to automatically create an instances of them. They may use @PostConstruct on a method to cause that method to execute at startup, which can be used for any initialisation you require.
  • Integration with the rest of the site can be achieved by exporting services as objects of known type and using @Autowire annotations on fields of that type to cause Spring to provide references to them.
  • Use the technique described at http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.VE2HPfl_vTo to configure a resource handler that maps a directory name on the server to a directory in the classpath and store your static resources in your jar file at that location
  • Precompile your JSP files to Java classes and include them in your jar file (instructions here: http://docs.oracle.com/cd/E19146-01/821-0790/abxcc/index.html)

You should then be able to bundle up features of your web site into JAR files that can be deployed simply by copying the JAR file into the WEB-INF/lib directory of your web app.

1

Whether you can use the file structure to configure enabled or not depends on how you deploy your web application.

Will the web app be deployed on the customers server? Then you can use the file structure. Will you deploy the web app on your own server? Then you won't be able to use file structure.

In any case it's probably less complicated to include all views (e.g. JSP or JSF pages) and then have a configuration table in your database for each customer that tells you which plugins are enabled. Then in your view (JSP or JSF) you use conditional rendering based on those config values.

In other words in JavaEE you dynamically generate html, so you for each payment method you can check in your database whether it's enabled and then only render the enabled ones to your final html output.

Update: One way to have different builds where you include/exclude the code might be to use maven and set up different profiles for the different payment options. This solution would only work if you deploy your webapp on your customers servers. I still think that the cleanest solution would be to use configuration.

3
  • Thanks for the answer Simon. But I was more looking for a solution where I can package a given payment gateway separately and include/exclude them if the user doesn't use it. That way the whole plugin (that is UI/Logic etc..) will be either deployed or not deployed. Do you know if there is any framework that supports that kind of behviour?
    – Can't Tell
    Oct 24, 2014 at 10:21
  • @Can'tTell OSGI? Oct 25, 2014 at 23:46
  • @BoristheSpider OSGi adds some other features/complexities that I would like to avoid. Isn't there a framework that can do this?
    – Can't Tell
    Oct 26, 2014 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.