From 3087cce5404d1ecbb76c22c9c77a40dd0d1d4ff4 Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Mon, 4 Jan 2010 04:25:34 +0000 Subject: [PATCH] Issue 89: fixed npe in google appengine live git-svn-id: http://jclouds.googlecode.com/svn/trunk@2592 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../tweetstore/config/SpringAppConfig.java | 158 +++++++++--------- .../config/SpringServletConfig.java | 132 +++++++-------- .../controller/AddTweetsController.java | 8 +- 3 files changed, 148 insertions(+), 150 deletions(-) diff --git a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringAppConfig.java b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringAppConfig.java index 353d2a2eaa..9b094e6feb 100644 --- a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringAppConfig.java +++ b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringAppConfig.java @@ -13,6 +13,7 @@ import java.util.Properties; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import javax.inject.Singleton; import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContextBuilder; @@ -37,89 +38,92 @@ import com.google.common.io.Closeables; * @see SpringServletConfig */ @Configuration +@Singleton public class SpringAppConfig implements ResourceLoaderAware { - /* - * The call to TwitterContextFactory.createContext in initialize() - * must be carried out before the servlet context loads, otherwise the - * GAE will throw an access exception. - * For this reason, this code cannot be in the default servlet context - * loaded by the DispatcherServlet, but is executed in the root application - * context (which is processed by a listener). - */ - - private final Properties props = new Properties(); + /* + * The call to TwitterContextFactory.createContext in initialize() must be carried out before the + * servlet context loads, otherwise the GAE will throw an access exception. For this reason, this + * code cannot be in the default servlet context loaded by the DispatcherServlet, but is executed + * in the root application context (which is processed by a listener). + */ - Map> providerTypeToBlobStoreMap; - TwitterClient twitterClient; - String container; + private final Properties props = new Properties(); - @SuppressWarnings("unchecked") - @PostConstruct - public void initialize() { - // shared across all blobstores and used to retrieve tweets - twitterClient = TwitterContextFactory.createContext(props, - new GaeHttpCommandExecutorServiceModule()).getApi(); + Map> providerTypeToBlobStoreMap; + TwitterClient twitterClient; + String container; - // common namespace for storing tweets. - container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), - PROPERTY_TWEETSTORE_CONTAINER); - ImmutableList contextBuilderClassNames = ImmutableList.of( - checkNotNull(props.getProperty(PROPERTY_BLOBSTORE_CONTEXTBUILDERS), - PROPERTY_BLOBSTORE_CONTEXTBUILDERS) - .split(",")); + private boolean initializing; - // instantiate and store references to all blobstores by provider name - providerTypeToBlobStoreMap = Maps.newHashMap(); - for (String className : contextBuilderClassNames) { - Class> builderClass; - Constructor> constructor; - String name; - BlobStoreContext context; - try { - builderClass = (Class>) Class.forName(className); - name = builderClass.getSimpleName().replaceAll("BlobStoreContextBuilder", ""); - constructor = builderClass.getConstructor(Properties.class); - context = constructor.newInstance(props) - .withModules(new GaeHttpCommandExecutorServiceModule()) - .buildContext(); - } catch (Exception e) { - throw new RuntimeException("error instantiating " + className, e); - } - providerTypeToBlobStoreMap.put(name, context); - } + @SuppressWarnings("unchecked") + @PostConstruct + public void initialize() { + if (initializing) + return; + initializing = true; + // shared across all blobstores and used to retrieve tweets + twitterClient = TwitterContextFactory.createContext(props, + new GaeHttpCommandExecutorServiceModule()).getApi(); - // get a queue for submitting store tweet requests - Queue queue = QueueFactory.getQueue("twitter"); - // submit a job to store tweets for each configured blobstore - for (String name : providerTypeToBlobStoreMap.keySet()) { - queue.add(url("/store/do").header("context", name).method(Method.GET)); - } - } + // common namespace for storing tweets. + container = checkNotNull(props.getProperty(PROPERTY_TWEETSTORE_CONTAINER), + PROPERTY_TWEETSTORE_CONTAINER); + ImmutableList contextBuilderClassNames = ImmutableList. of(checkNotNull( + props.getProperty(PROPERTY_BLOBSTORE_CONTEXTBUILDERS), + PROPERTY_BLOBSTORE_CONTEXTBUILDERS).split(",")); - @PreDestroy - public void destroy() { - for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) { - context.close(); - } - } + // instantiate and store references to all blobstores by provider name + providerTypeToBlobStoreMap = Maps.newHashMap(); + for (String className : contextBuilderClassNames) { + Class> builderClass; + Constructor> constructor; + String name; + BlobStoreContext context; + try { + builderClass = (Class>) Class.forName(className); + name = builderClass.getSimpleName().replaceAll("BlobStoreContextBuilder", ""); + constructor = builderClass.getConstructor(Properties.class); + context = constructor.newInstance(props).withModules( + new GaeHttpCommandExecutorServiceModule()).buildContext(); + } catch (Exception e) { + throw new RuntimeException("error instantiating " + className, e); + } + providerTypeToBlobStoreMap.put(name, context); + } - /* - * (non-Javadoc) - * - * @see - * org.springframework.context.ResourceLoaderAware#setResourceLoader(org - * .springframework.core.io.ResourceLoader) - */ - @Override - public void setResourceLoader(ResourceLoader resourceLoader) { - InputStream input = null; - try { - input = resourceLoader.getResource("/WEB-INF/jclouds.properties").getInputStream(); - props.load(input); - } catch (IOException e) { - throw new RuntimeException(e); - } finally { - Closeables.closeQuietly(input); - } - } + // get a queue for submitting store tweet requests + Queue queue = QueueFactory.getQueue("twitter"); + // submit a job to store tweets for each configured blobstore + for (String name : providerTypeToBlobStoreMap.keySet()) { + queue.add(url("/store/do").header("context", name).method(Method.GET)); + } + } + + @PreDestroy + public void destroy() { + for (BlobStoreContext context : providerTypeToBlobStoreMap.values()) { + context.close(); + } + } + + /* + * (non-Javadoc) + * + * @see org.springframework.context.ResourceLoaderAware#setResourceLoader(org + * .springframework.core.io.ResourceLoader) + */ + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + InputStream input = null; + try { + input = resourceLoader.getResource("/WEB-INF/jclouds.properties").getInputStream(); + props.load(input); + if (!initializing) + initialize(); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + Closeables.closeQuietly(input); + } + } } diff --git a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java index d3d46b3d3f..5bc64c6ed6 100644 --- a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java +++ b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/config/SpringServletConfig.java @@ -1,21 +1,33 @@ +/** + * + * Copyright (C) 2009 Cloud Conscious, LLC. + * + * ==================================================================== + * Licensed 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.config; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Map; -import javax.inject.Inject; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; - import org.jclouds.demo.tweetstore.controller.AddTweetsController; import org.jclouds.demo.tweetstore.controller.StoreTweetsController; import org.jclouds.demo.tweetstore.functions.ServiceToStoredTweetStatuses; -import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.context.ServletConfigAware; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.handler.SimpleServletHandlerAdapter; @@ -24,74 +36,54 @@ import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import com.google.common.collect.Maps; /** - * Creates servlets (using resources from the {@link SpringAppConfig}) and mappings. + * Creates servlets,(using resources from the {@link SpringAppConfig}) and mappings. * * @author Andrew Phillips - * @see SpringAppConfig */ @Configuration -public class SpringServletConfig implements ServletConfigAware { - private ServletConfig servletConfig; - - @Inject - private SpringAppConfig appConfig; - - @Bean - public StoreTweetsController storeTweetsController() { - StoreTweetsController controller = new StoreTweetsController(appConfig.providerTypeToBlobStoreMap, - appConfig.container, appConfig.twitterClient); - injectServletConfig(controller); - return controller; - } +public class SpringServletConfig { - @Bean - public AddTweetsController addTweetsController() { - AddTweetsController controller = new AddTweetsController(appConfig.providerTypeToBlobStoreMap, - serviceToStoredTweetStatuses()); - injectServletConfig(controller); - return controller; - } - - private void injectServletConfig(Servlet servlet) { - checkNotNull(servletConfig); - try { - servlet.init(servletConfig); - } catch (ServletException exception) { - throw new BeanCreationException("Unable to instantiate " + servlet, exception); - } - } + @Bean + public StoreTweetsController storeTweetsController(SpringAppConfig appConfig) { + return new StoreTweetsController(checkNotNull(appConfig.providerTypeToBlobStoreMap, + "contexts"), checkNotNull(appConfig.container, "container"), checkNotNull( + appConfig.twitterClient, "twitterClient")); + } - @Bean - ServiceToStoredTweetStatuses serviceToStoredTweetStatuses() { - return new ServiceToStoredTweetStatuses(appConfig.providerTypeToBlobStoreMap, - appConfig.container); - } - - @Bean - public HandlerMapping handlerMapping() { - SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); - Map urlMap = Maps.newHashMapWithExpectedSize(2); - urlMap.put("/store/*", storeTweetsController()); - urlMap.put("/tweets/*", addTweetsController()); - mapping.setUrlMap(urlMap); - /* - * "/store" and "/tweets" are part of the servlet mapping and thus stripped - * by the mapping if using default settings. - */ - mapping.setAlwaysUseFullPath(true); - return mapping; - } - - @Bean - public HandlerAdapter servletHandlerAdapter() { - return new SimpleServletHandlerAdapter(); - } + @Bean + public AddTweetsController addTweetsController(SpringAppConfig appConfig) { + return new AddTweetsController( + checkNotNull(appConfig.providerTypeToBlobStoreMap, "contexts"), + serviceToStoredTweetStatuses(appConfig)); + } - /* (non-Javadoc) - * @see org.springframework.web.context.ServletConfigAware#setServletConfig(javax.servlet.ServletConfig) - */ - @Override - public void setServletConfig(ServletConfig servletConfig) { - this.servletConfig = servletConfig; - } + @Bean + ServiceToStoredTweetStatuses serviceToStoredTweetStatuses(SpringAppConfig appConfig) { + return new ServiceToStoredTweetStatuses(checkNotNull(appConfig.providerTypeToBlobStoreMap, + "contexts"), checkNotNull(appConfig.container, "container")); + } + + @Bean + public HandlerMapping handlerMapping(AddTweetsController add, StoreTweetsController store, + WebApplicationContext context) { + SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); + mapping.setServletContext(context.getServletContext()); + Map urlMap = Maps.newHashMapWithExpectedSize(2); + urlMap.put("/store/*", checkNotNull(store, "store")); + add.setServletContext(checkNotNull(context.getServletContext(), "servletContext")); + urlMap.put("/tweets/*", checkNotNull(add, "add")); + mapping.setUrlMap(urlMap); + /* + * "/store" and "/tweets" are part of the servlet mapping and thus stripped by the mapping if + * using default settings. + */ + mapping.setAlwaysUseFullPath(true); + return mapping; + } + + @Bean + public HandlerAdapter servletHandlerAdapter() { + return new SimpleServletHandlerAdapter(); + } } + diff --git a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java index a427c0b0aa..261fa659a4 100644 --- a/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java +++ b/demos/gae-tweetstore-spring/src/main/java/org/jclouds/demo/tweetstore/controller/AddTweetsController.java @@ -69,8 +69,9 @@ public class AddTweetsController extends HttpServlet implements @Inject public AddTweetsController(Map> contexts, ServiceToStoredTweetStatuses blobStoreContextToContainerResult) { - this.contexts = contexts; - this.blobStoreContextToContainerResult = blobStoreContextToContainerResult; + this.contexts = checkNotNull(contexts, "contexts"); + this.blobStoreContextToContainerResult = checkNotNull(blobStoreContextToContainerResult, + "blobStoreContextToContainerResult"); } @Override @@ -100,6 +101,7 @@ public class AddTweetsController extends HttpServlet implements return statuses; } + @Inject @Override public void setServletContext(ServletContext context) { this.servletContext = context; @@ -107,6 +109,6 @@ public class AddTweetsController extends HttpServlet implements @Override public ServletContext getServletContext() { - return checkNotNull(servletContext, "servletContext"); + return (servletContext != null) ? servletContext : super.getServletContext(); } }