Author: ate
Date: Mon Sep  3 14:59:13 2012
New Revision: 1380262

URL: http://svn.apache.org/viewvc?rev=1380262&view=rev
Log:
RAVE-694: add support for dynamic mapping reloading, file config based only for 
now

Modified:
    
rave/sandbox/content-services/demo-portal/src/main/webapp/WEB-INF/dispatcher-servlet.xml
    
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigManager.java
    
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigUtils.java
    
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/FileConfigManager.java
    
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/JcrConfigManager.java
    
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/apache/rave/portal/web/hmvc/HmvcHandlerMethodMappingByConfig.java

Modified: 
rave/sandbox/content-services/demo-portal/src/main/webapp/WEB-INF/dispatcher-servlet.xml
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/demo-portal/src/main/webapp/WEB-INF/dispatcher-servlet.xml?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/demo-portal/src/main/webapp/WEB-INF/dispatcher-servlet.xml
 (original)
+++ 
rave/sandbox/content-services/demo-portal/src/main/webapp/WEB-INF/dispatcher-servlet.xml
 Mon Sep  3 14:59:13 2012
@@ -124,18 +124,6 @@
     </bean>
   </util:list>
 
-  <!-- FILE BASED LOADING-->
-  <!--
-    <bean name="hmvcHandlerMappingByConfig" 
class="org.apache.rave.portal.web.hmvc.HmvcHandlerMethodMappingByConfig">
-      <property name="order" value="-1"/>
-      <property name="interceptors" ref="interceptors"/>
-      <property name="configurationName" value="myConfiguration"/>
-      <property name="configurationPath" 
value="classpath:page-configuration.xml"/>
-      <property name="urlMappingsPath" 
value="classpath:url-configuration.xml"/>
-      <property name="configManager" ref="fileConfigurationManager"/>
-    </bean>
-  -->
-
   <bean name="lazyRepositoryFactory" 
class="org.apache.rave.jcr.LazyRepositoryFactory">
     <constructor-arg>
       <bean 
class="org.apache.rave.jcr.servlet.ServletContextRepositoryFactory">
@@ -159,7 +147,7 @@
     <constructor-arg index="4" value="true"/>
   </bean>
 
-  <!-- JCR LOADING -->
+  <!-- JCR|File based LOADING -->
   <bean name="hmvcHandlerMappingByConfig" 
class="org.apache.rave.portal.web.hmvc.HmvcHandlerMethodMappingByConfig" 
depends-on="repositoryBootstrap" destroy-method="shutdown">
     <property name="order" value="-1"/>
     <property name="configManager" ref="fileConfigurationManager"/>
@@ -171,6 +159,7 @@
 -->
     <property name="configurationPath" 
value="classpath:page-configuration.xml"/>
     <property name="urlMappingsPath" value="classpath:url-mapping.xml"/>
+    <property name="refreshDelay" value="10000"/>
   </bean>
 
   <bean id="fileConfigurationManager" 
class="org.apache.rave.jcr.config.FileConfigManager"/>

Modified: 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigManager.java
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigManager.java?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigManager.java
 (original)
+++ 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigManager.java
 Mon Sep  3 14:59:13 2012
@@ -57,4 +57,6 @@ public interface ConfigManager {
 
 
     void saveUrlConfiguration(UrlConfiguration configuration);
+
+    long lastModified(String name);
 }

Modified: 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigUtils.java
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigUtils.java?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigUtils.java
 (original)
+++ 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/ConfigUtils.java
 Mon Sep  3 14:59:13 2012
@@ -22,9 +22,11 @@ package org.apache.rave.jcr.config;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URL;
+import java.net.URLConnection;
 import java.net.URLDecoder;
 
 import org.slf4j.Logger;
@@ -83,6 +85,27 @@ public final class ConfigUtils {
         }
     }
 
+    public static long lastModified(String resourcePath) {
+        if (resourcePath == null) {
+            throw new IllegalArgumentException("resourcePath parameter cannot 
be <null>");
+        }
+        if (resourcePath.startsWith(FILE_PATH_PREFIX)) {
+            String fileName = 
resourcePath.substring(FILE_PATH_PREFIX.length());
+            return new File(fileName).lastModified();
+        } else if (resourcePath.startsWith(CLASSPATH_PREFIX)) {
+            String classPath = 
resourcePath.substring(CLASSPATH_PREFIX.length());
+            URL url = 
FileConfigManager.class.getClassLoader().getResource(classPath);
+            if (url == null) {
+                return 0;
+            }
+            return new File(url.getFile()).lastModified();
+        } else {
+            // fallback
+            log.info("Neither file or classpath prefix used, trying to get 
resource directly from '{}'", resourcePath);
+            return new File(resourcePath).lastModified();
+        }
+    }
+
     public static InputStream getResourceInputStream(String resourcePath) {
         if (resourcePath == null) {
             throw new IllegalArgumentException("resourcePath parameter cannot 
be <null>");
@@ -101,7 +124,15 @@ public final class ConfigUtils {
             if (url == null) {
                 return null;
             }
-            return 
FileConfigManager.class.getClassLoader().getResourceAsStream(classPath);
+            try {
+                // don't use ClassLoader.getResourceAsStream(path) as it 
can/does internal caching
+                // of resources, making change/reload detection useless
+                URLConnection urlConnection = url.openConnection();
+                urlConnection.setUseCaches(false);
+                return urlConnection.getInputStream();
+            } catch (IOException e) {
+                return null;
+            }
         } else {
             // fallback
             log.info("Neither file or classpath prefix used, trying to get 
resource directly from '{}'", resourcePath);

Modified: 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/FileConfigManager.java
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/FileConfigManager.java?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/FileConfigManager.java
 (original)
+++ 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/FileConfigManager.java
 Mon Sep  3 14:59:13 2012
@@ -107,5 +107,7 @@ public class FileConfigManager implement
         throw new IllegalStateException("Not supported");
     }
 
-
+    public long lastModified(String name) {
+        return ConfigUtils.lastModified(name);
+    }
 }

Modified: 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/JcrConfigManager.java
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/JcrConfigManager.java?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/JcrConfigManager.java
 (original)
+++ 
rave/sandbox/content-services/rave-jcr-integration/page-configuration/src/main/java/org/apache/rave/jcr/config/JcrConfigManager.java
 Mon Sep  3 14:59:13 2012
@@ -155,5 +155,7 @@ public class JcrConfigManager implements
         return new ObjectContentManagerImpl(session, mapper);
     }
 
-
+    public long lastModified(String name) {
+        return 0;
+    }
 }

Modified: 
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/apache/rave/portal/web/hmvc/HmvcHandlerMethodMappingByConfig.java
URL: 
http://svn.apache.org/viewvc/rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/apache/rave/portal/web/hmvc/HmvcHandlerMethodMappingByConfig.java?rev=1380262&r1=1380261&r2=1380262&view=diff
==============================================================================
--- 
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/apache/rave/portal/web/hmvc/HmvcHandlerMethodMappingByConfig.java
 (original)
+++ 
rave/sandbox/content-services/rave-web-hmvc/src/main/java/org/apache/rave/portal/web/hmvc/HmvcHandlerMethodMappingByConfig.java
 Mon Sep  3 14:59:13 2012
@@ -19,6 +19,7 @@
 
 package org.apache.rave.portal.web.hmvc;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -50,6 +51,7 @@ import org.springframework.web.bind.anno
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.method.HandlerMethodSelector;
+import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
 import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
 import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
 import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
@@ -66,8 +68,6 @@ public class HmvcHandlerMethodMappingByC
 
     private static final Logger log = 
LoggerFactory.getLogger(HmvcHandlerMethodMappingByConfig.class);
 
-    private Map<RequestMappingInfo, HmvcHandlerMethod> hmvcHandlerMethods = 
new LinkedHashMap<RequestMappingInfo, HmvcHandlerMethod>();
-
     private LazyRepositoryFactory repositoryFactory;
 
     private ConfigManager configManager;
@@ -78,13 +78,46 @@ public class HmvcHandlerMethodMappingByC
 
     private String urlMappingsPath;
 
+    // delay refresh in milliseconds
+    private long refreshDelay;
+
+    private long configsLastChecked;
+
     private boolean configured;
 
+    // temporary hacked open *reference* to the real but private 
handlerMethods map in AbstractHandlerMethodMapping.java
+    private Map<RequestMappingInfo, HandlerMethod> handlerMethods;
+
     /**
      * Used only when JCR config manager is used
      */
     private Credentials credentials;
 
+    public HmvcHandlerMethodMappingByConfig() {
+        super();
+        // temporary dirty hack to access private handlerMethods map in 
AbstractHandlerMethodMapping.java
+        // see #getHandlerMethodsInternal() method which should be provided on 
that class
+        try {
+            Field f = 
AbstractHandlerMethodMapping.class.getDeclaredField("handlerMethods");
+            f.setAccessible(true);
+            try {
+                handlerMethods = (Map<RequestMappingInfo, 
HandlerMethod>)f.get(this);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("Unexpected", e);
+            }
+        } catch (NoSuchFieldException e) {
+            throw new RuntimeException("Unexpected", e);
+        }
+        // end temporary dirty hack
+    }
+
+    /**
+     * Temporary method which should be made available on super class 
AbstractHandlerMethodMapping.java instead
+     * to allow access to the internal private handlerMethods map.
+     */
+    protected Map<RequestMappingInfo, HandlerMethod> 
getHandlerMethodsInternal() {
+        return this.handlerMethods;
+    }
 
     @Override
     protected void initHandlerMethods() {
@@ -98,6 +131,7 @@ public class HmvcHandlerMethodMappingByC
 
         } else {
             configured = true;
+            configsLastChecked = System.currentTimeMillis();
             final PageConfiguration configuration = 
configManager.loadConfiguration(configurationPath);
             final UrlConfiguration urlConfig = 
configManager.loadUrlConfig(urlMappingsPath, configuration);
             // TODO use urlConfig
@@ -105,6 +139,22 @@ public class HmvcHandlerMethodMappingByC
         }
     }
 
+    protected void reloadConfigIfNeeded() {
+        long currentTime = System.currentTimeMillis();
+        if (configured && (refreshDelay == 0 || configsLastChecked + 
refreshDelay < currentTime)) {
+            synchronized (configManager) {
+                if ( configManager.lastModified(configurationPath) > 
configsLastChecked ||
+                        configManager.lastModified(urlMappingsPath) > 
configsLastChecked ) {
+                    final PageConfiguration configuration = 
configManager.loadConfiguration(configurationPath);
+                    final UrlConfiguration urlConfig = 
configManager.loadUrlConfig(urlMappingsPath, configuration);
+                    // TODO use urlConfig
+                    processConfiguration(urlConfig);
+                }
+            }
+            configsLastChecked = currentTime;
+        }
+    }
+
     @Override
     public synchronized void repositoryAvailable(final Object factoryKey, 
final Repository repository) {
         Session session = null;
@@ -196,6 +246,9 @@ public class HmvcHandlerMethodMappingByC
 
     private void processConfiguration(UrlConfiguration configuration) {
 
+        // reset
+        getHandlerMethodsInternal().clear();
+
         for (UrlMapping urlMapping : configuration.getMappings()) {
             PageDefinition pageDefinition = urlMapping.getPageDefinition();
             final String controller = pageDefinition.getController();
@@ -221,10 +274,13 @@ public class HmvcHandlerMethodMappingByC
     protected void registerPageHandlerMethod(PageDefinition pageDefinition, 
Object handler, Method method, RequestMappingInfo mapping, String[] views) {
         HmvcHandlerMethod hmvcHandlerMethod = 
getHmvcHandlerMethodForFragment(handler, method, pageDefinition, views);
         registerHandlerMethod(handler, method, mapping);
-        hmvcHandlerMethods.put(mapping, hmvcHandlerMethod);
+        // replace default HandlerMethod with our own hmvcHandlerMethod
+        getHandlerMethodsInternal().put(mapping, hmvcHandlerMethod);
+        if (logger.isInfoEnabled()) {
+            logger.info("Remapped \"" + mapping + "\" onto hmvc " + 
hmvcHandlerMethod);
+        }
     }
 
-
     private HmvcHandlerMethod getHmvcHandlerMethodForFragment(Object handler, 
Method method, PageFragment fragment, String[] views) {
         HmvcHandlerConfiguration config = new HmvcHandlerConfiguration();
         config.setName(fragment.getName());
@@ -254,7 +310,6 @@ public class HmvcHandlerMethodMappingByC
         return config.getMethod();
     }
 
-
     
//*************************************************************************************
     // UTILITIES
     
//*************************************************************************************
@@ -281,7 +336,6 @@ public class HmvcHandlerMethodMappingByC
         return null;
     }
 
-
     private RequestMappingInfo createMappingInfo(RequestMapping annotation, 
String path) {
         final String[] patterns = {path};
         log.info("Creating mapping for patterns:[{}]", patterns);
@@ -297,7 +351,6 @@ public class HmvcHandlerMethodMappingByC
                 null);
     }
 
-
     public void setConfigManager(ConfigManager configManager) {
         this.configManager = configManager;
     }
@@ -322,6 +375,10 @@ public class HmvcHandlerMethodMappingByC
         this.repositoryFactory = repositoryFactory;
     }
 
+    public void setRefreshDelay(long refreshDelay) {
+        this.refreshDelay = refreshDelay;
+    }
+
     @Override
     protected void handleMatch(RequestMappingInfo info, String lookupPath, 
HttpServletRequest request) {
         super.handleMatch(info, lookupPath, request);
@@ -334,6 +391,8 @@ public class HmvcHandlerMethodMappingByC
         if (repositoryFactory != null) {
             repositoryFactory.getRepository();
         }
+        reloadConfigIfNeeded();
+
         String lookupPath = 
getUrlPathHelper().getLookupPathForRequest(request);
         if (logger.isDebugEnabled()) {
             logger.debug("Looking up handler method for path " + lookupPath);
@@ -350,9 +409,8 @@ public class HmvcHandlerMethodMappingByC
             }
         }
 
-        if (handlerMethod != null && mapping != null && 
hmvcHandlerMethods.containsKey(mapping)) {
-            // if available return hmvc variant instead
-            handlerMethod = hmvcHandlerMethods.get(mapping);
+        if (handlerMethod != null && mapping != null) {
+            // we have a HmvcHandlerMethod match
             request.setAttribute(HmvcHandlerMethod.class.getName(), 
Boolean.TRUE);
         }
         return (handlerMethod != null) ? 
handlerMethod.createWithResolvedBean() : null;


Reply via email to