We currently have a Maven multi-module setup of various commons modules and other standalone applications, which would depend on commons / other modules. All modules would have a default set of properties to enable/disable certain functionality, including the commons modules.
These commons properties can be overridden by properties files in one of the modules that has commons as a dependency (We have a custom setup for combining/overriding these properties which is quite intricate but results in a completely merged set of properties for the Spring environment to use)
I have been looking into Spring Cloud Config as an alternative to completely externalize our configuration from our codebase, but I can't see an easy/automatic way to combine these properties together for a module and it's dependencies.
What I have seen so far is that I could use spring.config.import= in my {application-name}.properties files to include the required properties from all of the dependencies (and their dependencies in some cases), but this would mean I would need to have multiples of these import statements in the properties file to ensure all properties from all dependencies are included in the final application.
I could also set spring.application.name to a comma separated list in the client application in order to access all of the properties I need, but again this would be a list of dependency names which would be difficult to manage. I've figured that I can use the profiles to switch between the likes of dev and prod-specific properties files for an application which is quite interesting, but my issue is more of an inheritance of properties instead of switching.
I'm not aware if this approach is covered by Spring Cloud Config, or if I've completely missed something?
Related
I am developing a library (JAR) that is meant to be used across many projects. I am using SLF4j for logging, and so I have declared the SLF4J API JAR to be a compile configuration.
When I'm developing this library locally on my machine, I'd like to run tests and see the output from all the SLF4J log statements. Or, outside of a test, it helps to add a temporary main(String[]) method to a random class and test functionality and log output as if the lib was an executable JAR. Since SLF4J's default binding is a No-Op (no output whatsoever), I have been getting by so far by adding the SLF4J Simple binding as a compile configuration dependency while I am developing & testing. Then, before I commit and publish, I simply remove the Simple binding as a dependency (since each developer who uses my lib should be able to select their own binding).
This is hacky and I know Gradle support custom configs, but I have yet to see a coherent example that could act as a guide. Ideally I'd like to define a custom dev configuration so that as a dependency I could have:
dependencies {
compile 'org.slf4j:slf4j-api:1.7.5'
dev 'org.slf4j:slf4j-simple:1.7.5' // Only used when running/testing locally
}
...but then ony the SLF4J API JAR gets added to my pom. Any ideas as to how to accomplish this? Perhaps Gradle already has such a concept built into it, or perhaps a custom configuration isn't even the right approach.
I am asking this especially, because JBoss AS 7+ has completely changed 360 degrees, enforcing the application developer to think completely in terms of JBoss Modules. That prevents earlier classpath-hell issues etc and encourages clean modular thinking etc. Also it claims a quick startup time etc.
All that is fine BUT my major concerns are thus, please confirm if you feel the same :
JBoss insists to put the jboss-deployment-structure.xml file inside WEB-INF. This would make the WAR file not portable at all since now it contains app server specific configuration files inside it. I am worried about inter-operability.
I am still nervous about the enormous amount of XML configuration needed - Create a module directory structure for each dependency you would like to add, create a module.xml for that dependency, create a jboss-deployment-structure.xml entries for non-modules or Manifest entries for libs inside WEB-INF/lib. etc etc.
That would require enough developer time and effort being spent towards being an configuration expert or hire an expert or buy the support - a significant cost in the long run for any team and company.
There is nothing about jboss-deployment-structure.xml that makes it non-portable. Other application servers will simply ignore the file if they don't use it.
You do not need to create a module if you want to use a dependency in your application. You would only do that if you want to use a common dependency among several deployments. For example a JDBC driver library.
There is no need to create a jboss-deployment-structure.xml or add manifest entries for libraries in WEB-INF/lib. The only time you would need a jboss-deployment-structure.xml is if you want to exclude server dependencies, like log4j, or add dependencies outside the scope of your deployment that are not automatically added. There are probably some other use cases, but those are the most common.
This is for Struts 1.x (I'm using 1.3.10).
I've noticed that Struts is unable to pick up resource bundles in the ApplicationResources.properties file if it is not placed somewhere in the default classpath (e.g., com.abc.SomePackage).
For instance, if I put the ApplicationResources.properties file in a custom folder /WEB-INF/strutsResources and configure the struts-config.xml thus:
<message-resources parameter="/WEB-INF/strutsResources/ApplicationResources"/>
I've read that the resources need to be on the classpath so I've also tried adding the /WEB-INF/strutsResources folder to the classpath. It still does not pick up the resource keys.
I've double-checked that the strutsResources folder is actually deployed to the server (I'm using Glassfish v3), so the file is there, it's just not being parsed.
P.S.
If you're wondering why I'm trying to do this, I just wanted to organize my code a little better ("better," IMO). Since the ApplicationResources.properties file is not really a class, I wanted to place it in a resources folder by itself.
I've checked that placing the ApplicationResources file in a package in the src directory works just fine.
Ultimately, the answer is yes. You can play some interesting games by configuring a custom className and/or factory and get messages however you want (including from a database) and so on. This allows you to customize whatever you want*.
I agree the resources aren't a class, but putting them on the classpath is a common practice, and allows resources to be loaded as a resource, e.g., from inside a jar. I'm sympathetic, but I'd leave it as-is.
*Like reversing all the text; a fun prank to play on your co-workers and QA department.
Its best leave it on the classpath.
It's stadard practise to include properties files on the classpath, especially if you're planning on packaging it up in your WAR/EAR. You're keeping it under WEB-INF so you gain no benefit from moving it off the classpath, and you'll just confuse other developers who have to work on the project and you've had to put a hack in to make this work.
If you want to keep your files external to your deployable WAR/EAR then that's a valid reason for not using the classpath. Typically this will require some configuration as part of your deployment to specify where the file is to reside.
For example specify the location using
a JVM argument (e.g. -Dprops.file=/config/myapp.properites)
lookup from a JNDI resource
use a PropertiesFactoryBean if you're using the Spring framework (I
use Spring's ApplicationContext with Struts 1 MVC)
read properties from a database writing your own
ApplicationPropertiesDAO class that initialises itself durnig your
applications bootstrap process (e.g. Spring application contact,
Servlet in web.xml, Listener in web.xml, etc)
I have following Maven projects set up:
PM-Core
PM-Web (with a dependency to PM-Core)
Now, this project is used for several clients but for each client there are some small differences: mostly differences in configuration files but some clients also require additional java files (which may not be installed for the other clients).
I've been considering several alternatives on how to support this with maven but am still looking for the perfect solution.
The best solution I can think of is to create a separate maven project for each client (e.g. PM-CLIENT1, ...) which contains only the client specific configuration files and additional java files or jsp's, ... . Next step would be to consider the PM-Web project and the client project as one web project, meaning: have them combined (packaged) into 1 war file with files from the client project having precedence over files from the PM-Web project.
More concrete: running mvn package on PM-Client1 would take everything from PM-Web, add/replace the files from PM-Client1 and then package this into a single war.
So the question is: how to achieve this with maven?
Yes, this can be done using Overlays. The sample on the webpage is exactly what you are talking about.
For the project structure, you could have something like this:
.
|-- PM-Core
|-- PM-WebCommon (of type war, depends on core)
|-- PM-Client1 (of type war, depends on webcommon)
`-- PM-Client2 (of type war, depends on webcommon)
And use overlay in PM-Client1 and PM-Client2 to "merge" them with PM-WebCommon and package wars for each client.
UPDATE I won't cover all the details but I think that declaring the war dependency with a scope of type runtime is required when using overlay, this is how overlay do work (actually, the whole overlay thing is a kind of hack). Now, to solve your eclipse issue, one solution would be to create a JAR containing the classes of the PM-WebCommon project. To do so, use the attachClasses optional parameter and set it to true. This will tell maven to create a PM-WebCommon-<version>-classes.jar that you'll then be able to declare as dependency in PM-Client1 (with a provided scope). For the details, have a look at MWAR-73 and MWAR-131. This is also discussed in the FAQ of the war plugin. Note that this is not a recommended practice, the right way would be to move the classes to a separate module (and this is the other solution I wanted to mention).
UPDATE (201001018): I've tried the attachClasses parameter and it works with version 2.1-beta-1 of the plugin.
You could use profiles see http://maven.apache.org/guides/mini/guide-building-for-different-environments.html and use classifiers to distinguish between the artifacts from the different builds for the same version.
In this setup, you could create additional optional modules for each of your clients specific customisations under the parent project i.e.
+ PM
++ PM-Core
++ PM-Web
++ PM-Client1
++ PM-Client2
Or you could look at using use the maven assembly plugin
Compare also the answers for question different WAR files, shared resources .
I'm happily using the Maven bundle-plugin to create OSGi manifest headers for my modules. However, when there are configuration files that pull in classes which aren't referenced directly in the code, the plugin can't tell which packages it's going to need.
One example is a bundle with domain models that constitute a Persistence Unit for JPA. The driver class is part of the PU configuration and either set in an XML file or at runtime when the EntityManager is instantiated. I have to manually add an Import-Package header for the driver class that I want to load, or I get CNF errors.
Another example is a Struts war, where the web.xml pulls in the Struts dispatcher that's otherwise not found anywhere in the code and has to be manually added to the headers.
How can I avoid this?
I tried adding the required packages as dependencies with a provided scope, but that didn't help.
In the plug-in section of the bnd configuration you can specify plug-ins to analyze these files and contribute to the import-package header. For spring it looks like this:
<_plugin>aQute.lib.spring.SpringComponent</_plugin>
I am not sure, what descriptors are supported on top of spring. Just take a look at the source (it's in the Apache Felix SVN) and see for yourself. In the worst case you have to write your own plug-in, but at least it is possible! Also peter kriens site about the bnd explains the usage and some internals.
Other then that I am not aware of any simple solution.