package de.mpiwg.itgroup.annotations.restlet; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Hashtable; import java.util.Properties; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.servlet.ServletContext; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.factory.GraphDatabaseFactory; import org.neo4j.kernel.AbstractGraphDatabase; import org.neo4j.server.WrappingNeoServerBootstrapper; import org.restlet.Application; import org.restlet.Context; import org.restlet.Restlet; import org.restlet.routing.Router; import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore; public class RestServer extends Application { public static Logger logger = Logger.getLogger(RestServer.class); /** * Properties holding consumer keys and secrets */ private Properties consumerKeys; public String CONSUMER_KEYS_PATH = "WEB-INF/consumerkeys.property"; private Properties serverConfig; public String CONFIG_PROPS_PATH = "WEB-INF/serverconfig.property"; private GraphDatabaseService graphDb; public static final String GRAPHDB_KEY = "annotationmanager.graphdb"; public static final String GRAPHDB_PATH_KEY = "annotationmanager.graphdb.path"; public String graphdbPath = "WEB-INF/neo4j-annotation-db"; private WrappingNeoServerBootstrapper srv; public static final String GRAPHDBSRV_KEY = "annotationmanager.graphdb.srv"; private AnnotationStore store; public static final String ANNSTORE_KEY = "annotationmanager.store"; /** * constructor * * @param parentContext */ public RestServer(Context parentContext) { super(parentContext); // TODO: is this the right place to run the log4j configurator? BasicConfigurator.configure(); ServletContext sc = (ServletContext) getContext().getServerDispatcher().getContext().getAttributes() .get("org.restlet.ext.servlet.ServletContext"); if (sc != null) { /* * read config from webapp */ serverConfig = new Properties(); InputStream ps1 = getResourceAsStream(sc, CONFIG_PROPS_PATH); if (ps1 != null) { logger.debug("loading config from " + CONFIG_PROPS_PATH); try { serverConfig.load(ps1); /* * read serverconfig options */ graphdbPath = serverConfig.getProperty(GRAPHDB_PATH_KEY, graphdbPath); } catch (IOException e) { logger.warn("Error loading server config: ", e); } logger.debug("config: " + serverConfig); } else { logger.error("Unable to get resource " + CONFIG_PROPS_PATH); } // look for database service in context graphDb = (GraphDatabaseService) sc.getAttribute(GRAPHDB_KEY); if (graphDb == null) { /* * open database */ String dbFn = getResourcePath(sc, graphdbPath); if (dbFn != null) { logger.debug("opening DB " + dbFn); graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(dbFn); registerShutdownHook(graphDb); // store in context sc.setAttribute(GRAPHDB_KEY, graphDb); // AnnotationStore store = new AnnotationStore(graphDb); sc.setAttribute(ANNSTORE_KEY, store); // admin server srv = new WrappingNeoServerBootstrapper((AbstractGraphDatabase) graphDb); logger.debug("Starting DB admin server..."); // store in context sc.setAttribute(GRAPHDBSRV_KEY, srv); srv.start(); } else { logger.error("Unable to get resource " + dbFn); } } /* * read consumerKeys from webapp */ consumerKeys = new Properties(); InputStream ps2 = getResourceAsStream(sc, CONSUMER_KEYS_PATH); if (ps2 != null) { logger.debug("loading consumer keys from " + CONSUMER_KEYS_PATH); try { consumerKeys.load(ps2); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.debug("consumer keys: " + consumerKeys); } else { logger.error("Unable to get resource " + CONSUMER_KEYS_PATH); } } else { logger.error("Unable to get ServletContext!"); } } /** * returns consumer secret for consumer key. returns null if consumer key * doesn't exist. * * @param consumerKey * @return */ public String getConsumerSecret(String consumerKey) { return consumerKeys.getProperty(consumerKey); } /* * (non-Javadoc) * * @see org.restlet.Application#createInboundRoot() */ @Override public Restlet createInboundRoot() { // this.authenticator = createAuthenticator(); Router router = new Router(getContext()); router.attach("/annotator/annotations", AnnotatorAnnotations.class); router.attach("/annotator/annotations/{id}", AnnotatorAnnotations.class); router.attach("/annotator/search", AnnotatorSearch.class); // router.attach("",redirector); router.attach("/annotator", // ExtendedAnnotationInput.class); router.attach("/", AnnotatorInfo.class); // authenticator.setNext(router); // return authenticator; return router; } /** * Hole den vollen Benutzernamen aus dem LDAP * * @param creator * @return */ public String getFullNameFromLdap(String creator) { String retString = creator; // falls nichts gefunden wird einfach den // creator zurueckgeben Hashtable env = new Hashtable(); String sp = "com.sun.jndi.ldap.LdapCtxFactory"; env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, sp); // TODO: should go into config file String ldapUrl = "ldap://ldap.mpiwg-berlin.mpg.de/dc=mpiwg-berlin,dc=mpg,dc=de"; env.put(javax.naming.Context.PROVIDER_URL, ldapUrl); DirContext dctx; try { dctx = new InitialDirContext(env); } catch (NamingException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return retString; } String base = "ou=people"; SearchControls sc = new SearchControls(); String[] attributeFilter = { "cn", "mail" }; sc.setReturningAttributes(attributeFilter); sc.setSearchScope(SearchControls.SUBTREE_SCOPE); String filter = "(uid=" + creator + ")"; try { NamingEnumeration results = dctx.search(base, filter, sc); while (results.hasMore()) { SearchResult sr = (SearchResult) results.next(); javax.naming.directory.Attributes attrs = sr.getAttributes(); Attribute attr = attrs.get("cn"); retString = (String) attr.get(); } } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { dctx.close(); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return retString; } /** * returns resource from path (in webapp) as InputStream. * * @param sc * @param path * @return */ protected InputStream getResourceAsStream(ServletContext sc, String path) { InputStream ps = sc.getResourceAsStream(path); if (ps == null) { // try as file File pf = new File(sc.getRealPath(path)); if (pf != null) { logger.debug("trying file for: " + pf); try { ps = new FileInputStream(pf); } catch (FileNotFoundException e) { logger.error(e); } } } return ps; } /** * get a real file name for a web app file pathname. * * If filename starts with "/" its treated as absolute else the path is * appended to the base directory of the web-app. * * @param filename * @param sc * @return */ public static String getResourcePath(ServletContext sc, String filename) { File f = new File(filename); // is the filename absolute? if (!f.isAbsolute()) { // relative path -> use getRealPath to resolve in webapp filename = sc.getRealPath(filename); } return filename; } /* (non-Javadoc) * @see org.restlet.Application#stop() */ @Override public synchronized void stop() throws Exception { /* * trying to clean up databases, nur sure if this is the right way... */ if (srv != null) { logger.debug("Stopping DB admin server..."); srv.stop(); srv = null; } if (graphDb != null) { logger.debug("Stopping DB..."); graphDb.shutdown(); graphDb = null; } super.stop(); } private static void registerShutdownHook(final GraphDatabaseService graphDb) { // Registers a shutdown hook for the Neo4j instance so that it // shuts down nicely when the VM exits (even if you "Ctrl-C" the // running example before it's completed) Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { graphDb.shutdown(); } }); } }