From e62ce882045052e41e3f907d5f7627b2dac536d6 Mon Sep 17 00:00:00 2001
From: Rick Herrick <jrherrick@wustl.edu>
Date: Fri, 22 Jul 2016 17:37:20 -0500
Subject: [PATCH] XNAT-2429 Workaround for bean loading issue: extension bean
 aggregates all extension instances, letting Spring manage the "beans of type"
 problem.

---
 .../xnat/configuration/ApplicationConfig.java | 12 ++++++
 .../org/nrg/xnat/configuration/WebConfig.java |  8 ++--
 .../org/nrg/xnat/restlet/XNATApplication.java | 21 +++++-----
 .../xnat/restlet/XnatRestletExtensions.java   | 21 ++++++----
 .../restlet/XnatRestletExtensionsBean.java    | 39 +++++++++++++++++++
 5 files changed, 80 insertions(+), 21 deletions(-)
 create mode 100644 src/main/java/org/nrg/xnat/restlet/XnatRestletExtensionsBean.java

diff --git a/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java b/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
index f618b49c..8d3a1e5d 100644
--- a/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
+++ b/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
@@ -14,7 +14,9 @@ import org.nrg.xdat.services.ThemeService;
 import org.nrg.xdat.services.impl.ThemeServiceImpl;
 import org.nrg.xnat.initialization.InitializingTask;
 import org.nrg.xnat.initialization.InitializingTasksExecutor;
+import org.nrg.xnat.restlet.XnatRestlet;
 import org.nrg.xnat.restlet.XnatRestletExtensions;
+import org.nrg.xnat.restlet.XnatRestletExtensionsBean;
 import org.nrg.xnat.restlet.actions.importer.ImporterHandlerPackages;
 import org.nrg.xnat.services.PETTracerUtils;
 import org.nrg.xnat.utils.XnatUserProvider;
@@ -97,11 +99,21 @@ public class ApplicationConfig {
         return new XnatUserProvider(preferences.getReceivedFileUser());
     }
 
+    @Bean
+    public XnatRestletExtensionsBean xnatRestletExtensionsBean(final List<XnatRestletExtensions> extensions) {
+        return new XnatRestletExtensionsBean(extensions);
+    }
+
     @Bean
     public XnatRestletExtensions defaultXnatRestletExtensions() {
         return new XnatRestletExtensions(new HashSet<>(Arrays.asList(new String[] {"org.nrg.xnat.restlet.extensions"})));
     }
 
+    @Bean
+    public XnatRestletExtensions extraXnatRestletExtensions() {
+        return new XnatRestletExtensions(new HashSet<>(Arrays.asList(new String[] {"org.nrg.xnat.restlet.actions"})));
+    }
+
     @Bean
     public ImporterHandlerPackages importerHandlerPackages() {
         return new ImporterHandlerPackages(new HashSet<>(Arrays.asList(new String[] {"org.nrg.xnat.restlet.actions", "org.nrg.xnat.archive"})));
diff --git a/src/main/java/org/nrg/xnat/configuration/WebConfig.java b/src/main/java/org/nrg/xnat/configuration/WebConfig.java
index 4bc2cdc4..2829c778 100644
--- a/src/main/java/org/nrg/xnat/configuration/WebConfig.java
+++ b/src/main/java/org/nrg/xnat/configuration/WebConfig.java
@@ -9,7 +9,7 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
-import org.springframework.context.support.ResourceBundleMessageSource;
+import org.springframework.context.support.ReloadableResourceBundleMessageSource;
 import org.springframework.web.multipart.MultipartResolver;
 import org.springframework.web.multipart.support.StandardServletMultipartResolver;
 import org.springframework.web.servlet.ViewResolver;
@@ -59,8 +59,8 @@ public class WebConfig extends WebMvcConfigurerAdapter {
 
     @Bean
     public MessageSource messageSource() {
-        return new ResourceBundleMessageSource() {{
-            setBasename("org/nrg/xnat/messages/system.properties");
+        return new ReloadableResourceBundleMessageSource() {{
+            setBasename("classpath:org/nrg/xnat/messages/system");
         }};
     }
 
@@ -71,6 +71,8 @@ public class WebConfig extends WebMvcConfigurerAdapter {
     }
 
     private ApiInfo apiInfo() {
+        // TODO: The deprecated class is ApiInfo(). There's no documentation on how to use the replacement Contact class instead, so migrate this when that's explained.
+        //noinspection deprecation
         return new ApiInfo("XNAT REST API", "The XNAT REST API (XAPI) functions provide access to XNAT internal functions for remote clients.", "1.7.0", "http://www.xnat.org", "info@xnat.org", "Simplified 2-Clause BSD", "API license URL");
     }
 
diff --git a/src/main/java/org/nrg/xnat/restlet/XNATApplication.java b/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
index fc54abf4..32913dc4 100755
--- a/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
+++ b/src/main/java/org/nrg/xnat/restlet/XNATApplication.java
@@ -46,10 +46,10 @@ public class XNATApplication extends Application {
     public static final String PREARC_PROJECT_URI = "/prearchive/projects/{PROJECT_ID}";
     public static final String PREARC_SESSION_URI = PREARC_PROJECT_URI + "/{SESSION_TIMESTAMP}/{SESSION_LABEL}";
 
+    @SuppressWarnings("WeakerAccess")
     @JsonIgnore
     public XNATApplication(Context parentContext) {
         super(parentContext);
-
     }
 
     @Override
@@ -364,19 +364,18 @@ public class XNATApplication extends Application {
      * @param router The URL router for the restlet servlet.
      * @return A list of classes that should be attached unprotected, i.e. publicly accessible.
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked", "Duplicates"})
     private List<Class<? extends Resource>> addExtensionRoutes(Router router) {
-        final Set<String> packages = new HashSet<>();
-        final Map<String, XnatRestletExtensions> pkgLists = XDAT.getContextService().getBeansOfType(XnatRestletExtensions.class);
-        if (pkgLists.size() == 0) {
-            final XnatRestletExtensions extensions = XDAT.getContextService().getBean("defaultXnatRestletExtensions", XnatRestletExtensions.class);
-            if (extensions != null) {
-                pkgLists.put("defaultXnatRestletExtensions", extensions);
+        final Set<String>               packages   = new HashSet<>();
+        final XnatRestletExtensionsBean extensions = XDAT.getContextService().getBean(XnatRestletExtensionsBean.class);
+        if (extensions.size() > 0) {
+            packages.addAll(extensions.getPackages());
+        } else {
+            final XnatRestletExtensions extension = XDAT.getContextService().getBean("defaultXnatRestletExtensions", XnatRestletExtensions.class);
+            if (extension != null) {
+                packages.addAll(extension.getPackages());
             }
         }
-        for (XnatRestletExtensions pkgList : pkgLists.values()) {
-            packages.addAll(pkgList);
-        }
         if (packages.size() == 0) {
             packages.add("org.nrg.xnat.restlet.extensions");
         }
diff --git a/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensions.java b/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensions.java
index c583e55f..cf51a588 100644
--- a/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensions.java
+++ b/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensions.java
@@ -12,16 +12,23 @@
 
 package org.nrg.xnat.restlet;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
-public class XnatRestletExtensions extends HashSet<String> {
-    public XnatRestletExtensions(Set<String> packages) {
-       super();
-       this.setPackages(packages);
+public class XnatRestletExtensions {
+    public XnatRestletExtensions(final Set<String> packages) {
+        super();
+        _packages.addAll(packages);
     }
-    public void setPackages(Set<String> packages) {
-        clear();
-        addAll(packages);
+
+    public int size() {
+        return _packages.size();
+    }
+
+    public Set<String> getPackages() {
+        return Collections.unmodifiableSet(_packages);
     }
+
+    private final Set<String> _packages = new HashSet<>();
 }
diff --git a/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensionsBean.java b/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensionsBean.java
new file mode 100644
index 00000000..64963b6d
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/restlet/XnatRestletExtensionsBean.java
@@ -0,0 +1,39 @@
+/*
+ * org.nrg.xnat.restlet.XnatRestletExtensionList
+ *
+ * Copyright (c) 2016, Washington University School of Medicine
+ * All Rights Reserved
+ *
+ * XNAT is an open-source project of the Neuroinformatics Research Group.
+ * Released under the Simplified BSD.
+ *
+ * Last modified 1/19/16 3:49 PM
+ */
+
+package org.nrg.xnat.restlet;
+
+import org.springframework.stereotype.Component;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Component
+public class XnatRestletExtensionsBean {
+    public XnatRestletExtensionsBean(final List<XnatRestletExtensions> extensions) {
+        for (final XnatRestletExtensions extension : extensions) {
+            _packages.addAll(extension.getPackages());
+        }
+    }
+
+    public int size() {
+        return _packages.size();
+    }
+
+    public Set<String> getPackages() {
+        return Collections.unmodifiableSet(_packages);
+    }
+
+    private final Set<String> _packages = new HashSet<>();
+}
-- 
GitLab