source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/BaseRestlet.java @ 94:fcb6fe10e08c

Last change on this file since 94:fcb6fe10e08c was 94:fcb6fe10e08c, checked in by casties, 9 years ago

added config option for webapp URL prefix.

File size: 16.0 KB
Line 
1package de.mpiwg.itgroup.annotations.restlet;
2
3/*
4 * #%L
5 * AnnotationManager
6 * %%
7 * Copyright (C) 2012 - 2014 MPIWG Berlin
8 * %%
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation, either version 3 of the
12 * License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Lesser Public License for more details.
18 *
19 * You should have received a copy of the GNU General Lesser Public
20 * License along with this program.  If not, see
21 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22 * #L%
23 * Author: Robert Casties (casties@mpiwg-berlin.mpg.de),
24 *         Dirk Wintergruen (dwinter@mpiwg-berlin.mpg.de)
25 */
26
27import java.io.File;
28import java.io.FileInputStream;
29import java.io.FileNotFoundException;
30import java.io.IOException;
31import java.io.InputStream;
32import java.util.Hashtable;
33import java.util.Properties;
34import java.util.concurrent.ConcurrentMap;
35import java.util.logging.Logger;
36
37import javax.naming.NamingEnumeration;
38import javax.naming.NamingException;
39import javax.naming.directory.Attribute;
40import javax.naming.directory.DirContext;
41import javax.naming.directory.InitialDirContext;
42import javax.naming.directory.SearchControls;
43import javax.naming.directory.SearchResult;
44import javax.servlet.ServletContext;
45
46import org.neo4j.graphdb.GraphDatabaseService;
47import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
48import org.neo4j.graphdb.factory.GraphDatabaseFactory;
49import org.neo4j.graphdb.factory.GraphDatabaseSettings;
50import org.neo4j.kernel.GraphDatabaseAPI;
51import org.neo4j.server.WrappingNeoServerBootstrapper;
52import org.restlet.Application;
53import org.restlet.Context;
54
55import de.mpiwg.itgroup.annotations.neo4j.AnnotationStore;
56
57public abstract class BaseRestlet extends Application {
58
59    public static Logger logger = Logger.getLogger(BaseRestlet.class.getCanonicalName());
60
61    /**
62     * Properties holding consumer keys and secrets.
63     */
64    protected Properties consumerKeys;
65    public String CONSUMER_KEYS_PATH = "consumerkeys.property";
66    public static final String CONSUMERKEYS_KEY = "annotationmanager.consumerkeys";
67
68    /**
69     * Properties holding server config.
70     */
71    protected Properties serverConfig;
72    public String CONFIG_PROPS_PATH = "serverconfig.property";
73    public static final String SERVERCONFIG_KEY = "annotationmanager.serverconfig";
74
75    /**
76     * database instance;
77     */
78    protected GraphDatabaseService graphDb;
79    public static final String GRAPHDB_KEY = "annotationmanager.graphdb";
80    public static final String GRAPHDB_PATH_KEY = "annotationmanager.graphdb.path";
81    public String graphdbPath = "neo4j-annotation-db";
82
83    /**
84     * database interface server instance.
85     */
86    protected WrappingNeoServerBootstrapper srv;
87    public static final String GRAPHDBSRV_KEY = "annotationmanager.graphdb.srv";
88
89    /**
90     * annotation store instance.
91     */
92    protected AnnotationStore store;
93    public static final String ANNSTORE_KEY = "annotationmanager.store";
94
95    /**
96     * LDAP server URI (for looking up full user names).
97     */
98    protected String ldapServerUrl;
99    public static final String LDAP_SERVER_KEY = "annotationmanager.ldapserver.url";
100
101    /**
102     * web frontend admin user name
103     */
104    public static final String ADMIN_USER_KEY = "annotationmanager.admin.user";
105    /**
106     * web frontend admin user password
107     */
108    public static final String ADMIN_PASSWORD_KEY = "annotationmanager.admin.password";
109
110    /**
111     * run in authorization mode i.e. with tokens.
112     */
113    protected boolean authorizationMode = false;
114    public static final String AUTHORIZATION_MODE_KEY = "annotationmanager.authorization";
115   
116    /**
117     * prefix for webapp URLs (if needed by proxying).
118     */
119    protected String webappUriPrefix = null;
120    public static final String WEBAPP_PREFIX = "annotationmanager.webapp.prefix";
121   
122    /**
123     * prefix to create uris for tags in store.
124     */
125    public static String TAGS_URI_PREFIX = "";
126    public static final String TAGS_URI_KEY = "annotationmanager.uris.tags";
127
128    /**
129     * prefix to create uris for persons in store.
130     */
131    public static String PERSONS_URI_PREFIX = "";
132    public static final String PERSONS_URI_KEY = "annotationmanager.uris.persons";
133
134    /**
135     * prefix to create uris for groups in store.
136     */
137    public static String GROUPS_URI_PREFIX = ""; 
138    public static final String GROUPS_URI_KEY = "annotationmanager.uris.groups";
139
140    public static final String ANNOTATIONS_URI_KEY = "annotationmanager.uris.annotations";
141
142
143    /* (non-Javadoc)
144     * @see org.restlet.Application#start()
145     */
146    @Override
147    public synchronized void start() throws Exception {
148        configure(getContext());
149        super.start();
150    }
151
152    /**
153     * Configures the restlet.
154     * Reads serverConfig, consumerKeys and graphDb config from config files and starts graphDb.
155     * Uses config from webapp context if already initialized.
156     * @param context
157     */
158    protected void configure(Context context) {
159        ConcurrentMap<String, Object> attrs = context.getAttributes();
160        ServletContext sc = (ServletContext) attrs.get("org.restlet.ext.servlet.ServletContext");
161        if (sc != null) {
162           logger.info(getVersion() + " starting...");
163
164            /*
165             * read config from webapp
166             */
167            serverConfig = (Properties) sc.getAttribute(SERVERCONFIG_KEY);
168            if (serverConfig == null) {
169                serverConfig = new Properties();
170                InputStream ps = getResourceAsStream(sc, CONFIG_PROPS_PATH);
171                if (ps != null) {
172                    logger.fine("loading config from " + CONFIG_PROPS_PATH);
173                    try {
174                        serverConfig.load(ps);
175                        /*
176                         * read serverconfig options
177                         */
178                        graphdbPath = serverConfig.getProperty(GRAPHDB_PATH_KEY, graphdbPath);
179                        ldapServerUrl = serverConfig.getProperty(LDAP_SERVER_KEY, null);
180                        webappUriPrefix = serverConfig.getProperty(WEBAPP_PREFIX, null);
181                        /*
182                         * uri prefixes
183                         */
184                        if (serverConfig.containsKey(PERSONS_URI_KEY)) {
185                            BaseRestlet.PERSONS_URI_PREFIX = serverConfig.getProperty(PERSONS_URI_KEY);
186                        }
187                        if (serverConfig.containsKey(GROUPS_URI_KEY)) {
188                            BaseRestlet.GROUPS_URI_PREFIX = serverConfig.getProperty(GROUPS_URI_KEY);
189                        }
190                        if (serverConfig.containsKey(TAGS_URI_KEY)) {
191                            BaseRestlet.TAGS_URI_PREFIX = serverConfig.getProperty(TAGS_URI_KEY);
192                        }
193                        if (serverConfig.containsKey(ANNOTATIONS_URI_KEY)) {
194                            AnnotationStore.ANNOTATION_URI_PREFIX = serverConfig.getProperty(ANNOTATIONS_URI_KEY);
195                        }
196                    } catch (IOException e) {
197                        logger.warning("Error loading server config: "+e.toString());
198                    }
199                    logger.fine("config: " + serverConfig);
200                } else {
201                    logger.severe("Unable to get resource " + CONFIG_PROPS_PATH);
202                }
203                // store config
204                sc.setAttribute(SERVERCONFIG_KEY, serverConfig);
205            }
206            // look for database service in context
207            graphDb = (GraphDatabaseService) sc.getAttribute(GRAPHDB_KEY);
208            if (graphDb == null) {
209                /*
210                 * open database
211                 */
212                String dbFn = getResourcePath(sc, graphdbPath);
213                if (dbFn != null) {
214                    logger.fine("opening DB " + dbFn);
215                    GraphDatabaseBuilder graphDbBuilder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(dbFn);
216                    graphDbBuilder.setConfig(GraphDatabaseSettings.allow_store_upgrade, "true");
217                    graphDb = graphDbBuilder.newGraphDatabase();
218                    registerShutdownHook(graphDb);
219                    // store in context
220                    sc.setAttribute(GRAPHDB_KEY, graphDb);
221                    // AnnotationStore
222                    store = new AnnotationStore(graphDb);
223                    sc.setAttribute(ANNSTORE_KEY, store);
224                    // admin server
225                    srv = new WrappingNeoServerBootstrapper((GraphDatabaseAPI) graphDb);
226                    logger.fine("Starting DB admin server...");
227                    // store in context
228                    sc.setAttribute(GRAPHDBSRV_KEY, srv);
229                    srv.start();
230                } else {
231                    logger.severe("Unable to get resource " + dbFn);
232                }
233            } else {
234                // get existing AnnotationStore
235                store = (AnnotationStore) sc.getAttribute(ANNSTORE_KEY);
236            }
237            /*
238             * read consumerKeys from webapp
239             */
240            consumerKeys = (Properties) sc.getAttribute(CONSUMERKEYS_KEY);
241            if (consumerKeys == null) {
242                consumerKeys = new Properties();
243                InputStream ps = getResourceAsStream(sc, CONSUMER_KEYS_PATH);
244                if (ps != null) {
245                    logger.fine("loading consumer keys from " + CONSUMER_KEYS_PATH);
246                    try {
247                        consumerKeys.load(ps);
248                    } catch (IOException e) {
249                        logger.fine("Error loading consumer keys: "+e);
250                    }
251                    logger.fine("consumer keys: " + consumerKeys);
252                } else {
253                    logger.severe("Unable to get resource " + CONSUMER_KEYS_PATH);
254                }
255                // store config
256                sc.setAttribute(CONSUMERKEYS_KEY, consumerKeys);
257            }
258        } else {
259            logger.severe("Unable to get ServletContext!");
260        }
261    }
262
263    public abstract String getVersion();
264
265    /**
266     * @return the authorizationMode
267     */
268    public boolean isAuthorizationMode() {
269        return authorizationMode;
270    }
271
272    /**
273     * @return the store
274     */
275    public AnnotationStore getAnnotationStore() {
276        return store;
277    }
278
279    /**
280     * returns consumer secret for consumer key. returns null if consumer key
281     * doesn't exist.
282     *
283     * @param consumerKey
284     * @return
285     */
286    public String getConsumerSecret(String consumerKey) {
287        return consumerKeys.getProperty(consumerKey);
288    }
289
290    /**
291     * Return the full name (String) of the person with the given user-id.
292     *
293     * Contacts a naming service (currently LDAP).
294     *
295     * @param userId
296     * @return full-name
297     */
298    public String getFullNameForId(String userId) {
299        return getFullNameFromLdap(userId);
300    }   
301   
302    /**
303     * Hole den vollen Benutzernamen aus dem LDAP
304     *
305     * @param creator
306     * @return
307     */
308    public String getFullNameFromLdap(String creator) {
309        String retString = creator; // falls nichts gefunden wird einfach den
310                                    // creator zurueckgeben
311        if (ldapServerUrl == null) {
312            return retString;
313        }
314        Hashtable<String, String> env = new Hashtable<String, String>();
315        String sp = "com.sun.jndi.ldap.LdapCtxFactory";
316        env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, sp);
317        env.put(javax.naming.Context.PROVIDER_URL, ldapServerUrl);
318
319        DirContext dctx;
320        try {
321            dctx = new InitialDirContext(env);
322        } catch (NamingException e) {
323            logger.warning("Error in getFullNameFromLDAP! "+e);
324            return retString;
325        }
326
327        String base = "ou=people";
328
329        SearchControls sc = new SearchControls();
330        String[] attributeFilter = { "cn", "mail" };
331        sc.setReturningAttributes(attributeFilter);
332        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
333
334        String filter = "(uid=" + creator + ")";
335
336        try {
337            NamingEnumeration<SearchResult> results = dctx.search(base, filter, sc);
338            while (results.hasMore()) {
339                SearchResult sr = (SearchResult) results.next();
340                javax.naming.directory.Attributes attrs = sr.getAttributes();
341
342                Attribute attr = attrs.get("cn");
343                retString = (String) attr.get();
344            }
345        } catch (NamingException e) {
346            logger.warning("Error in getFullNameFromLDAP!"+e);
347        }
348
349        try {
350            dctx.close();
351        } catch (NamingException e) {
352            logger.warning("Error in getFullNameFromLDAP!"+e);
353        }
354        return retString;
355    }
356
357    /**
358     * returns resource from path as InputStream.
359     *
360     * Tries path in webapp first, then uses classpath loader.
361     * Relative paths in webapp start in /WEB-INF/.
362     *
363     * @param sc
364     * @param path
365     * @return
366     */
367    protected InputStream getResourceAsStream(ServletContext sc, String path) {
368        InputStream ps = null;
369        if (sc == null) {
370            // no servlet context -> use class loader
371            ps = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
372        } else {
373            // try path in webapp first
374            String webPath = path;
375            if (!webPath.startsWith("/")) {
376                // relative path in webapp starts in WEB-INF
377                webPath = "/WEB-INF/" + webPath;
378            }
379            ps = sc.getResourceAsStream(webPath);
380            if (ps == null) {
381                // try as file
382                File pf = new File(sc.getRealPath(webPath));
383                if (pf.canRead()) {
384                    logger.fine("trying file for: " + pf);
385                    try {
386                        ps = new FileInputStream(pf);
387                    } catch (FileNotFoundException e) {
388                        logger.severe(e.toString());
389                    }
390                } else {
391                    // use class loader
392                    ps = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);                   
393                }
394            }
395        }
396        return ps;
397    }
398
399    /**
400     * get a real file name for a web app file pathname.
401     *
402     * If filename starts with "/" its treated as absolute else the path is
403     * appended to the /WEB-INF/ directory in the web-app.
404     *
405     * @param filename
406     * @param sc
407     * @return
408     */
409    public static String getResourcePath(ServletContext sc, String filename) {
410        File f = new File(filename);
411        // is the filename absolute?
412        if (!f.isAbsolute() && sc != null) {
413            // relative path -> use getRealPath to resolve in webapp
414            filename = sc.getRealPath("/WEB-INF/" + filename);
415        }
416        return filename;
417    }
418
419    /*
420     * (non-Javadoc)
421     *
422     * @see org.restlet.Application#stop()
423     */
424    @Override
425    public synchronized void stop() throws Exception {
426        /*
427         * trying to clean up databases, not sure if this is the right way...
428         */
429        if (srv != null) {
430            logger.info("Stopping DB admin server...");
431            srv.stop();
432            srv = null;
433        }
434        if (graphDb != null) {
435            logger.info("Stopping DB...");
436            graphDb.shutdown();
437            graphDb = null;
438        }
439        super.stop();
440    }
441
442    private static void registerShutdownHook(final GraphDatabaseService graphDb) {
443        // Registers a shutdown hook for the Neo4j instance so that it
444        // shuts down nicely when the VM exits (even if you "Ctrl-C" the
445        // running example before it's completed)
446        Runtime.getRuntime().addShutdownHook(new Thread() {
447            @Override
448            public void run() {
449                graphDb.shutdown();
450            }
451        });
452    }
453
454}
Note: See TracBrowser for help on using the repository browser.