Once an instance of an OSGi service is retrieved from the bundle context does it become invalidated when the service is stopped?
My initial tests show that the service instance can be used even after the service bundle is stopped, which contradicts my understanding of the dynamic nature of OSGi.
I suppose this boils down to what retrieving a service (via ServiceTracker) from another bundle in the OSGi container actually does, does it create a new instance or does it give you a pointer to the instance that is registered in the container?
Are there any dangers in using the service instance after the service has been stopped?
This is a very good question so I digged into the specification in search for a definitive answer. It turns out that there is a whole section talking about this problem - see section 5.4 Stale References starting on page 132 of OSGi Service Platform Core Specification, Release 4, Version 4.2.
To answer your question according to the specification:
The behavior of a service that becomes unregistered is undefined. Such services
may continue to work properly or throw an exception at their discretion.
And to prevent potential problems:
Bundles must listen to events generated by the Framework to clean up and remove stale
references.
The specification also gives some tips how to minimize the consequences of stale references.
You are right in that it is contradictory to the dynamic nature of OSGi. I believe that there is no guarantee that the service will be available, although different implementations of OSGi containers and services themselves may behave differently.
For example, if the service was created and registered with Spring DM, then the service retrieved is actually a Spring based proxy to the underlying implementation, and the implementation can still disappear. Thus a service reference that refers directly to an implementation may keep that object from being removed, whereas the proxy based reference will not.
The OSGi specification says:
Bundles are entities that are visible
in normal application programming. For
example, when a bundle is stopped, all
its services will be unregistered.
So you shouldn't be able to get a service from a stopped bundle. But technically it may be possible to use it, at least as long as you hold a reference to the service object (nobody can take it away from you and it will not be GC'd). But I don't think that it is save to use the service. It may depend on other bundle resources, that are not available after the bundle has stopped.
Once an instance of an OSGi service is
retrieved from the bundle context does
it become invalidated when the service
is stopped?
No, the reference itself does not become invalidated. As long as something within the container is holding it, it can also not be GC'ed.
However, whether or not it will be still useful, depends only on the service implementation itself, not the container.
My initial tests show that the service instance can be used even after the service bundle >is stopped, which contradicts my understanding of the dynamic nature of OSGi.
The specifications itself indicate that such references shouldn't be held, but it's up to the implementer to take care for implementing the specifications correctly; means there is no contradiction, there is only the fact that you can implement and deploy bundles which don't behave correctly according to the specifications.
I suppose this boils down to what retrieving a service (via ServiceTracker) from another bundle
in the OSGi container actually does, does it create a new instance or does it give you a pointer
to the instance that is registered in the container?
The container does not create new instances of services, except if there is a ServiceFactory involved (see specs). Looking up a service should always give you a pointer to the registered instance in the container.
Are there any dangers in using the service instance after the service has been stopped?
That only depends on the service implementation; however, by doing so in a bundle, you automatically create a bundle that is not conform with the specs.
In practice, many services are implemented to release resources and references and will not respond properly any longer.
Regarding your question whether it is dangerous to use a service instance after the service has been stopped. To cite from the 4.2 core spec (5.4 Stale References):
The behavior of a service that becomes
unregistered is undefined. Such
services may continue to work properly
or throw an exception at their
discretion.
I dont want to cite the whole section of the spec here, but the following sentences are a good discussion about the danger of using stale references:
A stale reference is a reference to a Java object that belongs
to the class loader of a bundle that is stopped or is associated
with a service object that is unregistered. Standard Java does not
provide any generic means to clean up stale references, and bundle
developers must analyze their code carefully to ensure that stale
references are deleted.
Stale references are potentially harmful because they hinder the Java
garbage collector from harvesting the classes, and possibly the instances,
of stopped bundles. This may result in significantly increased memory
usage and can cause updating native code libraries to fail. Bundles using
services are strongly recommended to use either the Service Tracker or
Declarative Services.
A service reference should never be kept as a reference. You should always look up a service at runtime. This ties you to the OSGI api however, whihc is not always wanted.
Have a look at
- OSGI serviceTracker
- OSGI declarative services
- OSGI BluePrint
- Spring DM
- Peaberry
- iPojo
which all take care of the dynamism for you, most of them with no OSGI api to use.
Regards,
Leen Toelen
Related
I'm running a JBoss AS 7.1.3.Final installation with a lot of applications. One of those applications provides common resources and functionallities used by all applications (let's call it framework). I'm also planning to move to WildFly 8, if this is an useful information for your answer.
All applications should only be accessible, if the framework is available (up and running). My current implementation to achive this dependency is not that nice** and as I'm currently re-designing some parts of the environment, I'm looking for a much neater solution for it. My first idea was to create some kind of a manager which will be instantiated by the application server and is available to all applications. So after an application is started, it could register itself on the manager and as soon as the framework is up, the applications will be notified.
Is this possible using the JNDI of the JVM where all applications + framework are running? How must this be implemented? It's really hard to find useful information about how the JNDI works and what is possible with it. Do you have any other, simplier ideas, how to share a class instance between applications?
Thank you.
** Currently I'm using a EJB-timer in the applications and a singleton EJB in the framework. The framework is available as soon as the EJB lookup succeeds.
--
Edit #1
Some more informations as requested by Nikos Paraskevopoulos
One functionionality that is provided by the framework is the maintenance mode. The applications will check, right after startup, if it is blocked for normal users. It will also receive notifications about planned maintenances. (central DB, the application has no rights on it)
Common stylesheets or layouts are deployed with the framework.
The user informations are provided by the framework. (central DB, the application has no rights on it)
The main problem is: How could I avoid any timers? I have no idea, how I could ensure, that the framework is up before everything else.
A few thoughts:
JBoss has the capability of ordering deployments according to their dependencies. See here and here. So, if all the "applications" depend explicitly on the "framework", your problem may be solved.
It seems you have a quite strongly coupled configuration. Would it be possible to decouple them, e.g. provide the service through web services (SOAP/REST)? Of course this introduces extra overhead for the communication and the refactoring...
JNDI can be seen (very roughly) as a name to object map shared across the applications. As such, you may share stuff through it. But I do not see how will you solve the timing problem, i.e. wait for a service to be available before using it from the "applications". The manager component you mention can be placed in JNDI.
This is not a complete answer, but it would not fit as a comment either. Maybe if you presented more details on the nature of the applications, the frameworks used etc, you could get more specific answers.
Good luck anyway
Edit #1:
Maintenance mode: This may be nice for using with JNDI. A servlet filter that intercepts every (applicable) request will check a global JNDI name; if it is not found (i.e. framework not started) or it is false, it will short-circuit the processing of the request, sending back the "maintenance mode" page. The framework will have to set a Boolean in the global JNDI name as soon as it has started and maintain its value, i.e. set it to false if maintenance mode is active.
Common stylesheets: This is really covered by the maintenance mode flag, I believe. Layouts: It depends on the view technology/layouts technology.
User information: This is a good candidate for SOAP/REST implementation. It is not expected to be called frequently, so I assume overhead will not matter.
I think OSGi is the technology you should consider. Basically you have an OSGi container with applications (called bundles) which provide or consume services. So you would have a framework service which is consumed by all applications. JBoss is an OSGi container, as far as I know.
If my web application and ejb application are on the same machine (on same JVM) and all the ejb calls are local calls , will the use of ThreadLocal create any issue while passing information from web to ejb?
Any workaround if the ejb calls are remote? Will ThreadLocal information be available from web application to ejb application? Is use of ThreadLocal advisable in such scenario?
For the first question, there is no problem as long as you remove the ThreadLocal variables at the end of every call. This is important because containers (servlet or ejb) typically use threadpools and therefore reuse threads, this has two effects: one "call" may see threadlocal info coming from a previous call, and if you remove an app from the container without stopping the JVM some classes may not be garbage collected because they are still referenced by a container thread. So put data in a threadlocal in a try / finally block and remove in the finally part.
Here is a post showing one way to handle the problem: ThreadLocal in web applications
For the second question as data is threadlocal it will not come with a remote call, you have to add a parameter to your interfaces, extract threadlocal data on one side and recreate it on the other side...
When using EJB 3.1 you can pass around contextual information in the EJBContext using its context data. This is just a Map<String,Object>.
ThreadLocal shouldn't be used in EJB contexts. One cannot guarantee that the EJB method invocations are all on the same thread (of course the should be).
In EJB there is a different approach call TransactionSyncrhonizationRegistry. See Explanation/Usage for further details.
all the ejb calls are local calls , will the use of ThreadLocal create
any issue while
No, you answered your question yourself. Since calls are local they are executed in the context of one thread.
Any workaround if the ejb calls are remote?
In case of remote calls, the Java EE container will be run in an other JVM, it will spawn its own threads to handle incoming RMI request, there is no way for a remote Java EE container to know about thread local variables that were declared on the other side. Pass it as a parameter object.
It depends what information you are passing! The first question it too generic. I suggest to read the JavaDoc related to ThreadLocal here.
ThreadLocal lives from the server side of the application and are used to let Thread-safe the calls of your Thread objects.
For local calls, the ThreadLocal should work fine, as long as everything is done in the same thread.
For remote calls, which can potentially run on a different server, you will need to come up with something else. Either pass all values as parameters (which will work, but introduces complexity in the code) or use something like a distributed cache, e.g. Hazelcast, which will function like a global HashMap, which all cluster nodes have access to.
ThreadLocal cannot be used with 100% certainty in web applications. You simply do not have the guarantee that one thread will be used for one session. In my point of view this can get a very hard to find security hole!
ctx.getContextData() does not work for me, it always returns null!
I also tried TransactionSynchronizationRegistry, but I get null as well.
The only thing that worked is using JAAS as a workaround.But it is not a nice solution.
I'd like to have a Spring-managed bean schedule execution of itself (or some other bean, simple factoring) if certain conditions are met (i.e. checking successul startup etc.)
I'd also like to be able to see and control the timer from within the application, which will be running on a Java EE 5-compliant container.
Not sure how best to do this - I know about the dangers of doing thread management myself in an EE environment.
You could have a base class that is a wrapper to schedule background tasks (could be e.g. an Executor or TimerTask) and be parameterized by the timing intervals or even the task to schedule and you could derive more specific classes specialized on certain tasks.
These you would configure/instantiate via Spring configuration and of course your app could modify these via the properties of the classes/beans.
Concerning thread management, I also had concerns regarding threads since JavaEE specs (I believe specifically EJB specs) disallow it but this perhaps depends on the container. For example in Tomcat which of course is not a fully EE container, I never had issue with my own threads.
You don't mention which container you are interested in.
Also (friends here can correct if I am wrong) my understanding is that threads are disallowed e.g. in EJB containers etc if you access various resources handled by the container threads.
So if you only want to do some e.g. sanity checks (checking succesful startup) and similar, I don't think that this would be an issue. But this is MHO. I am not sure to be honest
I have a modular application that uses OSGi for lifecycle and dependency management. However, some of the bundles require some time after startup to be ready, for example, because they have to acquire data from somewhere. Also, they might be unable to process certain calls during a configuration update, for example a bundle that keeps a connection to a db can't send queries while it is updating the connection parameters.
So, it seems to me that a bundle can have more subtle states than those managed by the OSGi container, and since they affect bundle interaction, there needs to be some handling. I can see three basic strategies for doing this:
screw subtlety, and for example put all initialization code into BundleActivator.start(). If it takes forever to acquire that data, well then the bundle just won't be started forever. I'm not 100% sure that this would cover all cases, and it seems slightly wrong.
fit my bundles with an additional event system that they use to notify each other of more subtle states like "momentarily unavailable" or "really ready now". This might simply be unnecessary overhead.
have the bundle keep its more subtle state changes to itself and just take calls anyway, deferring them internally if necessary. This might not be appropriate when the caller could actually handle unavailability better.
Do you have any general advice on that? Is there even something in OSGi that I could use?
Try using services and service tracker to communicate between bundles. This will also help decouple your bundles as you'll likely be using interfaces.
Using you example of bundle which talks to a database:
Activator.start(), launch a background thread to do your initization business. Activators should execute quickly.
Register a service that provides the needed DB related abstraction for other bundles.
Other bundles create a service tracker to look for services they need,
Other bundles get a callback in the service tracker only when the first bundle registers the service. The first bundles only registers the service when it's ready implying that other bundles can begin using it immediately.
I want to start a background process in a Java EE (OC4J 10) environment. It seems wrong to just start a Thread with "new Thread" But I can't find a good way for this.
Using a JMS queue is difficult in my special case, since my parameters for this method call are not serializable.
I also thought about using an onTimeout Timer Method on a session bean but this does not allow me to pass parameters (as far as I know).
Is there any "canon" way to handle such a task, or do I just have to revert to "new Thread" or a java.concurrent.ThreadPool.
Java EE usually attempts to removing threading from the developers concerns. (It's success at this is a completely different topic).
JMS is clearly the preferred approach to handle this.
With most parameters, you have the option of forcing or faking serialization, even if they aren't serializable by default. Depending on the data, consider wrapping it in a serializable object that can reload the data. This will clearly depend on the parameter and application.
JMS is the Java EE way of doing this. You can start your own threads if the container lets you, but that does violate the Java EE spec (you may or may not care about this).
If you don't care about Java EE generic compliance (if you would in fact resort to threads rather than deal with JMS), the Oracle container will for sure have proprietary ways of doing this (such as the OracleAS Job Scheduler).
Don't know OCJ4 in detail but I used the Thread approach and a java.util.Timer approach to perform some task in a Tomcat based application. In Java 5+ there is an option to use one of the Executor services (Sheduled, Priority).
I don't know about the onTimeout but you could pass parameters around in the session itself, the app context or in a static variable (discouraged would some say). But the name tells me it is invoked when the user's session times out and you want to do some cleanup.
Using the JMS is the right way to do it, but it's heavier weight.
The advantage you get is that if you need multiple servers, one server or whatever, once the servers are configured, your "Threading" can now be distributed to multiple machines.
It also means you don't want to send a message for a truly trivial amount of work or with a massive amount of data. Choose your interface points well.
see here for some more info:
stackoverflow.com/questions/533783/why-spawning-threads-in-j2ee-container-is-discouraged
I've been creating threads in a container (Tomcat, JBoss) with no problem, but they were really simple queues, and I don't rely on clustering.
However, EJB 3.1 will introduce asynchronous invocation that you may find useful:
http://www.theserverside.com/tt/articles/article.tss?track=NL-461&ad=700869&l=EJB3-1Maturity&asrc=EM_NLN_6665442&uid=2882457
Java EE doesn't really forbid you to create your own threads, it's the EJB spec that says "unmanaged threads" arn't allowed. The reason is that these threads are unknown to the application server and therefore the container cannot manage things like security and transactions on these threads.
Nevertheless there are lots of frameworks out there that do create their own threads. For example Quartz, Axis and Spring. Changes are your already using one of these, so it's not that bad to create your own threads as long as you're aware of the consequences. That said I agree with the others that the use of JMS or JCA is preferred over manual thread creation.
By the way, OC4J allows you to create your own threads. However it doesn't allow JNDI lookups from these unmanaged threads. You can disable this restriction by specifying the -userThreads argument.
I come from a .NET background, and JMS seems quite heavy-weight to me. Instead, I recommend Quartz, which is a background-scheduling library for Java and JEE apps. (I used Quartz.NET in my ASP.NET MVC app with much success.)