From 43f357e1bd8e14c6193a2225f15155488ba2aed8 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Tue, 22 May 2012 02:25:52 -0400 Subject: [PATCH] Added a 'clear container' admin function to gae-tweetstore-spring --- .../config/SpringServletConfig.java | 7 ++ .../controller/ClearTweetsController.java | 96 +++++++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 4 + .../controller/ClearTweetsControllerTest.java | 72 ++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/ClearTweetsController.java create mode 100644 demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/ClearTweetsControllerTest.java diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java index c925dc59a7..9bfba4a8cd 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java @@ -46,6 +46,7 @@ import org.jclouds.ContextBuilder; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.demo.tweetstore.config.util.CredentialsCollector; import org.jclouds.demo.tweetstore.controller.AddTweetsController; +import org.jclouds.demo.tweetstore.controller.ClearTweetsController; import org.jclouds.demo.tweetstore.controller.EnqueueStoresController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; @@ -172,6 +173,11 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA return new EnqueueStoresController(providerTypeToBlobStoreMap, queue); } + @Bean + public ClearTweetsController clearTweetsController() { + return new ClearTweetsController(providerTypeToBlobStoreMap, container); + } + private void injectServletConfig(Servlet servlet) { LOGGER.trace("About to inject servlet config '%s'", servletConfig); try { @@ -194,6 +200,7 @@ public class SpringServletConfig extends LoggingConfig implements ServletConfigA urlMap.put("/store/*", storeTweetsController()); urlMap.put("/tweets/*", addTweetsController()); urlMap.put("/stores/*", enqueueStoresController()); + urlMap.put("/clear/*", clearTweetsController()); mapping.setUrlMap(urlMap); /* * "/store", "/tweets" and "/stores" are part of the servlet mapping and thus diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/ClearTweetsController.java b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/ClearTweetsController.java new file mode 100644 index 0000000000..e08cfbc19e --- /dev/null +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/ClearTweetsController.java @@ -0,0 +1,96 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.jclouds.demo.tweetstore.controller; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.nullToEmpty; + +import java.io.IOException; +import java.util.Map; + +import javax.annotation.Resource; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; + +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.jclouds.logging.Logger; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Grab tweets related to me and store them into blobstores + * + * @author Adrian Cole + */ +@Singleton +public class ClearTweetsController extends HttpServlet { + /** The serialVersionUID */ + private static final long serialVersionUID = 7215420527854203714L; + + private final Map contexts; + private final String container; + + @Resource + protected Logger logger = Logger.NULL; + + @Inject + @VisibleForTesting + public ClearTweetsController(Map contexts, + @Named(TweetStoreConstants.PROPERTY_TWEETSTORE_CONTAINER) String container) { + this.container = container; + this.contexts = contexts; + } + + @VisibleForTesting + public void clearContainer(String contextName) { + BlobStoreContext context = checkNotNull(contexts.get(contextName), + "no context for %s in %s", contextName, contexts.keySet()); + try { + context.getBlobStore().clearContainer(container); + } catch (Exception e) { + logger.error(e, "Error clearing tweets in %s/%s", container, context); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + if (nullToEmpty(request.getHeader("X-Originator")).equals("admin")) { + try { + String contextName = checkNotNull(request.getHeader("context"), "missing header context"); + logger.info("clearing tweets in %s/%s", container, contextName); + clearContainer(contextName); + logger.debug("done clearing tweets"); + response.setContentType(MediaType.TEXT_PLAIN); + response.getWriter().println("Done!"); + } catch (Exception e) { + logger.error(e, "Error clearing tweets"); + throw new ServletException(e); + } + } else { + response.sendError(401); + } + } +} \ No newline at end of file diff --git a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml index 971ada29cd..3853142f26 100644 --- a/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml +++ b/demos/tweetstore/gae-tweetstore-spring/src/main/webapp/WEB-INF/web.xml @@ -45,6 +45,10 @@ dispatcher /stores/* + + dispatcher + /clear/* + diff --git a/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/ClearTweetsControllerTest.java b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/ClearTweetsControllerTest.java new file mode 100644 index 0000000000..81f0b9f3c7 --- /dev/null +++ b/demos/tweetstore/gae-tweetstore-spring/src/test/java/org/jclouds/demo/tweetstore/controller/ClearTweetsControllerTest.java @@ -0,0 +1,72 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds 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.jclouds.demo.tweetstore.controller; + +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +import org.jclouds.ContextBuilder; +import org.jclouds.blobstore.BlobStoreContext; +import org.jclouds.blobstore.TransientApiMetadata; +import org.jclouds.blobstore.domain.Blob; +import org.jclouds.demo.tweetstore.reference.TweetStoreConstants; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +/** + * Tests behavior of {@code AddTweetsController} + * + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ClearTweetsControllerTest { + + Map createBlobStores(String container) throws InterruptedException, ExecutionException { + TransientApiMetadata transientApiMetadata = TransientApiMetadata.builder().build(); + Map contexts = ImmutableMap.of( + "test1", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class), + "test2", ContextBuilder.newBuilder(transientApiMetadata).build(BlobStoreContext.class)); + for (BlobStoreContext blobstore : contexts.values()) { + blobstore.getBlobStore().createContainerInLocation(null, container); + Blob blob = blobstore.getAsyncBlobStore().blobBuilder("1").build(); + blob.getMetadata().getUserMetadata().put(TweetStoreConstants.SENDER_NAME, "frank"); + blob.setPayload("I love beans!"); + blobstore.getBlobStore().putBlob(container, blob); + } + return contexts; + } + + public void testClearTweets() throws IOException, InterruptedException, ExecutionException { + String container = ClearTweetsControllerTest.class.getName() + "#container"; + Map contexts = createBlobStores(container); + + ClearTweetsController controller = new ClearTweetsController(contexts, + container); + controller.clearContainer("test1"); + controller.clearContainer("test2"); + + for (BlobStoreContext context : contexts.values()) { + assertEquals(context.getBlobStore().countBlobs(container), 0, context.toString()); + } + } +}