Replace default resourceBundle and resourceControl implementations in JSP web application - java

in an existing Web Application (JSP, Struts), localizations are managed through JSTL tags fmt:setbundle, fmt:message and .properties files.
I'd like to get rid of the .properties files and use an alternative datasource for localizations.
For my goal I've created custom ResourceBundle and ResourceControl implementations (details on where data is picked, xml, database, are out of scope), but I'm wondering how to register and use them in place of the default/factory file-based implementation, so I'm not forced to modify markup code (fmt:message...) among web application files.
I saw examples that point to replace fmtResourceKey session value but it's limited to only one bundle and it looks like an "hack".
Any good ideas?
Thanks for your help!

Ok, it seems I sorted out with subclassing/customizing java.util.ResourceBundle, which also carries implementantion of custom ResourceBundleControl and ResourceBundleControlProvider (injected through Service Provider Interface - SPI).
Similar solution is depicted in this page from Oracle:
https://docs.oracle.com/javase/tutorial/i18n/serviceproviders/resourcebundlecontrolprovider.html
but was lacking an important hint: "put your JAR inside VM" since ResourceBundle.GetBundle method internally uses Serviceloader.LoadInstalled which searches for custom provider installed inside Java VM, as stated in LoadInstalled documentation:
This method is intended for use when only installed providers are
desired. The resulting servicewill only find and load providers that
have been installed into the current Java virtual machine; providers
on the application's class path will be ignored.
Thanks!

Related

Why we need ibm-web-bnd.xml and ibm-web-ext.xml?

Why we need ibm-web-bnd.xml and ibm-web-ext.xml in application that we need to run in WAS server. I found few things like it contain virtual host , context root etc. But i want to know why it is required for WAS server.
First of all they are not required, they can be generated during the installation for example via web admin console. However they can provide some predefined settings or change the default behavior.
The ibm-web-bnd.xml file provided binding between resource references used in web module and actual components, like datasouces, queues, etc. However since Java EE 6, you can actually use the lookup attribute from the #Resource annotation to provide them in the code. See some more info about bindings here - Application bindings
The ibm-web-ext.xml file allows you to configure some settings for web module e.g. context-root, directory browsing, etc and JSP engine parameters.
The easiest way to create them is to use WebSphere Developer Tools for Eclipse (free plugin), which have graphical/text editor for them.

Custom User Store Manager not recognized (WSOIS 5.3)

I've written a custom User Store Manager to interface WSO2 to a database managed by ASP.Net's Simple Membership Provider. My main issue is that SMP uses PBKDF2 for password hashing and the standard JDBC User Store doesn't seem to support that.
I basically used https://docs.wso2.com/display/IS530/Writing+a+Custom+User+Store+Manager as a template, as the example implements a different password hashing algo, which is exactly my use case.
You can find my POC implementation here: github project wso2_custom_userstore I built a jar, put it into the dropins directory and restarted the server. The server complained about lack of bundle headers, but that's it. When adding a new user store there's only the standard stores, nothing more. I then configured a JDBC user store and changed the class to the one I wrote. The only effect I saw was that my previously configured User Store had vanished. I tried putting the .jar into the libs directory instead, didn't change anything.
As that didn't seem to work and the server complained about missing bundle headers I built a OSGI bundle that exported my CustomUserStoreManager Package (the source can be found on github as well, I'm not allowed to add more than two URLs) - now the bundle gets loaded and activated but nothing more. Still my class is nowhere to be seen. I don't see it as an available class in the User Store add dialog and I don't see it as an available class in the log config. No hint of it anywhere, not in the log files, not in the server's startup output. Nada.
Am I doing something wrong?
I have to add that I by no means am a Java developer nor a developer at all. I'm evaluating WSO2 for a customer and this is supposed to be a PoC. Once it works and I know that using PBKDF2 hashes are possible someone more competent is going to build a production version.
Thanks in advance,
SunTsu
WSO2 IS 5.3.0 is based on org.wso2.carbon.user.core 4.4.11 [1] and you are using 4.2.0. Documentation should be updated in this case. You can find a sample code [2] which is written for WSO2 IS 5.1.0 and article in [3].

Link to properties file outside webservice

I have a webservice that uses Java, REST, Jersey and runs on Tomcat8. The webservice requires access to a database. Depending on where we are in the process the we may be using a testdatabase, production database or something else. Ideally we would like to be able to set which database to use without requiring a code change and recompile.
The approach we have tried is to have a properties file defining the database parameters and use an environment variable to point to the file. This has proved troublesome, first we've had a hard time defining system properties on the Tomcat server that we can read from the application, also it seems like all the files will have to be defined on the classpath, i.e already configured ahead of time and part of the codebase.
This seems like fairly common scenario, so I'm sure there is a recommended way to handle situations like this?
Zack Macomber has a point here. Don't enable your app/service to look up its settings dynamically.
Make your build process dynamic instead.
Maven, Gradle and friends all provide simple ways to modify output depending on build parameters and or tasks/profiles.
In your code always link to the same file (name). The actual file will then be included based on your task and/or build environment. Test config for tests. Production config for production.
In many cases a complete recompilation is not necessary and will therefore be skipped (this depends on your tool, of course).
No code changes at all. Moreover the code will be dumb as hell as it does not need to know anything about context.
Especially when working on something with multiple people this approach provides the most stable long-term-solution. Customizable for those who need some special, local config and most important transparent for all who don't need or don't want to know about runtime environment requirements!
We have a similar case. We have created a second web service on the same endpoint (/admin) which we call to set a few configuration parameters. We also have a DB for persisting the configuration once set. To make life easier, we also created a simple UI to set these values. The user configures the values in the UI, the UI calls the /admin web service, and the /admin service sets the configuration in memory (as properties) as well as in the DB. The main web service uses the properties as dynamic configuration.
Note: we use JWT based authorization to prevent unauthorized access to /admin. But depending upon your need you can keep it unsecure, use basic HTTP auth or go with something more detailed.
Not sure if in this particular case it is wise, but it is possible indeed to create a .properties file anywhere on the filesystem - and link it into your application by means of a Resources element.
https://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
The Resources element represents all the resources available to the web application. This includes classes, JAR files, HTML, JSPs and any other files that contribute to the web application. Implementations are provided to use directories, JAR files and WARs as the source of these resources and the resources implementation may be extended to provide support for files stored in other forms such as in a database or a versioned repository.
You would need a PreResources element here, linking to a folder, the contents of which will be made available to the application at /WEB-INF/classes.
<Context antiResourceLocking="false" privileged="true" docBase="${catalina.home}/webapps/myapp">
<Resources className="org.apache.catalina.webresources.StandardRoot">
<!-- external res folder (contains settings.properties) -->
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
base="/home/whatever/path/config/"
webAppMount="/WEB-INF/classes" />
</Resources>
</Context>
Your application now 'sees' the files in /home/whatever/path/config/ as if they were located at /WEB-INF/classes.
Typically, the Resources element is put inside a Context element. The Context element must be put in a file located at:
$CATALINA_BASE/conf/[enginename]/[hostname]/ROOT.xml
See https://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context

Serve files from a folder different of context directory in a servlet container

I got a situation that I must serve files from different folders then the one of the context my web app is running. As an example, suppose my web app is running in a servlet context on "/opt/tomcat/webapps/ROOT/" and I must serve files existent in "/opt/my_other_folder/". These folders can be changed in runtime by the client, so I can't simply add a new context pointing to these directories. I would like a solution that I wouldn't have to rewrite a web server only for that. Also, the product I work on is generic, so I can't have a solution specific to some servlet container.
Thanks!
If you're only serving files, I would consider fronting your servlet container with something like Apache HTTP Server, where you could simply use its various directives to provide a "virtual directory" pointing to an easily configured location.
Otherwise, you could write and configure a standard Java servlet that would do essentially the same thing - storing the actual path in a Java properties file that would be read by the servlet. But while this isn't a lot of work, it would be significantly more work that the above Apache HTTP Server solution. This would be very similar to several of the answers posted at Servlet for serving static content . Specifically, you could either use or extend upon Apache Tomcat's DefaultServlet. (There are some Tomcat-specific classes used in here, but they could be easily replaced with generic equivalents.) http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and.html looks even closer to what you'd be looking for, and it is completely generic - while still having some additional, significant features.
Either of these options would be very generic, and not specific to any particular servlet container.

In Java, how to reload dynamically resources bundles in a web application?

We are using fmt:setBundle to load a resource bundle from a database (we extended the ResourceBundle class to do that).
When we modify a value in database, we have to reload the web server to display the new value on the web app.
Is there any simple way to use the new value without restarting the web server ?
(We do not want to always look up the value from database but we would like to invalidate the cache, for example by calling a special 'admin' URL)
EDIT : We are using JDK 1.4, so I would prefer a solution on that version. :)
If you're using JDK 1.6 you can use the callback methods getTimeToLive() and needsReload() in ResourceBundle.Control to control if the bundle cache needs to be loaded with new values from the database.
As others have pointed out in the comments, you might want to look into Spring - particularly the ReloadableResourceBundleMessageSource.
First you can create a class which extends from ReloadableResourceBundleMessageSource to expose its inner class protected method called getProperties. This method return a concurrent map from PropertiesHolder object. Second you should configure a bean of that extended class in you web configuration class. Now you able to use messageSource in your service or business layer. Here is the reference link Configure reloadable message source bundle

Categories