This is an automated email from the ASF dual-hosted git repository.

iuliana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 5d6f0ea  make swagger classes extensible
     new b2f7806  Merge pull request #1149 from ahgittin/swagger-improvements
5d6f0ea is described below

commit 5d6f0ea87410715d71390f1d9e711fc5b5202b44
Author: Alex Heneveld <[email protected]>
AuthorDate: Mon Feb 15 14:57:55 2021 +0000

    make swagger classes extensible
    
    so add'l projects can add classes to be documented
---
 .../apache/brooklyn/camp/server/RestApiSetup.java  |  2 +-
 .../brooklyn/rest/resources/ApidocResource.java    | 26 ++++++++
 .../brooklyn/rest/util/ScannerInjectHelper.java    |  2 +-
 .../rest/resources/ApidocResourceTest.java         |  2 +-
 .../org/apache/brooklyn/rest/RestApiSetup.java     |  2 +-
 .../rest/apidoc/RestApiResourceScanner.java        | 74 ++++++++++++++++------
 6 files changed, 86 insertions(+), 22 deletions(-)

diff --git 
a/camp/camp-server/src/main/java/org/apache/brooklyn/camp/server/RestApiSetup.java
 
b/camp/camp-server/src/main/java/org/apache/brooklyn/camp/server/RestApiSetup.java
index 302dff8..ab94527 100644
--- 
a/camp/camp-server/src/main/java/org/apache/brooklyn/camp/server/RestApiSetup.java
+++ 
b/camp/camp-server/src/main/java/org/apache/brooklyn/camp/server/RestApiSetup.java
@@ -28,7 +28,7 @@ import io.swagger.config.ScannerFactory;
 public class RestApiSetup {
 
     public static void install(ServletContextHandler context) {
-        ScannerFactory.setScanner(new RestApiResourceScanner());
+        RestApiResourceScanner.install(null);
 
         CampRestApp app = new CampRestApp();
 
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApidocResource.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApidocResource.java
index 7372288..0be166f 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApidocResource.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApidocResource.java
@@ -19,10 +19,16 @@
 package org.apache.brooklyn.rest.resources;
 
 
+import javax.servlet.ServletConfig;
 import javax.ws.rs.Path;
 
 import io.swagger.annotations.Api;
 import io.swagger.jaxrs.listing.ApiListingResource;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.apache.brooklyn.rest.apidoc.RestApiResourceScanner;
 
 /**
  * @author Ciprian Ciubotariu <[email protected]>
@@ -31,4 +37,24 @@ import io.swagger.jaxrs.listing.ApiListingResource;
 @Path("/apidoc")
 public class ApidocResource extends ApiListingResource {
 
+    private void preprocess(Application app, ServletConfig sc) {
+        RestApiResourceScanner.rescanIfNeeded(() -> scan(app, sc));
+    }
+
+    @Override
+    public Response getListing(Application app, ServletConfig sc, HttpHeaders 
headers, UriInfo uriInfo, String type) {
+        preprocess(app, sc);
+        return super.getListing(app, sc, headers, uriInfo, type);
+    }
+
+    @Override
+    public Response getListingJson(Application app, ServletConfig sc, 
HttpHeaders headers, UriInfo uriInfo) {
+        return super.getListingJson(app, sc, headers, uriInfo);
+    }
+
+    @Override
+    public Response getListingYaml(Application app, ServletConfig sc, 
HttpHeaders headers, UriInfo uriInfo) {
+        return super.getListingYaml(app, sc, headers, uriInfo);
+    }
+
 }
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/ScannerInjectHelper.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/ScannerInjectHelper.java
index f8c224a..86202f5 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/ScannerInjectHelper.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/ScannerInjectHelper.java
@@ -22,6 +22,6 @@ import io.swagger.config.ScannerFactory;
 
 public class ScannerInjectHelper {
     public void setServer(JAXRSServerFactoryBean server) {
-        ScannerFactory.setScanner(new 
RestApiResourceScanner(server.getResourceClasses()));
+        RestApiResourceScanner.install(server.getResourceClasses());
     }
 }
diff --git 
a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApidocResourceTest.java
 
b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApidocResourceTest.java
index af09e67..7fde63a 100644
--- 
a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApidocResourceTest.java
+++ 
b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApidocResourceTest.java
@@ -56,7 +56,7 @@ public class ApidocResourceTest extends 
BrooklynRestResourceTest {
 
     @Override
     protected void addBrooklynResources() {
-        ScannerFactory.setScanner(new RestApiResourceScanner());
+        RestApiResourceScanner.install(null);
 
         for (Object o : BrooklynRestApi.getApidocResources()) {
             addResource(o);
diff --git 
a/rest/rest-server/src/main/java/org/apache/brooklyn/rest/RestApiSetup.java 
b/rest/rest-server/src/main/java/org/apache/brooklyn/rest/RestApiSetup.java
index 33bbfd3..52dd376 100644
--- a/rest/rest-server/src/main/java/org/apache/brooklyn/rest/RestApiSetup.java
+++ b/rest/rest-server/src/main/java/org/apache/brooklyn/rest/RestApiSetup.java
@@ -67,7 +67,7 @@ public class RestApiSetup {
     }
 
     public static void initSwagger() {
-        ScannerFactory.setScanner(new RestApiResourceScanner());
+        RestApiResourceScanner.install(null);
     }
 
 }
diff --git 
a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java
 
b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java
index e90aea0..83e56e0 100644
--- 
a/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java
+++ 
b/utils/rest-swagger/src/main/java/org/apache/brooklyn/rest/apidoc/RestApiResourceScanner.java
@@ -16,10 +16,9 @@
 package org.apache.brooklyn.rest.apidoc;
 
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import io.swagger.config.Scanner;
+import io.swagger.config.ScannerFactory;
+import java.util.*;
 
 import javax.servlet.ServletConfig;
 import javax.ws.rs.core.Application;
@@ -32,54 +31,74 @@ import io.swagger.models.Swagger;
 
 
 /**
+ * Scans resources for Swagger API resources. Makes them available to the 
Swagger scanner.
  * Much like DefaultJaxrsScanner, but looks at annotations of ancestors as 
well.
  *
  * For instance, if a resource implementation exposes an annotated interface,
  * that interface will be added as well.
  *
+ * Unfortunately the Swagger scanner is a static so this {@link 
#install(Collection)} expects static scope;
+ * it works out okay as we want all the resources from different bundles to be 
available in the API doc page.
+ * But it is a bit ugly.
+ *
+ * Swagger also caches things so, also unfortunately, we need to hack in to 
the ApiListing calls and
+ * {@link #rescanIfNeeded(Runnable)}.
  */
 public class RestApiResourceScanner extends AbstractScanner implements 
JaxrsScanner, SwaggerConfig {
 
-    private Set<Class<?>> apiClasses = null;
+    private boolean scannerDirty = true;
+
+    private final Set<Class<?>> globalClasses = new HashSet<>();
+
+    private final Map<Application,Set<Class<?>>> appCache = new 
WeakHashMap<>();
 
     public RestApiResourceScanner() {}
 
     public RestApiResourceScanner(Collection<Class<?>> resourceClasses) {
-        this.apiClasses = new HashSet<>();
-        addAnnotatedClasses(apiClasses, resourceClasses);
+        addAnnotatedClasses(globalClasses, resourceClasses);
+    }
+
+    private void addAnnotatedClasses(Collection<Class<?>> classes) {
+        addAnnotatedClasses(globalClasses, classes);
     }
 
     private void addAnnotatedClasses(Set<Class<?>> output, 
Collection<Class<?>> classes) {
-        for (Class<?> clz : classes) {
-            if (clz.getAnnotation(Api.class) != null) {
-                output.add(clz);
+        if (classes!=null) {
+            for (Class<?> clz : classes) {
+                if (clz.getAnnotation(Api.class) != null) {
+                    output.add(clz);
+                }
+                addAnnotatedClasses(output, 
Arrays.asList(clz.getInterfaces()));
             }
-            addAnnotatedClasses(output, Arrays.asList(clz.getInterfaces()));
         }
     }
 
-    private synchronized void buildApiClasses(Application app) {
-        if (apiClasses == null) {
-            apiClasses = new HashSet<>();
+    private synchronized Set<Class<?>> buildApiClasses(Application app) {
+        Set<Class<?>> cached = appCache.get(app);
+        if (cached == null) {
+            cached = new HashSet<>();
             if (app != null) {
                 Set<Class<?>> classes = app.getClasses();
                 if (classes != null) {
-                    addAnnotatedClasses(apiClasses, classes);
+                    addAnnotatedClasses(cached, classes);
                 }
                 Set<Object> singletons = app.getSingletons();
                 if (singletons != null) {
                     for (Object o : singletons) {
-                        addAnnotatedClasses(apiClasses, 
Arrays.<Class<?>>asList(o.getClass()));
+                        addAnnotatedClasses(cached, 
Arrays.<Class<?>>asList(o.getClass()));
                     }
                 }
             }
+            appCache.put(app, cached);
         }
+        return cached;
     }
 
     @Override
     public Set<Class<?>> classesFromContext(Application app, ServletConfig sc) 
{
-        buildApiClasses(app);
-        return apiClasses;
+        HashSet<Class<?>> all = new HashSet<>(globalClasses);
+        all.addAll(buildApiClasses(app));
+        return all;
     }
 
     @Override
@@ -98,4 +117,23 @@ public class RestApiResourceScanner extends AbstractScanner 
implements JaxrsScan
         return null;
     }
 
+    /** install this as the scanner which Swagger will use, with the given 
class also installed */
+    public static void install(Collection<Class<?>> resourceClasses) {
+        Scanner scanner = ScannerFactory.getScanner();
+        if (scanner instanceof RestApiResourceScanner) {
+            
((RestApiResourceScanner)scanner).addAnnotatedClasses(resourceClasses);
+        } else {
+            scanner = new RestApiResourceScanner(resourceClasses);
+        }
+        ScannerFactory.setScanner(scanner);
+        ((RestApiResourceScanner)ScannerFactory.getScanner()).scannerDirty = 
true;
+    }
+
+    public static void rescanIfNeeded(Runnable r) {
+        if (ScannerFactory.getScanner() instanceof RestApiResourceScanner && 
((RestApiResourceScanner)ScannerFactory.getScanner()).scannerDirty) {
+            r.run();
+            ((RestApiResourceScanner)ScannerFactory.getScanner()).scannerDirty 
= false;
+        }
+    }
+
 }

Reply via email to