view src/main/java/de/mpiwg/itgroup/annotations/restlet/BaseRestlet.java @ 58:f5c0e6df7e88

made uri prefixes in store configurable.
author casties
date Tue, 20 Nov 2012 18:23:52 +0100
parents 4efb21cf0ce0
children e2f86ef9b871
line wrap: on
line source

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 de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;

public abstract class BaseRestlet extends Application {

    public static Logger logger = Logger.getLogger(BaseRestlet.class);

    /**
     * Properties holding consumer keys and secrets.
     */
    protected Properties consumerKeys;
    public String CONSUMER_KEYS_PATH = "WEB-INF/consumerkeys.property";
    public static final String CONSUMERKEYS_KEY = "annotationmanager.consumerkeys";

    /**
     * Properties holding server config.
     */
    protected Properties serverConfig;
    public String CONFIG_PROPS_PATH = "WEB-INF/serverconfig.property";
    public static final String SERVERCONFIG_KEY = "annotationmanager.serverconfig";

    /** 
     * database instance;
     */
    protected 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";

    /**
     * database interface server instance.
     */
    protected WrappingNeoServerBootstrapper srv;
    public static final String GRAPHDBSRV_KEY = "annotationmanager.graphdb.srv";

    /**
     * annotation store instance.
     */
    protected AnnotationStore store;
    public static final String ANNSTORE_KEY = "annotationmanager.store";

    /**
     * LDAP server URI (for looking up full user names).
     */
    protected String ldapServerUrl;
    public static final String LDAP_SERVER_KEY = "annotationmanager.ldapserver.url";

    public static final String ADMIN_USER_KEY = "annotationmanager.admin.user";
    public static final String ADMIN_PASSWORD_KEY = "annotationmanager.admin.password";

    /**
     * run in authorization mode i.e. with tokens.
     */
    protected boolean authorizationMode = false;
    public static final String AUTHORIZATION_MODE_KEY = "annotationmanager.authorization";
    
    /**
     * prefix to create uris for tags in store.
     */
    public static String TAGS_URI_PREFIX = "";
    public static final String TAGS_URI_KEY = "annotationmanager.uris.tags";

    /**
     * prefix to create uris for persons in store.
     */
    public static String PERSONS_URI_PREFIX = "";
    public static final String PERSONS_URI_KEY = "annotationmanager.uris.persons";

    /**
     * prefix to create uris for groups in store.
     */
    public static String GROUPS_URI_PREFIX = ""; 
    public static final String GROUPS_URI_KEY = "annotationmanager.uris.groups";

    /**
     * constructor
     * 
     * @param context
     */
    public BaseRestlet(Context context) {
        super(context);
        configure();
    }

    /**
     * Configures the restlet.
     * Reads serverConfig, consumerKeys and graphDb config from config files and starts graphDb.
     * Uses config from webapp context if already initialized. 
     */
    protected void configure() {
        ServletContext sc = (ServletContext) getContext().getServerDispatcher().getContext().getAttributes()
                .get("org.restlet.ext.servlet.ServletContext");
        if (sc != null) {
            if (sc.getAttribute("annotationserver.log4j.configured") == null) {
                // TODO: is this the right place to run the log4j configurator?
                BasicConfigurator.configure();
                sc.setAttribute("annotationserver.log4j.configured", "done");
            }
            logger.info(getVersion() + " starting...");

            /*
             * read config from webapp
             */
            serverConfig = (Properties) sc.getAttribute(SERVERCONFIG_KEY);
            if (serverConfig == null) {
                serverConfig = new Properties();
                InputStream ps = getResourceAsStream(sc, CONFIG_PROPS_PATH);
                if (ps != null) {
                    logger.debug("loading config from " + CONFIG_PROPS_PATH);
                    try {
                        serverConfig.load(ps);
                        /*
                         * read serverconfig options
                         */
                        graphdbPath = serverConfig.getProperty(GRAPHDB_PATH_KEY, graphdbPath);
                        ldapServerUrl = serverConfig.getProperty(LDAP_SERVER_KEY, null);
                    } catch (IOException e) {
                        logger.warn("Error loading server config: ", e);
                    }
                    logger.debug("config: " + serverConfig);
                } else {
                    logger.error("Unable to get resource " + CONFIG_PROPS_PATH);
                }
                // store config
                sc.setAttribute(SERVERCONFIG_KEY, serverConfig);
            }
            // 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);
                }
            } else {
                // get existing AnnotationStore
                store = (AnnotationStore) sc.getAttribute(ANNSTORE_KEY);
            }
            /*
             * read consumerKeys from webapp
             */
            consumerKeys = (Properties) sc.getAttribute(CONSUMERKEYS_KEY);
            if (consumerKeys == null) {
                consumerKeys = new Properties();
                InputStream ps = getResourceAsStream(sc, CONSUMER_KEYS_PATH);
                if (ps != null) {
                    logger.debug("loading consumer keys from " + CONSUMER_KEYS_PATH);
                    try {
                        consumerKeys.load(ps);
                    } 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);
                }
                // store config
                sc.setAttribute(CONSUMERKEYS_KEY, consumerKeys);
            }
            /*
             * read uri prefixes
             */
            String pup = (String) sc.getAttribute(PERSONS_URI_KEY);
            if (pup != null) {
                BaseRestlet.PERSONS_URI_PREFIX = pup;
            }
            String gup = (String) sc.getAttribute(GROUPS_URI_KEY);
            if (gup != null) {
                BaseRestlet.GROUPS_URI_PREFIX = gup;
            }
            String tup = (String) sc.getAttribute(TAGS_URI_KEY);
            if (tup != null) {
                BaseRestlet.TAGS_URI_PREFIX = tup;
            }
        } else {
            logger.error("Unable to get ServletContext!");
        }
    }

    public abstract String getVersion();

    /**
     * @return the authorizationMode
     */
    public boolean isAuthorizationMode() {
        return authorizationMode;
    }

    /**
     * @return the store
     */
    public AnnotationStore getAnnotationStore() {
        return store;
    }

    /**
     * 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);
    }

    /**
     * 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
        if (ldapServerUrl == null) {
            return retString;
        }
        Hashtable<String, String> env = new Hashtable<String, String>();
        String sp = "com.sun.jndi.ldap.LdapCtxFactory";
        env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, sp);
        env.put(javax.naming.Context.PROVIDER_URL, ldapServerUrl);

        DirContext dctx;
        try {
            dctx = new InitialDirContext(env);
        } catch (NamingException e) {
            logger.error("Error in getFullNameFromLDAP!", e);
            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<SearchResult> 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) {
            logger.error("Error in getFullNameFromLDAP!", e);
        }

        try {
            dctx.close();
        } catch (NamingException e) {
            logger.error("Error in getFullNameFromLDAP!", e);
        }
        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, not 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();
            }
        });
    }

}