Configuring Atmosphere's Classes Creation and Injection - Atmosphere/atmosphere GitHub Wiki
Starting with Atmosphere 2.1+, it is possible to configure an AtmosphereObjectFactory for dependencies injection and class creation. You can define your own and pass it to the framework by defining an init-param:
<init-param>
<param-name>org.atmosphere.cpr.objectFactory</param-name>
<param-value> << an implementation of AtmosphereObjectFactory >> </param-value>
</init-param>
Starting with Atmosphere 2.3.0+ Atmosphere have basic support for injection. If you are using 2.3.2+, you can also defines under META-INF/services/org.atmosphere.inject.Injectable
classes that implements the Injectable interface so the AtmosphereObjectFactory can inject those objects into your classes.
You can also enable one of the following supported frameworks by just adding the artifact on you classpath.
For CDI, Atmosphere will use the following code for injecting/creating object:
public class CDIObjectFactory implements AtmosphereObjectFactory<Object> {
private static final Logger logger = LoggerFactory.getLogger(CDIObjectFactory.class);
private BeanManager bm;
public CDIObjectFactory(){
try {
bm = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
} catch (NamingException ex) {
try {
bm = (BeanManager) new InitialContext().lookup("java:comp/env/BeanManager");
} catch (NamingException e) {
logger.error("{}", e);
}
}
final Iterator<Bean<?>> i = bm.getBeans(AtmosphereProducers.class).iterator();
if (!i.hasNext()) {
throw new IllegalStateException();
}
}
@Override
@SuppressWarnings("unchecked")
public <T, U extends T> U newClassInstance(Class<T> classType, Class<U> classToInstantiate) throws InstantiationException, IllegalAccessException {
CreationalContext cc = null;
try {
final Iterator<Bean<?>> i = bm.getBeans(classToInstantiate).iterator();
if (!i.hasNext()) {
logger.trace("Unable to find {}. Creating the object directly.", classToInstantiate.getName());
return classToInstantiate.newInstance();
}
Bean<U> bean = (Bean<U>) i.next();
CreationalContext<U> ctx = bm.createCreationalContext(bean);
U dao = (U) bm.getReference(bean, classToInstantiate, ctx);
return dao;
} catch (Exception e) {
logger.error("Unable to construct {}. Creating the object directly.", classToInstantiate.getName());
return classToInstantiate.newInstance();
} finally {
if (cc != null) cc.release();
}
}
@Override
public AtmosphereObjectFactory allowInjectionOf(Object o) {
return this;
}
public String toString() {
return "CDI ObjectFactory";
}
@Override
public void configure(AtmosphereConfig config) {
try {
AtmosphereProducers p = newClassInstance(AtmosphereProducers.class,AtmosphereProducers.class);
p.configure(config);
} catch (Exception e) {
logger.error("", e);
}
}
}
You can install it by adding in your pom.xml:
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-cdi</artifactId>
<version>2.3.0+</version>
</dependency>
Atmosphere will auto-detect it and use it automatically.
For Spring, Atmosphere will use the following code for injecting/creating object:
public class SpringWebObjectFactory implements AtmosphereObjectFactory<Class<?>> {
/**
* A comma delimited list of {@link org.atmosphere.inject.InjectableObjectFactory.DEFAULT_ATMOSPHERE_INJECTABLE} that
* won't be created by Spring.
*/
public static final String ATMOSPHERE_SPRING_EXCLUDE_CLASSES = "org.atmosphere.spring.excludedClasses";
private static final Logger logger = LoggerFactory.getLogger(SpringWebObjectFactory.class);
protected boolean preventSpringInjection = false;
private final List<Class<?>> excludedFromInjection = new ArrayList<Class<?>>();
private AnnotationConfigApplicationContext context;
@Override
public <T, U extends T> U newClassInstance(Class<T> classType,
Class<U> classToInstantiate)
throws InstantiationException, IllegalAccessException {
if (preventSpringInjection && excludedFromInjection.contains(classType)) {
logger.trace("Excluded from injection {}", classToInstantiate.getName());
return classToInstantiate.newInstance();
}
String name = classToInstantiate.getSimpleName();
if (!context.containsBeanDefinition(Introspector.decapitalize(name))) {
context.register(classToInstantiate);
}
U t = context.getAutowireCapableBeanFactory().createBean(classToInstantiate);
if (t == null) {
logger.info("Unable to find {}. Creating the object directly."
+ classToInstantiate.getName());
return classToInstantiate.newInstance();
}
return t;
}
@Override
public AtmosphereObjectFactory allowInjectionOf(Class<?> aClass) {
context.register(aClass);
return this;
}
public String toString() {
return "Spring Web ObjectFactory";
}
@Override
public void configure(AtmosphereConfig config) {
try {
String s = config.getInitParameter(ATMOSPHERE_SPRING_EXCLUDE_CLASSES);
if (s != null) {
String[] list = s.split(",");
for (String clazz : list) {
excludedFromInjection.add(IOUtils.loadClass(getClass(), clazz));
}
if (list.length > 0) {
preventSpringInjection = true;
}
}
context = new AnnotationConfigApplicationContext();
context.setParent(WebApplicationContextUtils.getWebApplicationContext(config.framework().getServletContext()));
context.refresh();
// Hack to make it injectable
context.register(AtmosphereConfig.class);
context.getBean(AtmosphereConfig.class, config.framework()).populate(config);
} catch (Exception ex) {
logger.warn("Unable to configure injection", ex);
}
}
}
You can install it by adding in your pom.xml:
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-spring</artifactId>
<version>2.3.0+</version>
</dependency>
For Guice, Atmosphere will use the following code for injecting/creating object:
public class GuiceObjectFactory implements AtmosphereObjectFactory<AbstractModule> {
private static final Logger logger = LoggerFactory.getLogger(GuiceObjectFactory.class);
protected Injector injector;
protected AtmosphereConfig config;
private final List<AbstractModule> modules = new ArrayList<AbstractModule>();
@Override
public void configure(AtmosphereConfig config) {
if (config == null) {
throw new NullPointerException("AtmosphereConfig can't be null");
}
this.config = config;
modules.add(new AtmosphereModule());
try {
AtmosphereProducers p = newClassInstance(AtmosphereProducers.class, AtmosphereProducers.class);
p.configure(config);
} catch (Exception e) {
logger.error("", e);
}
}
@Override
public <T, U extends T> U newClassInstance(Class<T> classType, Class<U> classToInstantiate) throws InstantiationException, IllegalAccessException {
initInjector(config.framework());
U t;
if (injector != null) {
t = injector.getInstance(classToInstantiate);
} else {
logger.warn("No Guice Injector found in current ServletContext. Are you using {}?", AtmosphereGuiceServlet.class.getName());
logger.trace("Unable to find {}. Creating the object directly.", classToInstantiate.getName());
t = classToInstantiate.newInstance();
}
return t;
}
@Override
public String toString() {
return "Guice ObjectFactory";
}
protected void initInjector(AtmosphereFramework framework) {
if (injector == null) {
// start by trying to get an Injector instance from the servlet context
Injector existingInjector = (Injector) framework.getServletContext().getAttribute(Injector.class.getName());
AbstractModule[] a = modules.toArray(new AbstractModule[modules.size()]);
if (existingInjector != null) {
logger.trace("Adding AtmosphereModule to existing Guice injector");
injector = existingInjector.createChildInjector(a);
} else {
logger.trace("Creating the Guice injector manually with AtmosphereModule");
injector = Guice.createInjector(a);
}
}
}
@Override
public AtmosphereObjectFactory allowInjectionOf(AbstractModule module) {
modules.add(module);
return this;
}
private class AtmosphereModule extends AbstractModule {
@Override
protected void configure() {
bind(BroadcasterFactory.class).toProvider(new Provider<BroadcasterFactory>() {
@Override
public BroadcasterFactory get() {
return config.getBroadcasterFactory();
}
});
bind(AtmosphereFramework.class).toProvider(new Provider<AtmosphereFramework>() {
@Override
public AtmosphereFramework get() {
return config.framework();
}
});
bind(AtmosphereResourceFactory.class).toProvider(new Provider<AtmosphereResourceFactory>() {
@Override
public AtmosphereResourceFactory get() {
return config.resourcesFactory();
}
});
bind(MetaBroadcaster.class).toProvider(new Provider<MetaBroadcaster>() {
@Override
public MetaBroadcaster get() {
return config.metaBroadcaster();
}
});
bind(AtmosphereResourceSessionFactory.class).toProvider(new Provider<AtmosphereResourceSessionFactory>() {
@Override
public AtmosphereResourceSessionFactory get() {
return config.sessionFactory();
}
});
bind(AtmosphereConfig.class).toProvider(new Provider<AtmosphereConfig>() {
@Override
public AtmosphereConfig get() {
return config;
}
});
}
}
}
You can install it by adding in your pom.xml:
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-guice</artifactId>
<version>2.3.0+</version>
</dependency>