Author: carlucci
Date: Thu May  3 20:51:15 2012
New Revision: 1333616

URL: http://svn.apache.org/viewvc?rev=1333616&view=rev
Log:
RAVE-605: Add a consumer notification ability to the StaticContentFetcherService

Added:
    
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherConsumer.java
Modified:
    
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherService.java
    
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/impl/DefaultStaticContentFetcherService.java
    
rave/trunk/rave-components/rave-commons/src/test/java/org/apache/rave/service/impl/DefaultStaticContentFetcherServiceTest.java

Added: 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherConsumer.java
URL: 
http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherConsumer.java?rev=1333616&view=auto
==============================================================================
--- 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherConsumer.java
 (added)
+++ 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherConsumer.java
 Thu May  3 20:51:15 2012
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rave.service;
+
+/**
+ * A consumer of the StaticContentFetcherService
+ */
+public interface StaticContentFetcherConsumer {
+    /**
+     * Notifies the consumer that the static content with the supplied key has 
been refreshed.  This method is
+     * used to perform whatever logic needs to be executed upon learning the 
content has been updated.
+     *
+     * @param key the StaticContent id that was refreshed
+     */
+    void notify(String key);
+}

Modified: 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherService.java
URL: 
http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherService.java?rev=1333616&r1=1333615&r2=1333616&view=diff
==============================================================================
--- 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherService.java
 (original)
+++ 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/StaticContentFetcherService.java
 Thu May  3 20:51:15 2012
@@ -41,4 +41,22 @@ public interface StaticContentFetcherSer
      * @param key the cache key of the content artifact to refresh
      */
     void refresh(String key);
+
+    /**
+     * Registers a StaticContentFetcher consumer with this 
StaticContentFetcherService.
+     * StaticContentFetcherConsumers will have their notify method executed 
when the content
+     * has been updated.
+     *
+     * @param consumer
+     */
+    void registerConsumer(StaticContentFetcherConsumer consumer);
+
+    /**
+     * Un-registers a StaticContentFetcherConsumer from this 
StaticContentFetcherService.
+     * StaticContentFetcherConsumers un-registered will no longer have their 
notify method executed when
+     * the content has been updated
+     *
+     * @param consumer
+     */
+    void unregisterConsumer(StaticContentFetcherConsumer consumer);
 }

Modified: 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/impl/DefaultStaticContentFetcherService.java
URL: 
http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/impl/DefaultStaticContentFetcherService.java?rev=1333616&r1=1333615&r2=1333616&view=diff
==============================================================================
--- 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/impl/DefaultStaticContentFetcherService.java
 (original)
+++ 
rave/trunk/rave-components/rave-commons/src/main/java/org/apache/rave/service/impl/DefaultStaticContentFetcherService.java
 Thu May  3 20:51:15 2012
@@ -22,18 +22,18 @@ package org.apache.rave.service.impl;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.rave.model.StaticContent;
+import org.apache.rave.service.StaticContentFetcherConsumer;
 import org.apache.rave.service.StaticContentFetcherService;
 import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public class DefaultStaticContentFetcherService implements 
StaticContentFetcherService {
     private static final Log log = 
LogFactory.getLog(DefaultStaticContentFetcherService.class);
     private Map<String, StaticContent> contentMap;
     private RestTemplate restTemplate;
+    private final Set<StaticContentFetcherConsumer> 
staticContentFetcherConsumers;
 
     public DefaultStaticContentFetcherService(RestTemplate restTemplate, 
List<StaticContent> contentObjects) {
         this.restTemplate = restTemplate;
@@ -41,6 +41,7 @@ public class DefaultStaticContentFetcher
         for (StaticContent contentObject : contentObjects) {
             contentMap.put(contentObject.getId(), contentObject);
         }
+        staticContentFetcherConsumers = new 
HashSet<StaticContentFetcherConsumer>();
     }
 
     @Override
@@ -71,6 +72,22 @@ public class DefaultStaticContentFetcher
         }
     }
 
+    @Override
+    public void registerConsumer(StaticContentFetcherConsumer consumer) {
+        synchronized (staticContentFetcherConsumers) {
+            log.debug("adding " + consumer.getClass().getName() + " to 
staticContentFetcherConsumers");
+            staticContentFetcherConsumers.add(consumer);
+        }
+    }
+
+    @Override
+    public void unregisterConsumer(StaticContentFetcherConsumer consumer) {
+        synchronized (staticContentFetcherConsumers) {
+            log.debug("removing " + consumer.getClass().getName() + " from 
staticContentFetcherConsumers");
+            staticContentFetcherConsumers.remove(consumer);
+        }
+    }
+
     private void refreshFromLocation(StaticContent staticContent) {
         log.debug("refreshFromLocation() - for " + staticContent);
         try {
@@ -81,9 +98,20 @@ public class DefaultStaticContentFetcher
                 tempContent = 
tempContent.replaceAll(replacementTokenEntry.getKey(), 
replacementTokenEntry.getValue());
             }
             staticContent.setContent(tempContent);
+            // notify any registered consumers that the content has been 
updated
+            synchronized (staticContentFetcherConsumers) {
+                for (StaticContentFetcherConsumer consumer : 
staticContentFetcherConsumers) {
+                    log.debug("notifiying consumer " + 
consumer.getClass().getName() + " for content update: " + 
staticContent.getId());
+                    try {
+                        consumer.notify(staticContent.getId());
+                    } catch (Exception e) {
+                        log.warn("exception during consumer notification", e);
+                    }
+                }
+            }
         } catch (RestClientException e) {
             //RestClientException handles server errors 5xx, client errors 
4xx, and IO errors
             log.error("Unable to process {" + staticContent.getLocation() + 
"}", e);
-        }        
+        }
     }
 }

Modified: 
rave/trunk/rave-components/rave-commons/src/test/java/org/apache/rave/service/impl/DefaultStaticContentFetcherServiceTest.java
URL: 
http://svn.apache.org/viewvc/rave/trunk/rave-components/rave-commons/src/test/java/org/apache/rave/service/impl/DefaultStaticContentFetcherServiceTest.java?rev=1333616&r1=1333615&r2=1333616&view=diff
==============================================================================
--- 
rave/trunk/rave-components/rave-commons/src/test/java/org/apache/rave/service/impl/DefaultStaticContentFetcherServiceTest.java
 (original)
+++ 
rave/trunk/rave-components/rave-commons/src/test/java/org/apache/rave/service/impl/DefaultStaticContentFetcherServiceTest.java
 Thu May  3 20:51:15 2012
@@ -19,6 +19,8 @@
 package org.apache.rave.service.impl;
 
 import org.apache.rave.model.StaticContent;
+import org.apache.rave.service.StaticContentFetcherConsumer;
+import org.apache.rave.service.StaticContentFetcherService;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.test.util.ReflectionTestUtils;
@@ -30,6 +32,7 @@ import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import static org.easymock.EasyMock.*;
 import static org.hamcrest.CoreMatchers.is;
@@ -37,6 +40,7 @@ import static org.junit.Assert.assertTha
 
 public class DefaultStaticContentFetcherServiceTest {
     private RestTemplate restTemplate;
+    private StaticContentFetcherConsumer consumer;
 
     private final String VALID_URL1 = "http://www.google.com/";;
     private final String VALID_URL1_ID = "google";
@@ -65,24 +69,25 @@ public class DefaultStaticContentFetcher
         VALID_CONTENT_1 = new StaticContent(VALID_URL1_ID, new 
URI(VALID_URL1), null);
         VALID_CONTENT_2 = new StaticContent(VALID_URL2_ID, new 
URI(VALID_URL2), null);
         VALID_CONTENT_3 = new StaticContent(VALID_URL3_ID, new 
URI(VALID_URL3), null);
-        
+
         restTemplate = createNiceMock(RestTemplate.class);
+        consumer = createMock(StaticContentFetcherConsumer.class);
     }
 
     @Test
     public void getContent_validId() throws URISyntaxException {
         DefaultStaticContentFetcherService service = new 
DefaultStaticContentFetcherService(restTemplate, Arrays.asList(VALID_CONTENT_1, 
VALID_CONTENT_2, VALID_CONTENT_3));
-        expectAllRestTemplateGetForObject();        
+        expectAllRestTemplateGetForObject();
         replay(restTemplate);
-        
-        //Initially all content will be blank        
+
+        //Initially all content will be blank
         assertBlankInitialContent(service);
-        
+
         service.refreshAll();
 
         //Now that the content has been refreshed we should get a valid value
         assertThat(service.getContent(VALID_URL1_ID), is(VALID_URL1_CONTENT));
-        
+
         verify(restTemplate);
     }
 
@@ -104,7 +109,7 @@ public class DefaultStaticContentFetcher
         assertThat(service.getContent(VALID_URL1_ID), is(VALID_URL1_CONTENT));
         assertThat(service.getContent(VALID_URL2_ID), is(VALID_URL2_CONTENT));
         assertThat(service.getContent(VALID_URL3_ID), 
is(VALID_URL3_CONTENT_WITH_REPLACEMENTS));
-        
+
         verify(restTemplate);
     }
 
@@ -117,11 +122,18 @@ public class DefaultStaticContentFetcher
     @Test
     public void refreshAll() throws URISyntaxException {
         DefaultStaticContentFetcherService service = new 
DefaultStaticContentFetcherService(restTemplate, Arrays.asList(VALID_CONTENT_1, 
VALID_CONTENT_2, VALID_CONTENT_3));
-
+        service.registerConsumer(consumer);
         assertBlankInitialContent(service);
 
         expectAllRestTemplateGetForObject();
-        replay(restTemplate);
+        consumer.notify(VALID_CONTENT_1.getId());
+        expectLastCall();
+        consumer.notify(VALID_CONTENT_2.getId());
+        // simulate an exception in the middle of the notification loop to 
ensure it continues processing
+        expectLastCall().andThrow(new RuntimeException("boom"));
+        consumer.notify(VALID_CONTENT_3.getId());
+        expectLastCall();
+        replay(restTemplate, consumer);
 
         service.refreshAll();
 
@@ -129,6 +141,7 @@ public class DefaultStaticContentFetcher
         assertThat(service.getContent(VALID_URL1_ID), is(VALID_URL1_CONTENT));
         assertThat(service.getContent(VALID_URL2_ID), is(VALID_URL2_CONTENT));
         assertThat(service.getContent(VALID_URL3_ID), is(VALID_URL3_CONTENT));
+        verify(restTemplate, consumer);
     }
 
     @Test
@@ -172,7 +185,7 @@ public class DefaultStaticContentFetcher
 
         expectAllRestTemplateGetForObject();
         replay(restTemplate);
-        
+
         service.refreshAll();
 
         assertThat(service.getContent(VALID_URL1_ID), is(VALID_URL1_CONTENT));
@@ -196,7 +209,17 @@ public class DefaultStaticContentFetcher
         assertThat(service.getContent(VALID_URL1_ID), is(newContent));
         assertThat(service.getContent(VALID_URL2_ID), is(VALID_URL2_CONTENT));
         assertThat(service.getContent(VALID_URL3_ID), is(newContent));
-    }    
+    }
+
+    @Test
+    public void registerAndUnregisterConsumer() {
+        DefaultStaticContentFetcherService service = new 
DefaultStaticContentFetcherService(restTemplate, Arrays.asList(VALID_CONTENT_1, 
VALID_CONTENT_2, VALID_CONTENT_3));
+        assertThat(getInternalConsumersSet(service).contains(consumer), 
is(false));
+        service.registerConsumer(consumer);
+        assertThat(getInternalConsumersSet(service).contains(consumer), 
is(true));
+        service.unregisterConsumer(consumer);
+        assertThat(getInternalConsumersSet(service).contains(consumer), 
is(false));
+    }
 
     private void expectAllRestTemplateGetForObject() throws URISyntaxException 
{
         expect(restTemplate.getForObject(new URI(VALID_URL1), 
String.class)).andReturn(VALID_URL1_CONTENT);
@@ -209,4 +232,8 @@ public class DefaultStaticContentFetcher
         assertThat(service.getContent(VALID_URL2_ID), is(""));
         assertThat(service.getContent(VALID_URL3_ID), is(""));
     }
+
+    private Set<StaticContentFetcherConsumer> 
getInternalConsumersSet(StaticContentFetcherService service) {
+        return (Set<StaticContentFetcherConsumer>) 
ReflectionTestUtils.getField(service, "staticContentFetcherConsumers");
+    }
 }


Reply via email to