source: AnnotationManagerN4J/src/main/java/de/mpiwg/itgroup/annotations/restlet/BaseRestlet.java @ 86:e3f0613b2f2d

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

renamed getFullname to make it configurable.
fixed Restlet at 2.2.3.

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