package com.tinkerpop.rexster.server;
import com.sun.jersey.api.core.HttpContext;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
import com.tinkerpop.rexster.Tokens;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Type;
import java.util.List;
/**
* A Jersey InjectableProvider and Injectable that supplies Servlets that have a @Context
* annotated RexsterApplication field with a DefaultRexsterApplication.
* <p/>
* Those interested in embedding Rexster into their custom application should write a Provider
* class following this pattern that supplies their custom implementation of RexsterApplication.
* <p/>
* This class allows deployment of Rexster inside of a servlet container like Tomcat. If
* it is deployed in this fashion, rexster.xml need only consist of the graph definitions as
* follows:
*
* <pre>
* {@code
* <rexster>
* <graphs>
* <graph>
* ...
* </graph>
* ...
* </graphs>
* </rexster>
* }
* </pre>
*
* The other settings will be ignore and controlled by the servlet container. While TinkerPop does not
* officially support this kind of deployment, it can be done by building Rexster to a WAR with
* the appropriate web.xml file which should look something like:
*
* <pre>
* {@code
* <?xml version="1.0" encoding="utf-8"?>
* <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
* <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
* <display-name>Rexster: A RESTful Graph Shell</display-name>
* <servlet>
* <servlet-name>Jersey Web Application</servlet-name>
* <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
* <init-param>
* <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
* <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
* </init-param>
* <init-param>
* <param-name>com.sun.jersey.config.property.packages</param-name>
* <param-value>com.tinkerpop.rexster;com.tinkerpop.rexster.server</param-value>
* </init-param>
* <init-param>
* <param-name>com.tinkerpop.rexster.config</param-name>
* <param-value>rexster.xml</param-value>
* </init-param>
* </servlet>
* </web-app>
* }
* </pre>
*
* @author Jordan A. Lewis (http://jordanlewis.org)
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
@Provider
public class RexsterApplicationProvider extends AbstractHttpContextInjectable<RexsterApplication>
implements InjectableProvider<Context, Type> {
private static RexsterApplication rexster;
private static XMLConfiguration configurationProperties;
public RexsterApplicationProvider(@Context ServletContext servletContext, @Context ServletConfig servletConfig) {
if (rexster == null) {
if (configurationProperties == null) {
configurationProperties = new XMLConfiguration();
}
final String rexsterXmlFile = servletConfig.getInitParameter("com.tinkerpop.rexster.config");
try {
configurationProperties.load(servletContext.getResourceAsStream(rexsterXmlFile));
} catch (ConfigurationException e) {
throw new RuntimeException(String.format(
"Could not load %s properties file. Message: %s", rexsterXmlFile, e.getMessage()), e);
}
final List<HierarchicalConfiguration> graphConfigs = configurationProperties.configurationsAt(Tokens.REXSTER_GRAPH_PATH);
rexster = new XmlRexsterApplication(graphConfigs);
}
}
@Override
public RexsterApplication getValue(HttpContext c) {
return rexster;
}
@Override
public RexsterApplication getValue() {
return rexster;
}
@Override
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
@Override
public Injectable getInjectable(ComponentContext ic, Context context, Type type) {
if (type.equals(RexsterApplication.class)) {
return this;
}
return null;
}
}