Parametric file inclusion in struts.xml configurations, based on properties - spring

I have a web application (built on Spring, Struts 2) and I am trying to dynamically include a struts configuration file inside the main struts.xml configuration, based on a property.
Having defined, in the property file:
key=foo
I try to use it inside struts.xml:
<struts>
...
<include file="/config/struts/struts-${key}.xml" />
</struts>
To include the "struts-foo.xml" file (or another file, depending on the value).
The property file is loaded at startup by Spring, and I am able to use it inside Spring's xml files to parametrize bean definition.

You could leverage the Struts2 plugin framework.
You basically create a jar based project where you include all of a particular client's action mappings, support classes, etc. If you're also deploying into a Servlet 3.0 or higher container, you can also elect to include the UI artifacts inside the jar's META-INF\resources directory too for clean packaging.
Now, the contents you typically place inside the struts.xml for action mappings, you simply place inside struts-plugin.xml and place this xml file in the root of the jar file.
When the Struts2 framework starts, the jar files will be scanned, the struts-plugin.xml files will be picked up and automatically included in your application.
I use the same setup in conjunction with my maven build process so that if a client's deployment isn't suppose to include a specific feature or if a standard feature is to be customized, I can customize the action mappings from the stock ones.
In our case, the stock app is a struts-plugin based jar that gets loaded before any other jars and then subsequent feature jars are loaded to extend or override functionality. The actual WAR project has little inside it and is mainly an artifact used to deploy combinations of other project artifacts.

As you know you can change the struts.xml config file name, as below:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>config</param-name>
<param-value>struts-config.xml</param-value>
</init-param>
</filter>
You can use this feature to change struts.xml dynamicly.
You need to extend the StrutsPrepareAndExecuteFilter and load your dynamic config here. Replace your new fildter with struts in web.xml.
public class MyStrutsPrepareAndExecuteFilter extends StrutsPrepareAndExecuteFilter{
#Override
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
//load your config here
}
}
Please have a look at StrutsPrepareAndExecuteFilter source code. you can see how the config is loaded and you can how you can change it.
If you want to only dynamical change your application messages you can do it more easily by just calling LocalizedTextUtil.addDefaultResourceBundle ("messages/customize") in MyStrutsPrepareAndExecuteFilter

Related

Deploying BEAN in OSGi plugin

I am currently deploying my custom controls as OSGi plugins and I wanted to do the same thing with my beans. I have tried putting them into the OSGi plugin and it works fine but the only problem I have is the faces-config.
It seems it has to be called faces-config in the OSGi plugin to work but that means i can't use beans in the NSF anymore because it seems to ignore the local faces-config.
Is there a way to change the name of the faces-config in the OSGi plugin?
Something like FEATURE-faces-config.xml?
In the class in your plugin that extends AbstractXspLibrary, you can override "getFacesConfigFiles", which should return an array of strings representing paths within the plugin to additional files of any name to load as faces-config additions. For example:
#Override
public String[] getFacesConfigFiles() {
return new String[] {
"com/example/config/beans.xml"
};
}
Then you can put the config file in that path within your Java source folder (or another folder that is included in build.properties) and it will be loaded in addition to your app's normal faces-config, beans and all.
The NSFs are running as separate, distinct Java applications. The OSGi plugin is running in the OSGi layer, above all those distinct Java applications, as a single code base. Consequently, the faces-config is only at that level.
It's possible to load them dynamically, by using an ImplicitObjectFactory, loaded from an XspContributor. That's what is done in OpenNTF Domino API for e.g. userScope (which is a bean stored in applicationScope of an NSF). See org.openntf.domino.xsp.helpers.OpenntfDominoImplicitObjectFactory, which is referenced in OpenntfDominoXspContributor, loaded via the extension point of type "com.ibm.xsp.library.Contributor".
A few caveats:
You have no control over what happens if you try to register your bean with a name the developer also uses for a different variable in that scope.
Unless you add code to check if the library is enabled, as we do, you'll be adding the bean to every database on the server.
You still need to add the library to the NSF. Unless you also provide a component that those databases will all use, there's no way you can programmatically add it, as far as I know.
It might be easier to skip the bean approach and just add an instance of the Java class in beforePageLoad, page controller class, or however you're managing the backing to the relevant XPage (if viewScope) or application (if sessionScope / applicationScope).

Jetty spring profile programmatically

I'm looking for a way to set spring profile in jetty programmatically so that the application that the war file on the server used the given profile, this is my code:
final WebAppContext context = new WebAppContext();
context.setLogUrlOnStart(true);
context.setWar("target/deployables/myapp-rest/myapp-rest.war");
context.setContextPath("/" + TEST_APP_CONTEXT);
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
I tried a couple of things but none of them seem to work... I need to pass -Dspring.profiles.active=myProfile
This is tested with Jetty 9.3 but webdefault.xml seem to also be available for lower versions (it's placement might be different though).
Go to $JETTY_HOME/etc and open webdefault.xml. Search for context-param in the file. Add this code somewhere below:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>prod</param-value>
</context-param>
This will work if your web.xml (in the your-app.war file) doesn't contain this context-param.
Otherwise you could also use override-web.xml (docs) but you would need to configure it in jetty-web.xml and jetty-web.xml must be bundled inside the war... So YMMV, but I didn't want to change my war and webdefault.xml is an easier solution for me.

Accessing properties file from another module context

I use maven. My web application contains two modules and each has it's own spring context. First is packed to jar, the second one to war. The second one uses first module's jar and calls it's methods.
I need to add property file, which will be used by first module (via spring context). The main issue is that I should be able to access/edit this property file after war deployment.
How can I provide such a property file, that will be used in first jar module and can be changed after war module deployment?
Thanks.
Sorry, don't see the problem, you need to describe that better. From what I understood this is the way to go:
place a.properties in src/main/resources in the JAR module
use a PropertyPlaceholderConfigurer to make the properties available in the Spring context
it'll be packed in root of the JAR
the JAR ends up in WEB-INF/lib of the WAR which again is "root of the classpath" so to speak
Update, 2013-06-09
(question was updated based on comments to initial answer above)
Essentially what you seem to be looking for (still not quite sure) is how to load properties from a properties file that is not packaged with your WAR/JAR.
In this case you can skip all of the above steps except 2.
Use a PropertyPlaceholderConfigurer and specify the location of the file as classpath*:a.properties (see below)
Place a.properties anywhere on the classpath outside the WAR file.
Warning! Of course you can now edit the properties independently from releasing the WAR file but since Spring initializes the beans on application start and since all beans are singletons by default changes to the properties file won't become effective until you restart the app.
XML example
<bean class="....PropertyPlaceholderConfigurer">
<property name="location" value="classpath*:a.properties" />

Spring Persistence archive and entitymanager is null when accessing from web-application

I've created a jar file through spring roo (maven project - persistence archive) unit tests are running fine, the concerned files are on the following location
jarFile/META-INF/persistence.xml
jarFile/META-INF/applicationContext.xml
jarFile/META-INF/applicationContext-jpa.xml
jarFile/META-INF/database.properties
Unit tests are running fine.
Because its a maven project I added it to local repository by executing the command "mvn install" and after that I added it as a dependency to another maven based web-application.
I am running the web application using mvn jetty:run command. the concerned files in web application are.
webApp/WEB-INF/web.xml
webApp/WEB-INF/applicationContext.xml
The Problem
* Its loading the webapp/WEB-INF/applicationContext.xml but how can I verify its loading the child jarFile/META-INF/applicationContext.xml or not? actually when i try to access the service class methods from persistence archive the entityManager is NULL.
* If i try to put contextConfigLocation directive (tried various options) within web.xml, Its not even loading the webapp/WEB-INF/applicationContext.xml.
What I want
Use the service methods (which uses entitymanager) from persistence archive from within my web application.
Thanks in advance.
Found the answer by digging around a bit.
Actually I was confused with various ways/syntax to include the context file, was trying with all sort of classpath*:xxx syntax but actually the WEB-INF is not on the class path so following have to be added to web.xml to load the main webApp/WEB-INF/applicationContext.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
Then had to add the following to the webApp/WEB-INF/applicationContext.xml
<import resource="classpath*:META-INF/spring/applicationContext*.xml" />
Now the webapplication is loading the context file from jar file as well. And things are working.

Component Scan not finding #Component's in a JAR in Tomcat webapp

I just filed a bug in the Spring bugsystem ( https://jira.springsource.org/browse/SPR-8551 ), but I am still unsure if I am missing something
I tracked down a problem with <context:component-scan/> to this statement.
Given the two following classes which are in the same JAR in WEB-INF/lib of a web application (The JAR file has the directory structure):
test/TheBean.java:
package test;
#Component
public class TheBean{
}
test/BeanSearcher.java:
package test;
public class BeanSearcher{
public void init(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("test");
ctx.refresh();
TheBean b= ctx.getBean(TheBean.class);
// What is the value of b?
}
}
If I run new BeanSearcher().init() in a jUnit test case or other type of standalone application, b is getting assigned an instance of TheBean, but if I run it, say, in a JSP, ctx.getBean() is returning null.
So, am I doing something wrong or not taking something into account, is this just a bug...?
EDIT 8/8/2011: It seems to work good as I tried to simplify the problem, but still, when I try to make it work, in the initialization of OpenCms, it fails. Now I am trying to look for the differences between working versions and the one which doesn't work. (Classloader, ubication of the relevant classes in different JARs or directly in WEB-INF/classes, calls via reflection, etc.)
As I wrote in the comment, the solution is given by the answer here:
Spring Annotation-based controllers not working if it is inside jar file
When you export the jar file using the export utility in eclipse there
is a option called Add directory entries.
The obvious question is whether you have things like these in your web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/foo.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Without these, Spring won't actually load at all, let alone properly build beans…

Resources