Adding aspects on services across OSGi bundles - java

I have an OSGi bundle (that is not owned by me - so I cannot change it!) that exposes (exports) a service EchoService, and I want to attach an aspect to methods of this service (so as to perform some pre/post processing around it). These are deployed on the Apache Felix container.
I've written my own OSGi bundle (that obviously imports the EchoService), and attaches Spring aspects to it using standard Spring AOP. However, looks like the aspects are not attached and my interceptor is not being invoked.
I suspect that this is because I'm trying to intercept a service that does not belong to my bundle (which seems reasonable). Is that correct? How can I overcome this?
Here's what my interceptor/aspect looks like:
#Before("serviceOperation()")
public void before(JoinPoint jp) {
logger.debug("Entering method: " + jp.toShortString());
}
#AfterReturning("serviceOperation()")
public void after(JoinPoint jp) {
logger.debug("Exiting method: " + jp.toShortString());
}

I'm not an AOP nor a Spring expert, but maybe I could give you some ideas. As far as I see Spring use standard J2SE dynamic proxies for AOP proxies. Hence your clients should use the proxy instead of the original EchoService object. This is also true when you're using CGLIB proxies because "the proxies are created by sub-classing the actual class".
If your client bundles asking for an EchoService you have to pass them the proxy somehow. For this inside an OSGi container you should also export an EchoService (proxy) and make sure that the clients use the proxied service/bundle, not the original. You can accomplish this by setting a different version number for the (proxied) package and set this version as an import requirement in your client bundles. (I suppose you can modify the clients of EchoService.) For services you can set a property when you're registering it and modify the clients to query only for services which have this property.
If you are not able to modify the client bundles another solution could be wrapping the original bundle as an internal jar in your bundle. You can call the wrapped bundle's activator from your activator and pass them a modified BundleContext. This BundleContext should catch the registering service calls and register the proxy object instead of the original EchoService. You can use simple delegate pattern since BundleContext, ServiceListener etc. are usually interfaces. I suppose it could work but it maybe has other challenges.

Related

Dynamically extend Spring MVC powered REST api with access to application jar only

I am in a situation where I have a nascent rest api architecture where each method has tons of ceremony (validation, db connection acquisition/release, authentication), raw request/response objects as the parameters, and hard-coded json strings as the output. I want to use spring mvc to help with at least some of these issues (auth & db stuff i'll need to hold off on). This would render a lot of the current architecture unnecessary. This is pretty easy except for one feature of the current architecture: dynamically adding api calls.
The entry point (servlet) for the architecture reads from an xml file that contains the path for a request and a corresponding class to load. The class must implement an interface that contains an 'execute' method which has the logic for the request. The servlet calls this execute method after loading the class. This allows dynamic extension of the api as follows. The app is packaged as a jar together with the associated config (xml) files and given to a client. The client includes this jar in his project, creates a class that implements the aforementioned interface, and adds a mapping from request url to that class in the included xml file. He then runs the app and gets access to both the original api and his custom api.
Example:
Client is given app.war, interface.jar and custom-mappings.xml. app.war contains the implementation of the core api (rest webservice), and interface.jar exposes the interface BaseController that has the method 'execute' (app.jar also uses this interface in its controller). Client then defines his own class as follows.
package custapi.controllers;
public class ExtendedController implements BaseController {
public void execute(HttpServletRequest request, HttpServletResponse response) {
// LOGIC
}
}
He compiles this class and adds it to app.war. Next, he updates custom-mappings.xml with the following entry.
/custcall/mycall
custapi.controllers.ExtendedController
He then deploys the app. The controller provided with the core api receives the request /custcall/mycall, looks it up in custom-mappings.xml, finds the class is custapi.controllers.ExtendedController, loads that class, and finally runs its 'execute' method. This allows the logic defined by the client to be run.
Ideal:
Current architecture is replaced with spring-mvc. That is, there is no more 'super' controller that parses requests and delegates to the appropriate class and, finally, method. Spring handles this. For the app that uses this new architecture, the client would receive the app.war and the spring mvc deps that expose controller annotations. The client would then create a new spring mvc controller (taking advantage of validation, parameter -> pojo mapping, object -> json conversion), compile it, and add the resulting class file to app.war. His controller would then become an extension to the core api exposed by the app. When the app is deployed, he would be able to make a request /custcall/mycall like before and have it execute the logic he defined. This ideal scenario allows clean code for the core api (which I and others programmed) and an extended api. (A downside to this approach is that the client is tied to spring. In an even more ideal scenario, the client would use framework-agnostic annotations which are mapped to spring annotations by the app. I'm not sure how easy this would be.)
I'm not sure how the above would be realized with a spring-aware controller without sacrificing the benefits of spring. I don't believe the client could simply define another spring-aware controller (correct me if I'm wrong on this). The only solution I can think of is to have a spring-aware controller that has a wildcard path (e.g., /cust_rest/*) which acts exactly the same as the current controller. The client would not get any advantages that spring has to offer, but the core api would be a lot cleaner. I was hoping there was a better solution, however. Ideally the client would get the benefits of spring without having access to the core api source code. Any ideas on this, or is my solution the best that can be hoped for?
Thanks.
(NOTE: For both scenarios, I am only guessing how the client actually gains access to the dependencies/interfaces and deploys. I have only had access to the core api project for one day, and so my understanding of it is not complete.)
Related: Runtime loading of Controllers for Spring MVC and dynamically mapping requests/URLs
The above question looks pretty similar to mine. Replies are sparse (second one is just off topic, I believe).
Provided you setup classpath scanning properly there's no need for interface. Your clients can just annotate classes with #Controller #RequestMapping("/foo/bar"). Even if this class is located in its own jar it will still be scanned. If this is a REST service consider using #RestController instead to avoid having to place #ResponseBody on each handler method.
Use spring security to do declarative authentication & authorization (what you're doing now is programmatic security)

Possibility to intercept OSGi service resolving

I have rather big set of services registered with registerService. For simplicity let's assume they are lookup by some property name. So pair of invocation is straightforward (I use pseudocode for property spec):
context.registerService(
IMyService.getClass().getName(), myServiceInst, {"name"="a"})
After that on client side:
context.getServiceReferences(IMyService.getClass().getName(), {"name"="a"})
For some reason I cannot register all possible combinations of name. Is it possible to intercept all OSGi queries so I could create services on the fly when they are queried?
I would like have basic solution that works on all layers of OSGi - it mean that code above and code with (for example) Declarative Service will work the same way.
Take a look at Service Hooks in the core specification. They allow you to find out who is waiting for what services. Notice that this might imply parsing the filter if you're interested in what properties they're waiting for.
I think you have a couple of options:
Option 1:
If you need only one Service object by client bundle (where the client bundle identifies the key-value pairs) consider using http://www.osgi.org/javadoc/r4v43/core/org/osgi/framework/ServiceFactory.html. I think the javadoc is pretty self explaining and you can find easily usage samples in google. In this case you have to implement ServiceFactory and you have to use that one in Declarative Services (please correct me if I have not used declarative services only blueprint)
Option 2:
Create your services with the help of ConfigAdmin. You create a configuration with your client bundle and your service provider bundle will catch that and export the necessary service. After the service is provided you can catch the new service registration with the client. You can find nice doc at http://felix.apache.org/site/apache-felix-config-admin.html. Well in case of this option you will be able to get more services by client bundles but I do not think you can use this with Declarative Services (You must catch the configuration changes programmatically).
Option 3:
Instead of registering IMyService register IMyServiceFactory as an OSGi service. that has a createService(name) function. In this case in the client bundles you have to take care of the lifecycles of your IMyService objects (if no more IMyService is used you can "unget" IMyServiceFactory).

How to get a 'JBoss service' with CDI in JMX with AS6?

I'm currently migrating a JBoss service class from AS5.1 to AS6 (not going to AS7 for a variety of reasons).
For AS5.1, the service implements a {serviceName}MBean and has a jboss-service.xml with attribute values. It's packaged in a jboss-sar, which is packaged in an EAR to be deployed. When deployed, the service fields are populated with the values from jboss-service.xml, and the service is automatically registered into JMX.
I would like to achieve the same thing using AS6, but would like the service to support CDI - so I'd like its new #Inject injection points to be satisfied. I need these to be satisfied in the object registered with JMX, so that methods called via JMX can reference injected fields, but I'm struggling to achieve this.
I've had to package the service in a jar, instead of a jboss-sar, for classloader reasons, but let's say it's otherwise unchanged. When deployed to AS6, all works as before - service goes into JMX, values from XML propagate to the object. However, the instance created does not have its CDI injection points satisfied, and neither does the object registered in JMX.
If I annotate the service class with #Startup and #javax.ejb.Singleton, but keep its interface and the jboss-service.xml, the object registered into JMX still does not have its CDI injection points satisfied. However if I programmattically deregister that bean, and re-register the instance in a #PostConstruct method, then the bean in JMX DOES have its injection points satisfied. However that bean no longer has the values specified in the jboss-service.xml.
So how can I get the best of both worlds? CDI and the usual JBoss service behaviour? What is the correct way to implement a JBoss service with CDI? I've been unable to find documentation on this. Hope someone can help.
Thanks,
Ben
As a worst-case fallback, you should be able to use the CDI extension API to get your service to be injected. I don't think you would need to write a fully-fledged extension, but if you have an initialisation hook in the service object, you can do this (lifted with minor editing from the docs, not compiled or tested):
public static <T> void inject(T object) {
BeanManager beanManager = (BeanManager)new InitialContext().lookup("java:comp/BeanManager");
AnnotatedType<T> type = beanManager.createAnnotatedType(object.getClass());
InjectionTarget<T> it = beanManager.createInjectionTarget(type);
CreationalContext ctx = beanManager.createCreationalContext(null);
it.inject(object, ctx);
it.postConstruct(object);
}
Basically, any object to that method will get injected. All the usual CDI annotations should work. Hopefully.
As mentioned in the comments above, it seems Tom's right - there's no 'nice' way of created a CDIed, JMX bean in one go, you either have to put your JMX bean in CDI, as is suggested above, or put you CDIed bean into JMX. We tried the former, but it appears the BeanManager isn't bound to JNDI at the point the service starts up.
So instead we went with CDI bean -> JMX. We're creating the services as Singleton EJBs, so their injection points are satisfied, and they then get registered/unregistered to JMX in their PostConstruct/PreDestroy methods, using German Escobar's excellent CDI portable extension (germanescobar.net/2010/01/cdi-portable-extension-jmx.html, community.jboss.org/thread/148750 is also helpful).
May try to use ApplicationScoped beans and get them to start by observing a ContainerInitialized(?) event, however, as we don't need all the features of an EJB. Haven't tried that yet, mind...

How do I write an application that more or less acts as a container?

I am planning an application that must provide services that are very much like those of a Java EE container to third party extension code. Basically, what this app does is find a set of work items (currently, the plan is to use Hibernate) and dispatch them to work item consumers.
The work item consumers load the item details, invoke third party extension code, and then if the third party code did not fail, update some state on the work item and commit all work done.
I am explicitly not writing this as a Java EE application. Essentially, my application must provide many of the services of a container, however; it must provide transaction management, connection pooling and management, and a certain amount of deployment support. How do I either A) provide these directly, or B) choose a third party library to provide them. Due to a requirement of the larger project, the extension writers will be using Hibernate, if that makes any difference.
It's worth noting that, of all of the features I've mentioned, the one I know least about is transaction management. How can I provide this service to extension code running in my container?
Hi I recommend using the Spring Framework. It provides a nice way to bring together a lot of the various services you are talking about.
For instance to address your specific needs:
Transaction Management/Connection pooling
I built a spring-based stand-alone application that used Apache commons connection pooling. Also I believe spring has some kind of transaction mgmt built in.
Deployment support
I use ant to deploy and run things as a front-loader. It works pretty well. I just fork a seperate process using ant to run my Spring stand-alone app.
Threading.
Spring has support for Quartz which deals well with threads and thread pools
DAO
Spring integrates nicely with Hibernate and other similar projects
Configuration
Using its xml property definitions -- Spring is pretty good for multiple-environment configuration.
Spring does have transaction management. You can define a DataSource in your application context using Apache DBCP (using a org.apache.commons.dbcp.BasicDataSourceorg.springframework.jdbc.datasource.DataSourceTransactionManager for the DataSource. After that, any object in your application can define its own transactions programatically if you pass it the TransactionManager, or you can use AOP interceptors on the object's definition in your application context, to define which methods need to be run inside a transaction.
Or, the easier approach nowadays with Spring is to use the #Transactional annotation in any method that needs to be run inside a transaction, and to add something like this to your application context (assuming your transactionManager is named txManager):
<tx:annotation-driven transaction-manager="txManager"/>
This way your application will easily accept new components later on, which can have transaction management simply by using the #Transactional annotation or by directly creating transactions through a PlatformTransactionManager that they will receive through a setter (so you can pass it when you define the object in your app context).
You could try Atomikos TransactionsEssentials for Java transaction management and connection pooling (JDBC+JMS) in a J2SE environment. No need for any appservers, and it is much more fun to work with ;-)
HTH
Guy

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