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");
+ }
}