We load our translations from our database. To retrieve the bundles we have a custom java.util.ResourceBundle.Control.
To translate our e4 RCP application, I already created a TranslationService, which I add to the root context using an addon. That was no problem (only that I had to copy 95% of BundleTranslationProvider because I did not see any other way).
Now I want to use the new Message Extension (coming with Eclipse Luna) to translate the rest. As far as I can see from the sources of the default MessageFactoryServiceImpl, there does not seem to be an easy way to inject my ResourceBundle.Control there either.
In the linked blog series, the use case of getting the resource bundles from a database is described, but solved by using class based resource bundles. This is no option, because I can't implement a class for every resource bundle and every locale. The reason for loading the resource bundles from the database is to be able to deploy translations into new languages without redeploying the application.
Is the only way to achive this by creating my own IMessageFactoryService by copying 99% of the default MessageFactoryServiceImpl, just to pass our Control into the calls to ResourceBundleHelper?
After some investigation on this, I found a way that you are able to support your use case without modifying or copying code a lot.
You need to exchange the BundleLocalization to load the ResourceBundle your way. In your case by using your custom ResourceBundle.Control. By doing this you override that the platform is looking for the ResourceBundle specified by the MANIFEST.
At the moment you will also have to implement a custom TranslationService that uses your BundleLocalization. The existing BundleTranslationProvider does not take the BundleLocalization out of the context. And you will need to copy a lot of code there, because getBundle() is private. I will discuss possible modifications with the developers.
You can find an example here: https://github.com/fipro78/e4classbasedtranslation
Hope that helps you to solve your specific requirement.
AFAIK ResourceBundle.Control is used to load ResourceBundles. In the new Message Extension we use a custom ResourceBundle.Control to enable the loading of ResourceBundles in the OSGi context, and it is configurable via annotations.
AFAICS exchanging the ResourceBundle.Control will break any other use case supported by the new Message Extension.
The question is, why do you use a custom ResourceBundle.Control instead of creating a class based ResourceBundle? I haven't tried it yet, but maybe it is possible to create only the base ResourceBundle (without Locale information) and determine the Locale in another way than using getLocale().
But without knowing what you are doing in your custom ResourceBundle.Control, I don't know what to answer and what to suggest. Of course we could open the API for that, but as I said before, then every other plugin that makes use of the default implementation will fail.
Maybe you can give some hints on what you are doing exactly and I can show you a way to achieve your goal in another way.
Related
I'm trying to add multiple language support to the application. Is it possible to add languages at runtime, by creating new property file at runtime, pulling all the english text and calling google translator api to create the equivalent values and using native2ascii converter to change the values and put it in the property file?
Any better approach available to add languages at runtime??
Thanks
You can do that with a custom ResourceBundle implementation wherein you in turn provide a custom ResourceBundle.Control wherein you manage the loading and providing the values yourself. You can even provide them from the DB.
Then, to use it, just specify the FQN of the custom ResourceBundle instead in the <resource-bundle><base-name> or <f:loadBundle baseName>.
See also:
internationalization in JSF with ResourceBundle entries which are loaded from database
There's a few problems with java's i18n support. First, ResourceBundle.getBundle() can only look into two places for language support:
Properties files in the classpath
Class on the classpath
In either case, if you wanted to dynamically provide different languages on the fly (as they are requested), you'd most likely either have to:
Create a custom classloader so that loadClass and getResource could create these on the fly.
Use aspectJ to intercept the getBundle() method call and put some before advice on it to do what you want.
In contrast, spring's MessageSource framework is much more extensible, as MessageSource is an interface, and you can supply your own implementations and register them with the spring context, or nest them in other message sources, etc....
I've searched on internet and here on SO, but couldn't wrap my mind around the various options.
What I need is a way to be able to introduce customer specific customization in any point of my app, in an "external" way, external as in "add drop-in jar and get the customized behavior".
I know that I should implement some sort of plugin system, but I really don't know where to start.
I've read some comment about spring, osgi, etc, can't figure out what is the best approach.
Currently, I have a really simple structure like this:
com.mycompany.module.client.jar // client side applet
com.mycompany.module.server.jar // server side services
I need a way of doing something like:
1) extend com.mycompany.module.client.MyClass as com.mycompany.module.client.MyCustomerClass
2) jar it separately from the "standard" jars: com.mycompany.customer.client.jar
3) drop in the jar
4) start the application, and have MyCustomerClass used everywhere the original MyClass was used.
Also, since the existing application is pretty big and based on a custom third-party framework, I can't introduce devastating changes.
Which is the best way of doing this?
Also, I need the solution to be doable with java 1.5, since the above mentioned third-party framework requires it.
Spring 3.1 is probably the easiest way to go about implementing this, as their dependency injection framework provides exactly what you need. With Spring 3.1's introduction of Bean Profiles, separating concerns can be even easier.
But integrating Spring into an existing project can be challenging, as there is some core architecture that must be created. If you are looking for a quick and non-invasive solution, using Spring containers programmatically may be an ideal approach.
Once you've initialized your Spring container in your startup code, you can explicitly access beans of a given interface by simply querying the container. Placing a single jar file with the necessary configuration classes on the classpath will essentially automatically include them.
Personalization depends on the application design strongly. You can search for a pluggable application on the Internet and read a good article (for an example: http://solitarygeek.com/java/a-simple-pluggable-java-application). In the pluggable application, you can add or remove a feature that a user decides. A way for the pluggable application is using the Interface for de-coupling of API layer and its implementation.
There is a good article in here
User personalisation is something which needs to be in the design. What you can change as an after thought if the main body of code cannot be changed, is likely to be very limited.
You need to start be identifying what can be changed on a per user basis. As it appears this cannot be changed, this is your main limiting factor. From this list determine what would be useful to change and implement this.
It seems like everybody has had an unpleasant brush with the Java Service Provider, that thing you can do with a file named like META-INF/services/com.example.Interface, but that nobody uses except for trying to load the right XML parser. I'm trying to work with a library that uses the Service Provider API, and trick it so that I can provide some runtime-extended classes (using cglib) that don't actually implement the interface but can be made to do so easily.
Basically, I think the steps I need to perform are:
Create a custom class loader that will respond to getResources(...) and return an "extra" URL
Also have that class loader hook getResourceAsStream(...) to return a list of the classes I am going to manipulate with cglib, when asked for the "extra" resource
Finally, have that class loader load those classes when requested
But here's where I get lost. For example, when the library tries to determine what implementers are out there, it calls getResources(...) which returns a bunch of URLs. But getResourceAsStream(...) doesn't take URLs, it takes "names". Names which seem to be classpath-relative, and therefore the same everywhere. So META-INF/services/com.example.Interface in has the same "name" as META-INF/services/com.example.Interface in their JAR, right? Except somehow this works with those blasted XML parsers...
Of course, all of this assumes they were smart/kind enough to call ClassLoader.getSystemClassLoader() rather than using ClassLoader.getSystemResources(...), ClassLoader.getSystemResourceAsStream(...), etc., as in the latter case there's no way to hook the ClassLoader and provide the faked file.
I guess in that case I could use BCEL to manipulate the class files when my code is being packaged by Maven, rather than waiting until runtime to do it with cglib?
The idea I described was along the right track. The mistake I made was in thinking that using ClassLoader.getResourceAsStream(..) to access the contents of the URLs. Instead, you should just URL.openStream().
Had I found it before posting, java.util.ServiceLoader (#since 1.6) provides some insight into how to do things correctly.
I'd like to implement a dynamic plugin feature in a Java application. Ideally:
The application would define an interface Plugin with a method like getCapabilities().
A plugin would be a JAR pluginX.jar containing a class PluginXImpl implementing Plugin (and maybe some others).
The user would put pluginX.jar in a special directory or set a configuration parameter pointing to it. The user should not necessarily have to include pluginX.jar in their classpath.
The application would find PluginXImpl (maybe via the JAR manifest, maybe by reflection) and add it to a registry.
The client could get an instance of PluginXImpl, e.g., by invoking a method like getPluginWithCapabilities("X"). The user should not necessarily have to know the name of the plugin.
I've got a sense I should be able to do this with peaberry, but I can't make any sense of the documentation. I've invested some time in learning Guice, so my preferred answer would not be "use Spring Dynamic Modules."
Can anybody give me a simple idea of how to go about doing this using Guice/peaberry, OSGi, or just plain Java?
This is actually quite easy using plain Java means:
Since you don't want the user to configure the classpath before starting the application, I would first create a URLClassLoader with an array of URLs to the files in your plugin directory. Use File.listFiles to find all plugin jars and then File.toURI().toURL() to get a URL to each file. You should pass the system classloader (ClassLoader.getSystemClassLoader()) as a parent to your URLClassLoader.
If the plugin jars contain a configuration file in META-INF/services as described in the API documentation for java.util.ServiceLoader, you can now use ServiceLoader.load(Plugin.class, myUrlClassLoader) to obatin a service loader for your Plugin interface and call iterator() on it to get instances of all configured Plugin implementations.
You still have to provide your own wrapper around this to filter plugin capabilites, but that shouldn't be too much trouble, I suppose.
OSGI would be fine if you want to replace the plugins during runtime i.g. for bugfixes in a 24/7 environment. I played a while with OSGI but it took too much time, because it wasn't a requirement, and you need a plan b if you remove a bundle.
My humble solution then was, providing a properties files with the class names of plugin descriptor classes and let the server call them to register (including quering their capabilities).
This is obvious suboptimal but I can't wait to read the accepted answer.
Any chance you can leverage the Service Provider Interface?
The best way to implement plug-ins with Guice is with Multibindings. The linked page goes into detail on how to use multibindings to host plugins.
Apologize if you know this, but check out the forName method of Class. It is used at least in JDBC to dynamically load the DBMS-specific driver classes runtime by class name.
Then I guess it would not be difficult to enumerate all class/jar files in a directory, load each of them, and define an interface for a static method getCapabilities() (or any name you choose) that returns their capabilities/description in whatever terms and format that makes sense for your system.
I am working on a big (lots of classes) java project and I have it's source code but most of the classes are dynamically created or downloaded via ClassLoaders.
Anyways, I'd like to be able to "override" the java.net.URL class so I could trace down the calls to open a url. I can not use a sniffer because the content is SSL encrypted.
I tried to extend the java.net.URL but it didn't work because its a final class.
I also opened the source to java.net.URL and modified it and could successfully build it, now how can I make the default java classloader to load my modified copy of java.net.URL instead of the original one?
Any suggestions are welcome! Thanks in advance.
An option would be to use AspectJ and weave your extension code into the URL class instead of extending it. That way you don't have to modify any of the original sources and you can still "extend" a final class. The downside of course is, that you add another dependency to your project.
If you have not yet worked with AOP, you may find a short introduction to AOP at my blog: http://whatiscomingtomyhead.wordpress.com/2010/02/06/aspect-oriented-programming-an-introduction/
You can't extent URL, as you have discovered. You may be able to get the JVM to load your custom version of the class, but IMHO that sounds like a nightmare.
Thankfully you can implement a custom URLStreamHandlerFactory and register it by URL.setURLStreamHandlerFactory(). This will allow you to wrap and monitor when URLs open streams, just as you desire.
EDIT
But you won't be able to use this approach if your app already registers one; URLStreamHandlerFactories are 1/app. And many types of app containers use one (e.g. Tomcat), so if you're using one of those you're SOL.
Have you considered using AspectJ? You could set a pointcut on URL constructors and thus be notified of any new URL instance creation.
If you have modified classes in the standard API, you have to prepend the boot class path with your classes (jars or directories), otherwise the VM internal classes will have priority over any classes added to the normal class path. With Sun's VM, you can use the argument -Xbootclasspath/p: to add new classes with a higher priority than the internal implementations.
Another option, without modifying the URL implementation may be to implement a ProxySelector. Opening a URLConnection would cause the URL implementation to query ProxySelector.select(URI uri) for a suitable proxy for the given address. This will even work if you actually are using proxies. You can obtain the system ProxySelector with ProxySelector.getDefault() before you register your own implementation and delegate the select calls to the original implementation after you've tracked the URI, which is passed to the select method.