source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/BaseRestlet.java @ 89:247cbbb385de

Last change on this file since 89:247cbbb385de was 89:247cbbb385de, checked in by casties, 9 years ago

improved logging.

File size: 15.7 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 to create uris for tags in store.
118     */
119    public static String TAGS_URI_PREFIX = "";
120    public static final String TAGS_URI_KEY = "annotationmanager.uris.tags";
121
122    /**
123     * prefix to create uris for persons in store.
124     */
125    public static String PERSONS_URI_PREFIX = "";
126    public static final String PERSONS_URI_KEY = "annotationmanager.uris.persons";
127
128    /**
129     * prefix to create uris for groups in store.
130     */
131    public static String GROUPS_URI_PREFIX = ""; 
132    public static final String GROUPS_URI_KEY = "annotationmanager.uris.groups";
133
134    public static final String ANNOTATIONS_URI_KEY = "annotationmanager.uris.annotations";
135
136
137    /* (non-Javadoc)
138     * @see org.restlet.Application#start()
139     */
140    @Override
141    public synchronized void start() throws Exception {
142        configure(getContext());
143        super.start();
144    }
145
146    /**
147     * Configures the restlet.
148     * Reads serverConfig, consumerKeys and graphDb config from config files and starts graphDb.
149     * Uses config from webapp context if already initialized.
150     * @param context
151     */
152    protected void configure(Context context) {
153        ConcurrentMap<String, Object> attrs = context.getAttributes();
154        ServletContext sc = (ServletContext) attrs.get("org.restlet.ext.servlet.ServletContext");
155        if (sc != null) {
156           logger.info(getVersion() + " starting...");
157
158            /*
159             * read config from webapp
160             */
161            serverConfig = (Properties) sc.getAttribute(SERVERCONFIG_KEY);
162            if (serverConfig == null) {
163                serverConfig = new Properties();
164                InputStream ps = getResourceAsStream(sc, CONFIG_PROPS_PATH);
165                if (ps != null) {
166                    logger.fine("loading config from " + CONFIG_PROPS_PATH);
167                    try {
168                        serverConfig.load(ps);
169                        /*
170                         * read serverconfig options
171                         */
172                        graphdbPath = serverConfig.getProperty(GRAPHDB_PATH_KEY, graphdbPath);
173                        ldapServerUrl = serverConfig.getProperty(LDAP_SERVER_KEY, null);
174                        /*
175                         * uri prefixes
176                         */
177                        if (serverConfig.containsKey(PERSONS_URI_KEY)) {
178                            BaseRestlet.PERSONS_URI_PREFIX = serverConfig.getProperty(PERSONS_URI_KEY);
179                        }
180                        if (serverConfig.containsKey(GROUPS_URI_KEY)) {
181                            BaseRestlet.GROUPS_URI_PREFIX = serverConfig.getProperty(GROUPS_URI_KEY);
182                        }
183                        if (serverConfig.containsKey(TAGS_URI_KEY)) {
184                            BaseRestlet.TAGS_URI_PREFIX = serverConfig.getProperty(TAGS_URI_KEY);
185                        }
186                        if (serverConfig.containsKey(ANNOTATIONS_URI_KEY)) {
187                            AnnotationStore.ANNOTATION_URI_PREFIX = serverConfig.getProperty(ANNOTATIONS_URI_KEY);
188                        }
189                    } catch (IOException e) {
190                        logger.warning("Error loading server config: "+e.toString());
191                    }
192                    logger.fine("config: " + serverConfig);
193                } else {
194                    logger.severe("Unable to get resource " + CONFIG_PROPS_PATH);
195                }
196                // store config
197                sc.setAttribute(SERVERCONFIG_KEY, serverConfig);
198            }
199            // look for database service in context
200            graphDb = (GraphDatabaseService) sc.getAttribute(GRAPHDB_KEY);
201            if (graphDb == null) {
202                /*
203                 * open database
204                 */
205                String dbFn = getResourcePath(sc, graphdbPath);
206                if (dbFn != null) {
207                    logger.fine("opening DB " + dbFn);
208                    GraphDatabaseBuilder graphDbBuilder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(dbFn);
209                    graphDbBuilder.setConfig(GraphDatabaseSettings.allow_store_upgrade, "true");
210                    graphDb = graphDbBuilder.newGraphDatabase();
211                    registerShutdownHook(graphDb);
212                    // store in context
213                    sc.setAttribute(GRAPHDB_KEY, graphDb);
214                    // AnnotationStore
215                    store = new AnnotationStore(graphDb);
216                    sc.setAttribute(ANNSTORE_KEY, store);
217                    // admin server
218                    srv = new WrappingNeoServerBootstrapper((GraphDatabaseAPI) graphDb);
219                    logger.fine("Starting DB admin server...");
220                    // store in context
221                    sc.setAttribute(GRAPHDBSRV_KEY, srv);
222                    srv.start();
223                } else {
224                    logger.severe("Unable to get resource " + dbFn);
225                }
226            } else {
227                // get existing AnnotationStore
228                store = (AnnotationStore) sc.getAttribute(ANNSTORE_KEY);
229            }
230            /*
231             * read consumerKeys from webapp
232             */
233            consumerKeys = (Properties) sc.getAttribute(CONSUMERKEYS_KEY);
234            if (consumerKeys == null) {
235                consumerKeys = new Properties();
236                InputStream ps = getResourceAsStream(sc, CONSUMER_KEYS_PATH);
237                if (ps != null) {
238                    logger.fine("loading consumer keys from " + CONSUMER_KEYS_PATH);
239                    try {
240                        consumerKeys.load(ps);
241                    } catch (IOException e) {
242                        logger.fine("Error loading consumer keys: "+e);
243                    }
244                    logger.fine("consumer keys: " + consumerKeys);
245                } else {
246                    logger.severe("Unable to get resource " + CONSUMER_KEYS_PATH);
247                }
248                // store config
249                sc.setAttribute(CONSUMERKEYS_KEY, consumerKeys);
250            }
251        } else {
252            logger.severe("Unable to get ServletContext!");
253        }
254    }
255
256    public abstract String getVersion();
257
258    /**
259     * @return the authorizationMode
260     */
261    public boolean isAuthorizationMode() {
262        return authorizationMode;
263    }
264
265    /**
266     * @return the store
267     */
268    public AnnotationStore getAnnotationStore() {
269        return store;
270    }
271
272    /**
273     * returns consumer secret for consumer key. returns null if consumer key
274     * doesn't exist.
275     *
276     * @param consumerKey
277     * @return
278     */
279    public String getConsumerSecret(String consumerKey) {
280        return consumerKeys.getProperty(consumerKey);
281    }
282
283    /**
284     * Return the full name (String) of the person with the given user-id.
285     *
286     * Contacts a naming service (currently LDAP).
287     *
288     * @param userId
289     * @return full-name
290     */
291    public String getFullNameForId(String userId) {
292        return getFullNameFromLdap(userId);
293    }   
294   
295    /**
296     * Hole den vollen Benutzernamen aus dem LDAP
297     *
298     * @param creator
299     * @return
300     */
301    public String getFullNameFromLdap(String creator) {
302        String retString = creator; // falls nichts gefunden wird einfach den
303                                    // creator zurueckgeben
304        if (ldapServerUrl == null) {
305            return retString;
306        }
307        Hashtable<String, String> env = new Hashtable<String, String>();
308        String sp = "com.sun.jndi.ldap.LdapCtxFactory";
309        env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, sp);
310        env.put(javax.naming.Context.PROVIDER_URL, ldapServerUrl);
311
312        DirContext dctx;
313        try {
314            dctx = new InitialDirContext(env);
315        } catch (NamingException e) {
316            logger.warning("Error in getFullNameFromLDAP! "+e);
317            return retString;
318        }
319
320        String base = "ou=people";
321
322        SearchControls sc = new SearchControls();
323        String[] attributeFilter = { "cn", "mail" };
324        sc.setReturningAttributes(attributeFilter);
325        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
326
327        String filter = "(uid=" + creator + ")";
328
329        try {
330            NamingEnumeration<SearchResult> results = dctx.search(base, filter, sc);
331            while (results.hasMore()) {
332                SearchResult sr = (SearchResult) results.next();
333                javax.naming.directory.Attributes attrs = sr.getAttributes();
334
335                Attribute attr = attrs.get("cn");
336                retString = (String) attr.get();
337            }
338        } catch (NamingException e) {
339            logger.warning("Error in getFullNameFromLDAP!"+e);
340        }
341
342        try {
343            dctx.close();
344        } catch (NamingException e) {
345            logger.warning("Error in getFullNameFromLDAP!"+e);
346        }
347        return retString;
348    }
349
350    /**
351     * returns resource from path as InputStream.
352     *
353     * Tries path in webapp first, then uses classpath loader.
354     * Relative paths in webapp start in /WEB-INF/.
355     *
356     * @param sc
357     * @param path
358     * @return
359     */
360    protected InputStream getResourceAsStream(ServletContext sc, String path) {
361        InputStream ps = null;
362        if (sc == null) {
363            // no servlet context -> use class loader
364            ps = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
365        } else {
366            // try path in webapp first
367            String webPath = path;
368            if (!webPath.startsWith("/")) {
369                // relative path in webapp starts in WEB-INF
370                webPath = "/WEB-INF/" + webPath;
371            }
372            ps = sc.getResourceAsStream(webPath);
373            if (ps == null) {
374                // try as file
375                File pf = new File(sc.getRealPath(webPath));
376                if (pf.canRead()) {
377                    logger.fine("trying file for: " + pf);
378                    try {
379                        ps = new FileInputStream(pf);
380                    } catch (FileNotFoundException e) {
381                        logger.severe(e.toString());
382                    }
383                } else {
384                    // use class loader
385                    ps = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);                   
386                }
387            }
388        }
389        return ps;
390    }
391
392    /**
393     * get a real file name for a web app file pathname.
394     *
395     * If filename starts with "/" its treated as absolute else the path is
396     * appended to the /WEB-INF/ directory in the web-app.
397     *
398     * @param filename
399     * @param sc
400     * @return
401     */
402    public static String getResourcePath(ServletContext sc, String filename) {
403        File f = new File(filename);
404        // is the filename absolute?
405        if (!f.isAbsolute() && sc != null) {
406            // relative path -> use getRealPath to resolve in webapp
407            filename = sc.getRealPath("/WEB-INF/" + filename);
408        }
409        return filename;
410    }
411
412    /*
413     * (non-Javadoc)
414     *
415     * @see org.restlet.Application#stop()
416     */
417    @Override
418    public synchronized void stop() throws Exception {
419        /*
420         * trying to clean up databases, not sure if this is the right way...
421         */
422        if (srv != null) {
423            logger.info("Stopping DB admin server...");
424            srv.stop();
425            srv = null;
426        }
427        if (graphDb != null) {
428            logger.info("Stopping DB...");
429            graphDb.shutdown();
430            graphDb = null;
431        }
432        super.stop();
433    }
434
435    private static void registerShutdownHook(final GraphDatabaseService graphDb) {
436        // Registers a shutdown hook for the Neo4j instance so that it
437        // shuts down nicely when the VM exits (even if you "Ctrl-C" the
438        // running example before it's completed)
439        Runtime.getRuntime().addShutdownHook(new Thread() {
440            @Override
441            public void run() {
442                graphDb.shutdown();
443            }
444        });
445    }
446
447}
Note: See TracBrowser for help on using the repository browser.