Having trouble with a custom adapter factory not being loaded - osgi

we're having a bit of trouble getting a custom adapter factory loaded in CQ5. The adapter factory code works fine, as the trouble is that we are attempting to use it during the #Activate phase in another SlingServlet.
It seems as though when the Activate phase is called within the Sling Servlet, the Custom Adapter Factory class has not yet been loaded in.
Is there a way to specify dependancy upon the other bundle having loaded, or is it generally a bad idea to attempt to use an Adaptable inside an activate function.

You are right - the adapter factory starts after the servlet and it isn't available during the servlet activation. Normally such cases are solved by OSGi dependency management, but we don't have a clear dependency here, as the servlet doesn't #Reference the adapter factory, but it's used via a Sling adapter factory manager.
You have three options:
Reference the adapter factory in servlet to create an aritficial, strong dependency between two components:
#Reference(target = "(component.name=your.adapter.factory.package.name)")
If the servlet and the adapter factory are placed in different bundles, you may use startlevels to control the order of bundles activation. You can control the startlevel by putting OSGi bundles into following JCR directory:
/apps/[app]/install/[startLevel]
Extract the logic from adapter factory and use it directly in the servlet activator, without the adaptTo() method.

Related

Specs: OSGi HTTP Whiteboard and ServletContextHelper

I need some precision about the ServletContextHelper behavior related to the Http Whiteboard Specification when multiple bundle use the same ServletContextHelper
The spec says :
The Http Whiteboard implementation must create a separate
ServletContext instance for each ServletContextHelper service.
Whiteboard services can be associated with the Servlet Context Helper
by using the osgi.http.whiteboard.context.select property. If this
property is not set, the default Servlet Context Helper is used.
If I understand correctly, all Servlet or Filter using the same ServletContextHelper reference are bound to the same 'ServletContext'
Then :
Some implementations of the ServletContextHelper may be implemented
using a Service Factory, for example to provide resources from the
associated bundle, as the default implementation does. Therefore the
Whiteboard implementation must get the Servlet Context Helper using
the Bundle Context of the bundle that registered the Whiteboard
service.
So if a bundle A registers a Servlet with the ServletContextHelper X, and the bundle B registers a Filter with the same reference of ServletContextHelper, then the Servlet and Filter are registered to the same ServletContext, but their init methods are called with two different instances of ServletContext (in order to implements the getClassLoader() methods differently) ?
Moreover, what is the behavior of the "default" ServletContextHelper ? is there always a "default" ServletContextHelper registered ? is it shared between bundles or is there only one instance by bundles ?
I work on Pax Web 8, where I really want to get the behavior right.
140.2.7 Relation to the Servlet Container chapter of OSGi CMPN specification shows a picture, where there are actually three layers of javax.servlet.ServletContext objects:
the ServletContext implementation specific to real Servlet container. In Pax Web it's one of:
org.eclipse.jetty.servlet.ServletContextHandler.Context
org.apache.catalina.core.ApplicationContext
io.undertow.servlet.spec.ServletContextImpl
the ServletContext implementation in 1:1 relation with the org.osgi.service.http.context.ServletContextHelper OSGi service
the ServletContext that's implementing the service-factory contract for each Whiteboard bundle where all but getClassLoader() methods delegate to the above SCH and getClassLoader() returns bundle.adapt(BundleWiring.class).getClassLoader()
The problem is related to the double-responsibility principle assumed with org.osgi.service.http.context.ServletContextHelper. It is used both to implement functional aspects (handleSecurity()) and resource-separation aspects (getResource()).
So you're right - if Bundle A registers a servlet and Bundle B registers a filter, both will use the same instance of ServletContext (supported by the referenced ServletContextHelper), but their init() methods will be provided with different, bundle-specific instance of ServletContext.
This is simply implemented by delegation, there are two implementations:
org.ops4j.pax.web.service.spi.servlet.OsgiServletContext implements the 1:1 behavior
org.ops4j.pax.web.service.spi.servlet.OsgiScopedServletContext implements getClassLoader() and delegates all other methods to the above OsgiServletContext

How can I access Spring bean from Message-driven bean in JBoss AS 7

I want to make a call to a Spring bean (a #Component) from my message-driven bean (MDB) but have problems getting a reference to it. I've tried with a class implementing org.springframework.context.ApplicationContextAware which stores the Spring ApplicationContext in a static field in a class MyAppContext. The static field in MyAppContext is then accessed from the MDB. But MyAppContext is loaded from different classloaders. The Spring application context is correctly set in the web module classloader context, but in the MDB's classloader context, it's null.
Can I somehow instruct JBoss to use the same classloader for the web app and the MDB?
Or is there a better way than storing the Spring application context in a static field?
Thanks for any advice!
A static holder for the context is not really a good idea. To make your beans available to other applications in a Java EE environment, you should consider making use of JNDI.
Unfortunately, there is no plain JNDI exporter available out of the box, but it's fairly easy to write one yourself, as shown in this blog post: http://maestro-lab.blogspot.ro/2009/01/how-to-export-spring-managed-bean-to.html
There is however a JndiRmiServiceExporter that you may want to look at.
Once your beans are bound to names in JNDI, they can be referenced using standard CDI in your message bean without worrying about class loading issues.
Why not use "ClassPathXmlApplicationContext" to load and look up for the Spring bean you require in your MBean?

dynamically declare beans at runtime in Spring

I am wondering if the following is possible. For testing purposes, I wish for different mock classes to be declared in the application context for different tests. These are acceptance tests, using the Jersey REST client. Is there a way to dynamically declare a bean at runtime? Does Spring have an API to allow changes to the application context after the context has been loaded?
The common way to have different beans in the application context is using profiles. You can read about profiles in the following spring source posts:
http://blog.springsource.org/2011/02/14/spring-3-1-m1-introducing-profile
http://blog.springsource.org/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles/
About your first question, you can declare beans at runtime via BeanDefinitionRegistry.registerBeanDefinition() method, for example:
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SomeClass.class);
builder.addPropertyReference("propertyName", "someBean"); // add dependency to other bean
builder.addPropertyValue("propertyName", someValue); // set property value
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();
factory.registerBeanDefinition("beanName", builder.getBeanDefinition());
Is possible also to register a singleton bean instance (already configured) with
context.getBeanFactory().registerSingleton(beanName, singletonObject)
Finally, Spring don't provides a clear way to change a bean after refreshing the context, but the most common approachs are:
close and refresh again (obiously)
Use a proxy and swap the targetSource at runtime: see Replace spring bean in one context with mock version from another context (for an example).

Recommended way to access Spring beans in Apache Tomcat webapp?

I'm developing a web application on Apache Tomcat 6 with Hibernate and Spring, I'm using different XML configuration files to define my Spring beans (like the Hibernate DAO, Quartz scheduler and some other stuff). All these files are loaded at Tomcat start up via web.xml (ContextLoaderListener).
Now I'm not sure what is the recommended way to get access to my beans.
Should I write on class which provides the BeanFactory for all classes which should use a bean, or is it the better way to load the BeanFactory in each class.
BeanFactory bf = (BeanFactory) ContextLoader.getCurrentWebApplicationContext();
One of the core ideas of the spring framework is to minimize dependencies between classes. You'll get the most benefit by using this concept throughout your whole project. Each and every backend object should be defined as bean and can therefore use the dependency injection automatism.
If some of your Beans need to access the ApplicationContext directly (eg for requesting all Beans implementing some marker interface) you can implement the ApplicationContextAware interface, so still no factory is needed.
Use dependency injection instead. Create getters & setters in each controller class, and use your *-servlet.xml to inject the required beans via the <property> tag. No factory needed!

Calling remote EJB3 without interface classes available

When calling remote EJB3 (Glassfish) from another EJB module, it is usual to have interfaces available, they are included as JAR file so that when you do JNDI lookup everything works as expected.
I have a situation where EJB3 JNDI name is determined at runtime, and my attempts to access the EJBs retrieved from JNDI in usual way fail, container complains ClassNotFound for remote interface classes. This is odd to me, since all the interface classes extend a parent interface for which I DO have a dependency in my calling EJB module, i.e.:
IParent ejbRef = (IParent) JndiLocator.getObject("jndinameRemote");
Is this possible with EJB3, without the need to have an exact remote EJB interface bytecode available in my JAR?
Bozo
Even though i am exactly not sure what the above setup is , I had a similar need of trying to invoke EJB when the client jars are not known during the compile time, infact in addition there is also no way for me to know what Application service is the EJB deployed at.
I had managed to do this by writing my Customized Class Loader , the catch here is that the Class which in turn tries to invoke the EJB must be itself loaded using the Customized class loader along with all the necessary jars i.e client jar with interfaces and models and the application server specific client jar.
I passed all the context properties as an input to my Invoker class to initialize context factory and invoke the bean.
These are high level steps to achieve this
Create Class EJBInvoker with method invokeEJB, you can pass it couple of Maps with properties for preparing context and Ejb interface , method , parameters classes , values and output class.
Use reflection to create instance of InitialContextFactory as well as Bean object , parameters and method invokation.
Add the above class to separate jar file and invoke the method with properties required from external project using a customized class loader.

Resources