changeset 562:05caf2e731d0

Allow to add additional restful services via configuration.
author gernotbelger
date Wed, 10 Oct 2018 20:07:58 +0200
parents 1c2ce0501305
children 8d11d6a17f3b
files artifact-database/pom.xml artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java
diffstat 7 files changed, 134 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/artifact-database/pom.xml	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/pom.xml	Wed Oct 10 20:07:58 2018 +0200
@@ -91,5 +91,10 @@
         <artifactId>jetty</artifactId>
         <version>6.1.26</version>
     </dependency>
+    <dependency>
+      <groupId>org.restlet.jse</groupId>
+      <artifactId>org.restlet.ext.httpclient</artifactId>
+      <version>2.0.7</version>
+    </dependency>
   </dependencies>
 </project>
--- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java	Wed Oct 10 20:07:58 2018 +0200
@@ -407,6 +407,8 @@
      */
     protected HashMap     name2service;
 
+    private Map<String, Class<?>> restServices;
+
     /**
      * The factory that is used to create new artifact collections.
      */
@@ -464,6 +466,8 @@
 
     protected List<LifetimeListener> lifetimeListeners;
 
+    private String serverAddress;
+
     /**
      * Default constructor.
      */
@@ -493,10 +497,13 @@
 
         backgroundIds  = new HashSet<Integer>();
         backgroundMsgs = new HashMap<String, LinkedList<Message>>();
+        
+        this.serverAddress = bootstrap.getHTTPServer().getServerAddress();
 
         setupArtifactCollectionFactory(bootstrap);
         setupArtifactFactories(bootstrap);
         setupServices(bootstrap);
+        setupRestServices(bootstrap);
         setupUserFactory(bootstrap);
         setupCallContextListener(bootstrap);
         setupHooks(bootstrap);
@@ -638,6 +645,17 @@
     }
 
     /**
+     * Used to extract the service factories from the bootstrap
+     * parameters, setting up the services and building the internal
+     * lookup tables.
+     * @param bootstrap The bootstrap parameters.
+     */
+    private void setupRestServices(FactoryBootstrap bootstrap) {
+        
+        restServices  = new HashMap<String,Class<?>>(bootstrap.getRestServiceNames());
+    }
+
+    /**
      * Wires a storage backend to this artifact database and
      * establishes a callback to be able to revive artifacts
      * via the serializers of this artifact factories.
@@ -1984,5 +2002,15 @@
     public String findArtifactUser(final String artifactIdentifier) {
         return backend.findUserName(artifactIdentifier);
     }
+    
+    @Override
+    public String getServerAddress() {
+        return this.serverAddress;
+    }
+
+    @Override
+    public Map<String, Class<?>> getRestServices() {
+        return restServices;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java	Wed Oct 10 20:07:58 2018 +0200
@@ -20,11 +20,12 @@
 import org.dive4elements.artifacts.UserFactory;
 
 import org.dive4elements.artifacts.common.utils.StringUtils;
-
 import org.dive4elements.artifactdatabase.rest.HTTPServer;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 
@@ -70,6 +71,13 @@
         "/artifact-database/factories/service-factories/service-factory";
 
     /**
+     * XPath to figure out the names of the addtional restful services from
+     * the global configuration.
+     */
+    public static final String RESTFUL_SERVICES =
+            "/artifact-database/factories/restful-services/restful-service";
+
+    /**
      * XPath to figure out the class name of the user factory from global
      * configuration.
      */
@@ -144,6 +152,8 @@
      * artifact database.
      */
     protected ArtifactFactory [] artifactFactories;
+    
+    private Map<String, Class<?>> restServices;
 
     /**
      * List of service factories which creates services that are
@@ -361,6 +371,40 @@
             new ServiceFactory[loadedFactories.size()]);
     }
 
+    /**
+     * Scans the global configuration for the configured service factories
+     * and sets them up.
+     */
+    private void loadRestfulServices() {
+        
+        logger.info("loading additional restful services");
+        
+        restServices = new HashMap<String, Class<?>>();
+        
+        final NodeList nodes = Config.getNodeSetXPath(RESTFUL_SERVICES);
+        
+        if (nodes == null)
+            return;
+        
+        for (int i = 0; i < nodes.getLength(); ++i) {
+            
+            final Node node = nodes.item(i);
+            
+            final String className = Config.getStringXPath( node, "@class");
+            final String path = Config.getStringXPath( node, "@path");
+
+            try {
+                final Class<?> clazz = Class.forName(className);
+                restServices.put(path, clazz);
+            }
+            catch (final ClassNotFoundException cnfe) {
+                logger.error(cnfe.getLocalizedMessage(), cnfe);
+            }
+            catch (final ClassCastException cce) {
+                logger.error(cce.getLocalizedMessage(), cce);
+            }
+        }
+    }
 
     /**
      * Scans the global configuration for the configured user factory.
@@ -638,6 +682,7 @@
         loadCollectionFactory();
         loadArtifactFactories();
         loadServiceFactories();
+        loadRestfulServices();
         loadUserFactory();
         loadCallContextListener();
         loadHTTPServer();
@@ -729,5 +774,9 @@
     public List<BackendListener> getBackendListeners() {
         return backendListeners;
     }
+
+    public Map<String,Class<?>> getRestServiceNames() {
+        return restServices;
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java	Wed Oct 10 20:07:58 2018 +0200
@@ -1,13 +1,13 @@
 package org.dive4elements.artifactdatabase.rest;
 
+import org.dive4elements.artifacts.ArtifactDatabase;
 import org.w3c.dom.Document;
 
-import org.dive4elements.artifacts.ArtifactDatabase;
-
 public interface HTTPServer
 {
     void setup(Document document);
 
     void startAsServer(ArtifactDatabase database);
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+
+    String getServerAddress();
+}
\ No newline at end of file
--- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java	Wed Oct 10 20:07:58 2018 +0200
@@ -8,14 +8,14 @@
 
 package org.dive4elements.artifactdatabase.rest;
 
-import org.dive4elements.artifacts.ArtifactDatabase;
-
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentMap;
 
+import org.dive4elements.artifacts.ArtifactDatabase;
 import org.restlet.Application;
 import org.restlet.Context;
 import org.restlet.Restlet;
-
 import org.restlet.routing.Router;
 
 /**
@@ -25,32 +25,21 @@
  *
  * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
  */
-public class RestApp
-extends      Application
-{
+public class RestApp extends Application {
+
     /**
      * The central artifact database instance to work with.
      */
-    protected ArtifactDatabase database;
-
-    /**
-     * Default constructor
-     */
-    public RestApp() {
-    }
-
-    public RestApp(Context context, ArtifactDatabase database) {
-        super(context);
-        this.database = database;
-    }
+    private final ArtifactDatabase database;
 
     /**
      * Constructor to create REST appliction bound to a specific
      * artifact database.
      *
-     * @param database The artifact database to be used.
+     * @param database
+     *            The artifact database to be used.
      */
-    public RestApp(ArtifactDatabase database) {
+    public RestApp(final ArtifactDatabase database) {
         this.database = database;
     }
 
@@ -63,35 +52,35 @@
     @Override
     public Restlet createRoot() {
 
-        Context context = getContext();
-
-        ConcurrentMap map = context.getAttributes();
-        map.put("database", database);
+        final Context context = getContext();
 
-        Router router = new Router(context);
+        final ConcurrentMap<String, Object> map = context.getAttributes();
+        map.put("database", this.database);
 
-        router.attach(ServicesResource.PATH,    ServicesResource.class);
-        router.attach(ServiceResource.PATH,     ServiceResource.class);
-        router.attach(FactoriesResource.PATH,   FactoriesResource.class);
-        router.attach(CreateResource.PATH,      CreateResource.class);
-        router.attach(ArtifactResource.PATH,    ArtifactResource.class);
+        final Router router = new Router(context);
+
+        router.attach(ServicesResource.PATH, ServicesResource.class);
+        router.attach(ServiceResource.PATH, ServiceResource.class);
+        router.attach(FactoriesResource.PATH, FactoriesResource.class);
+        router.attach(CreateResource.PATH, CreateResource.class);
+        router.attach(ArtifactResource.PATH, ArtifactResource.class);
         router.attach(ArtifactOutResource.PATH, ArtifactOutResource.class);
-        router.attach(ExportResource.PATH,      ExportResource.class);
-        router.attach(ImportResource.PATH,      ImportResource.class);
-        router.attach(CreateUserResource.PATH,  CreateUserResource.class);
-        router.attach(ListUsersResource.PATH,   ListUsersResource.class);
-        router.attach(UserResource.PATH,        UserResource.class);
-        router.attach(FindUserResource.PATH,    FindUserResource.class);
-        router.attach(
-            CreateCollectionResource.PATH, CreateCollectionResource.class);
-        router.attach(
-            ListCollectionsResource.PATH, ListCollectionsResource.class);
-        router.attach(
-            CollectionResource.PATH, CollectionResource.class);
-        router.attach(
-            CollectionOutResource.PATH, CollectionOutResource.class);
+        router.attach(ExportResource.PATH, ExportResource.class);
+        router.attach(ImportResource.PATH, ImportResource.class);
+        router.attach(CreateUserResource.PATH, CreateUserResource.class);
+        router.attach(ListUsersResource.PATH, ListUsersResource.class);
+        router.attach(UserResource.PATH, UserResource.class);
+        router.attach(FindUserResource.PATH, FindUserResource.class);
+        router.attach(CreateCollectionResource.PATH, CreateCollectionResource.class);
+        router.attach(ListCollectionsResource.PATH, ListCollectionsResource.class);
+        router.attach(CollectionResource.PATH, CollectionResource.class);
+        router.attach(CollectionOutResource.PATH, CollectionOutResource.class);
+
+        /* register any additional services */
+        final Map<String, Class<?>> restServices = this.database.getRestServices();
+        for (final Entry<String, Class<?>> entry : restServices.entrySet())
+            router.attach(entry.getKey(), entry.getValue());
 
         return router;
     }
-}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
+}
\ No newline at end of file
--- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java	Wed Oct 10 20:07:58 2018 +0200
@@ -89,6 +89,12 @@
         listen     = XMLUtils.xpathString(document, LISTEN_INTERFACE, null);
         maxThreads = XMLUtils.xpathString(document, MAX_THREADS, null);
     }
+    
+    @Override
+    public String getServerAddress() {
+        String host = (this.listen == null || this.listen.trim().length() == 0 ) ? "localhost" : this.listen;
+        return String.format("http://%s:%d", host, this.port);
+    }
 
     protected Server createServer() {
         return listen != null && listen.length() > 0
--- a/artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java	Mon Sep 24 17:59:17 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java	Wed Oct 10 20:07:58 2018 +0200
@@ -14,6 +14,7 @@
 import org.w3c.dom.Document;
 
 import java.util.Date;
+import java.util.Map;
 
 /**
  * Interface of an artifact managing database.
@@ -296,5 +297,10 @@
         throws ArtifactDatabaseException;
 
     String findArtifactUser(String artifactIdentifier);
+
+    String getServerAddress();
+
+    /** an additional list of rest services (path and implementing class) that should be registered */
+    Map<String, Class<?>> getRestServices();
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org