Author: ivol37 at gmail.com
Date: Thu Nov 4 16:06:52 2010
New Revision: 248
Log:
[AMDATU-151] Implemented whiteboard style registration of filters. Also the
infamous 'Thread.sleep' to wait for the availability of the Guice injector has
been replaced by service dependency mechanism. Also shindig dependency is no
longer needed during integration tests.
Added:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorService.java
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServiceImpl.java
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServlet.java
Modified:
trunk/integration-tests/pom.xml
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
trunk/platform-bundles/httpcontext/pom.xml
trunk/platform-bundles/httpcontext/src/main/java/org/amdatu/platform/httpcontext/service/HttpContextFactoryServiceImpl.java
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/osgi/Activator.java
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/ShindigRegistrationServiceImpl.java
trunk/src/main/resources/conf/felix-config.properties
Modified: trunk/integration-tests/pom.xml
==============================================================================
--- trunk/integration-tests/pom.xml (original)
+++ trunk/integration-tests/pom.xml Thu Nov 4 16:06:52 2010
@@ -128,7 +128,14 @@
<version>${org.apache.felix.http.version}</version>
<scope>test</scope>
<type>bundle</type>
- </dependency>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ <scope>compile</scope>
+ </dependency>
+
</dependencies>
<build>
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/base/IntegrationTestBase.java
Thu Nov 4 16:06:52 2010
@@ -16,16 +16,20 @@
*/
package org.amdatu.test.integration.base;
-import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.CoreOptions.bundle;
+import static org.ops4j.pax.exam.CoreOptions.felix;
+import static org.ops4j.pax.exam.CoreOptions.frameworks;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.mavenConfiguration;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import org.amdatu.platform.cassandra.application.CassandraConfigurationService;
-import org.amdatu.platform.configtemplatemanager.ConfigTemplateManager;
-import org.amdatu.platform.httpcontext.HttpContextServiceFactory;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.DependencyManager;
@@ -40,8 +44,6 @@
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.cm.ConfigurationAdmin;
-import org.osgi.service.log.LogService;
/**
* This class works as a base for all our integration tests. The notable
components,
@@ -55,6 +57,9 @@
public abstract class IntegrationTestBase {
public final static String TEST_PREFIX = "> TESTING: ";
public final static int SERVICE_TIMEOUT = 30;
+
+ public final static String HOST_NAME = "localhost";
+ public final static int PORT_NR = 3738;
@Inject
protected BundleContext m_bundleContext;
@@ -76,6 +81,9 @@
// Set System property to enable Jetty for the Felix http bundle
systemProperty("org.apache.felix.http.jettyEnabled").value("true"),
+
systemProperty("org.apache.felix.http.whiteboardEnabled").value("true"),
+ systemProperty("org.osgi.service.http.hostname").value(HOST_NAME),
+ systemProperty("org.osgi.service.http.port").value(new
Integer(PORT_NR).toString()),
new VMOption("-Xmx1g"),
// Enable this line to allow a remote debugger to attach to the VM
in which Pax Exam runs
@@ -104,7 +112,6 @@
amdatuHttpContext(),
amdatuConfigTemplateManager(),
amdatuCassandraApplication(),
- amdatuShindigApplication(),
amdatuCassandraListener(),
amdatuCassandraPersistenceManager(),
amdatuTenantService(),
@@ -272,10 +279,6 @@
return
mavenBundle().groupId("org.amdatu.platform").artifactId("cassandra-listener").versionAsInProject();
}
- protected static MavenArtifactProvisionOption amdatuShindigApplication() {
- return
mavenBundle().groupId("org.amdatu.platform").artifactId("shindig-application").versionAsInProject();
- }
-
protected static MavenArtifactProvisionOption amdatuCassandraApplication()
{
return
mavenBundle().groupId("org.amdatu.platform").artifactId("cassandra-application").versionAsInProject();
}
Modified:
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
==============================================================================
---
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
(original)
+++
trunk/integration-tests/src/test/java/org/amdatu/test/integration/tests/CassandraDaemonIntegrationTest.java
Thu Nov 4 16:06:52 2010
@@ -74,15 +74,6 @@
@Before
public void setUp() throws Exception {
- System.out.println("AVAILABLE: " + getService(LogService.class));
- System.out.println("AVAILABLE: " +
getService(ConfigurationAdmin.class));
- System.out.println("AVAILABLE: " + getService(HttpService.class));
-
- System.out.println("AVAILABLE: " +
getService(HttpContextServiceFactory.class));
-
- System.out.println("AVAILABLE: " +
getService(ConfigTemplateManager.class));
- System.out.println("AVAILABLE: " +
getService(CassandraConfigurationService.class));
-
m_daemonService = getService(CassandraDaemonService.class);
}
Modified: trunk/platform-bundles/httpcontext/pom.xml
==============================================================================
--- trunk/platform-bundles/httpcontext/pom.xml (original)
+++ trunk/platform-bundles/httpcontext/pom.xml Thu Nov 4 16:06:52 2010
@@ -47,15 +47,9 @@
<Embed-Dependency>*;scope=compile;groupId=!org.apache.felix|org.osgi</Embed-Dependency>
<Import-Package>
*;resolution:=optional,
- org.apache.shindig.auth,
- org.apache.shindig.common,
- org.apache.shindig.common.crypto,
- org.apache.shindig.common.util,
- org.apache.shindig.social.opensocial.oauth,
- net.oauth,
org.osgi.service.useradmin,
org.amdatu.platform.httpcontext
- </Import-Package>
+ </Import-Package>
<_exportcontents>
org.amdatu.platform.httpcontext
</_exportcontents>
Modified:
trunk/platform-bundles/httpcontext/src/main/java/org/amdatu/platform/httpcontext/service/HttpContextFactoryServiceImpl.java
==============================================================================
---
trunk/platform-bundles/httpcontext/src/main/java/org/amdatu/platform/httpcontext/service/HttpContextFactoryServiceImpl.java
(original)
+++
trunk/platform-bundles/httpcontext/src/main/java/org/amdatu/platform/httpcontext/service/HttpContextFactoryServiceImpl.java
Thu Nov 4 16:06:52 2010
@@ -41,9 +41,6 @@
private volatile HttpService m_httpService;
private volatile LogService m_logService;
- // Injected by Felix
- private DependencyManager m_manager;
-
/**
* Creates a new http context.
* @param bundleContext The bundle context
@@ -54,21 +51,25 @@
Dictionary<String, Object> properties = new Hashtable<String,
Object>();
properties.put(HttpContextImpl.BUNDLECONTEXT_PROP, bundleContext);
properties.put(HttpContextImpl.BUNDLEID_PROP,
bundleContext.getBundle().getBundleId());
+ properties.put("contextId", resourceProvider.getResourceId());
if (resourceProvider != null) {
properties.put(HttpContextImpl.RESOURCEPROVIDER_PROP,
resourceProvider);
if (resourceProvider.getResourceId() != null) {
properties.put(HttpContextImpl.RESOURCEID_PROP,
resourceProvider.getResourceId());
}
}
- Component component = m_manager.createComponent();
- m_manager.add(
+
+ // Create a new dependency manager such that we have a dependency
manager for the proper bundle context
+ DependencyManager manager = new DependencyManager(bundleContext);
+ Component component = manager.createComponent();
+ manager.add(
component
.setImplementation(HttpContextImpl.class)
.setInterface(HttpContext.class.getName(), properties)
-
.add(m_manager.createServiceDependency().setService(HttpService.class).setRequired(true))
-
.add(m_manager.createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
-
.add(m_manager.createServiceDependency().setService(MimeTypeService.class).setRequired(false))
-
.add(m_manager.createServiceDependency().setService(LogService.class).setRequired(true)));
+
.add(manager.createServiceDependency().setService(HttpService.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(ConfigurationAdmin.class).setRequired(true))
+
.add(manager.createServiceDependency().setService(MimeTypeService.class).setRequired(false))
+
.add(manager.createServiceDependency().setService(LogService.class).setRequired(true)));
return component;
}
Modified:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/osgi/Activator.java
==============================================================================
---
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/osgi/Activator.java
(original)
+++
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/osgi/Activator.java
Thu Nov 4 16:06:52 2010
@@ -31,14 +31,16 @@
import org.amdatu.platform.shindig.application.persistence.CassandraOAuthStore;
import
org.amdatu.platform.shindig.application.persistence.GadgetColumnFamilyProvider;
import org.amdatu.platform.shindig.application.persistence.GadgetStoreImpl;
+import org.amdatu.platform.shindig.application.service.GuiceInjectorService;
+import
org.amdatu.platform.shindig.application.service.GuiceInjectorServiceImpl;
import
org.amdatu.platform.shindig.application.service.ShindigRegistrationServiceImpl;
import org.apache.felix.dm.DependencyActivatorBase;
import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.http.api.ExtHttpService;
import org.apache.shindig.gadgets.oauth.OAuthStore;
import org.apache.shindig.social.opensocial.spi.AppDataService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
+import org.osgi.service.http.HttpService;
import org.osgi.service.log.LogService;
import org.osgi.service.useradmin.UserAdmin;
@@ -112,30 +114,31 @@
.setImplementation(ConfigurationAdminGuiceModule.class)
.add(createConfigurationDependency().setPid(SHINDIG_CONFIG_PID).setPropagate(true)));
+ // Create the Guice injector servlet
+ manager.add(
+ createComponent()
+ .setInterface(GuiceInjectorService.class.getName(), null)
+ .setImplementation(GuiceInjectorServiceImpl.class)
+
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(SocialApiModule.class).setRequired(true))
+
.add(createServiceDependency().setService(OAuthModule.class).setRequired(true))
+
.add(createServiceDependency().setService(ConfigurationAdminGuiceModule.class,
"("+ Constants.SERVICE_PID + "=" + SHINDIG_CONFIG_PID + ")")
+ .setRequired(true)));
+
// Register the Shindig registration service
manager.add(
createComponent()
.setImplementation(ShindigRegistrationServiceImpl.class)
.setInterface(ResourceProvider.class.getName(), null)
.add(createServiceDependency().setService(LogService.class).setRequired(true))
+
.add(createServiceDependency().setService(GuiceInjectorService.class).setRequired(true))
.add(createServiceDependency().setService(SocialApiModule.class).setRequired(true))
.add(createServiceDependency().setService(OAuthModule.class).setRequired(true))
.add(createServiceDependency()
.setService(ConfigurationAdminGuiceModule.class, "("+
Constants.SERVICE_PID + "=" + SHINDIG_CONFIG_PID + ")")
.setRequired(true))
.add(createServiceDependency().setService(HttpContextServiceFactory.class).setRequired(true))
-
.add(createServiceDependency().setService(ExtHttpService.class).setRequired(true)));
-
- //TODO: Register authentication filter as a service
- /*
- Dictionary<String, String> props = new Hashtable<String, String>();
- props.put("pattern ", "/*");
- props.put("service.ranking", "0");
- manager.add(
- createComponent()
- .setImplementation(AuthenticationServletFilter.class)
- .setInterface(Filter.class.getName(), props));
- */
+
.add(createServiceDependency().setService(HttpService.class).setRequired(true)));
}
@Override
Added:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorService.java
==============================================================================
--- (empty file)
+++
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorService.java
Thu Nov 4 16:06:52 2010
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.platform.shindig.application.service;
+
+import javax.servlet.Servlet;
+
+/**
+ * Interface for the Guice injector service. The only purpose of this
interface is to allow service
+ * dependencies to be created. For that reason, it holds no methods.
+ *
+ * @author ivol
+ */
+public interface GuiceInjectorService extends Servlet {
+}
Added:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServiceImpl.java
==============================================================================
--- (empty file)
+++
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServiceImpl.java
Thu Nov 4 16:06:52 2010
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.platform.shindig.application.service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+
+import org.amdatu.platform.shindig.application.OAuthModule;
+import org.amdatu.platform.shindig.application.SocialApiModule;
+import
org.amdatu.platform.shindig.application.module.ConfigurationAdminGuiceModule;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.shindig.common.servlet.GuiceServletContextListener;
+import org.osgi.service.log.LogService;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.Stage;
+import com.google.inject.tools.jmx.Manager;
+
+/**
+ * This class covers a rather complicated problem using Guice. Guice-based
servlets require the "Guice injector" to
+ * be created before they are registered. The Guice injector should be
associated with that same servlet context, so
+ * to make that so a servlet should be registered. Usually you do not have
control when a servlet is
+ * actually initialized.
+ * This service covers this tricky stuff. This is what will happen:
+ * -1- First this GuiceInjectorService is created, which contains some
dependencies on Guice modules. The service is
+ * registered with the GuiceInjectorService interface, so it will not register
any servlet yet.
+ * -2- The ShindigRegistrationService has a dependency on this
GuiceInjectorService. In its init() method it will
+ * first create a http context.
+ * -3- The ShindigRegistrationService will now register the
GuiceInjectorService as servlet, using the http context
+ * it just created
+ * -4- By registration of this service as Servlet, the init(ServletConfig)
will be invoked which creates the Guice
+ * injector and associates it with the servlet context.
+ * -5- When the Guice injector is registered, this service is registered as
GuiceInjectorServlet service.
+ * -6- The ShindigRegistrationService continues to register filters and
servlets (whiteboard style), but all with a
+ * service dependency on the GuiceInjectorServlet. This ensures that the Guice
injector is initialized and bound to
+ * the servlet context before it is created.
+ * @author ivol
+ *
+ */
+public class GuiceInjectorServiceImpl implements GuiceInjectorService,
GuiceInjectorServlet {
+ /**
+ * This a path to a fake servlet used to initialize the Guice context.
This servlet is registered *before* all other
+ * servlets and it activates a common HttpContext in its {@link
HttpServlet#init(javax.servlet.ServletConfig)}
+ * method. So all other servlets could find the Guice injector stored by
this fake servlet.
+ */
+ public static final String SERVLET_ALIAS =
"/this/is/the/guice/injector/servlet";
+
+ // Service dependencies
+ private volatile LogService m_logService;
+ private volatile SocialApiModule m_socialApiModule;
+ private volatile OAuthModule m_oAuthModule;
+ private volatile ConfigurationAdminGuiceModule
m_shindigConfigurationModule;
+ private volatile DependencyManager m_dependencyManager;
+
+ // Instance variables
+ private boolean m_jmxInitialized;
+
+ public ServletConfig getServletConfig() {
+ return null;
+ }
+
+ public String getServletInfo() {
+ return null;
+ }
+
+ public void init(ServletConfig config) throws ServletException {
+ Injector injector = createGuiceInjector();
+ ServletContext context = config.getServletContext();
+ context.setAttribute(GuiceServletContextListener.INJECTOR_ATTRIBUTE,
injector);
+ registerService();
+ }
+
+ private void registerService() {
+ // This registers ourselves as GuiceInjectorServlet. Note that the
activator explicitly
+ // does not register the service with the GuiceInjectorServlet
interface since we want
+ // postpone the availability of the service until the Guice injector
is initialized.
+ Dictionary<String, String> serviceProps = new Hashtable<String,
String>();
+ Component component = m_dependencyManager.createComponent();
+ component.setImplementation(this);
+ component.setInterface(GuiceInjectorServlet.class.getName(),
serviceProps);
+ m_dependencyManager.add(component);
+ }
+
+ public void service(ServletRequest arg0, ServletResponse arg1) throws
ServletException, IOException {
+ }
+
+ public void destroy() {
+ }
+
+ /**
+ * @return a newly created Guice injector which is shared between all
Shindig servlets using a common HttpContext
+ */
+ private Injector createGuiceInjector() {
+ String[] moduleNames = getGuiceModules();
+ List<Module> modules = new ArrayList<Module>();
+ if (moduleNames != null) {
+ // First add the properties module
+ modules.add(m_shindigConfigurationModule);
+
+ // Now add all Guice-injected modules
+ for (String moduleName : moduleNames) {
+ try {
+ moduleName = moduleName.trim();
+ if (moduleName.length() > 0) {
+ ClassLoader cl = Module.class.getClassLoader();
+ Module moduleInstance = (Module)
cl.loadClass(moduleName).newInstance();
+ modules.add(moduleInstance);
+ }
+ }
+ catch (InstantiationException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
+ }
+ catch (ClassNotFoundException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
+ }
+ catch (IllegalAccessException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
+ }
+ catch (ClassCastException e) {
+ m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
+ }
+ }
+
+ // Add our own oAuth module
+ modules.add(m_oAuthModule);
+
+ // Finally add our own social api module
+ modules.add(m_socialApiModule);
+ }
+ Injector injector = Guice.createInjector(Stage.PRODUCTION, modules);
+ injector.injectMembers(this);
+ try {
+ if (m_jmxInitialized == false) {
+ Manager.manage("ShindigGuiceContext", injector);
+ m_jmxInitialized = true;
+ }
+ }
+ catch (Exception e) {
+ // Ignore errors
+ }
+ return injector;
+ }
+
+ private String[] getGuiceModules() {
+ return new String[] {
+ "org.apache.shindig.gadgets.DefaultGuiceModule",
+ "org.apache.shindig.extras.ShindigExtrasGuiceModule",
+ "org.apache.shindig.common.cache.ehcache.EhCacheModule" };
+ }
+}
Added:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServlet.java
==============================================================================
--- (empty file)
+++
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/GuiceInjectorServlet.java
Thu Nov 4 16:06:52 2010
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2010 Amdatu.org
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.amdatu.platform.shindig.application.service;
+
+/**
+ * This interface enables dependencies on the availability of the Guice
injector servlet using service dependencies.
+ * When a service dependency on this interface is created, the dependency
implies that the Guice injector servlet is
+ * registered AND initialized, as it registers the service AFTER
initialization of the servlet. This dependency is
+ * needed since each servlet and filter that uses Guice needs this servlet to
be registered first.
+ *
+ * @author ivol
+ */
+public interface GuiceInjectorServlet {
+
+}
Modified:
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/ShindigRegistrationServiceImpl.java
==============================================================================
---
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/ShindigRegistrationServiceImpl.java
(original)
+++
trunk/platform-bundles/shindig-application/src/main/java/org/amdatu/platform/shindig/application/service/ShindigRegistrationServiceImpl.java
Thu Nov 4 16:06:52 2010
@@ -24,25 +24,20 @@
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
import java.util.List;
-import java.util.Properties;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
import org.amdatu.platform.httpcontext.HttpContextServiceFactory;
import org.amdatu.platform.httpcontext.ResourceProvider;
-import org.amdatu.platform.shindig.application.OAuthModule;
-import org.amdatu.platform.shindig.application.SocialApiModule;
-import
org.amdatu.platform.shindig.application.module.ConfigurationAdminGuiceModule;
import org.amdatu.platform.shindig.application.oauth.AmdatuOAuthServlet;
import org.amdatu.platform.shindig.application.osgi.Activator;
import org.apache.felix.dm.Component;
-import org.apache.felix.http.api.ExtHttpService;
+import org.apache.felix.dm.DependencyManager;
import org.apache.shindig.auth.AuthenticationServletFilter;
-import org.apache.shindig.common.servlet.GuiceServletContextListener;
import org.apache.shindig.gadgets.servlet.ConcatProxyServlet;
import org.apache.shindig.gadgets.servlet.GadgetRenderingServlet;
import org.apache.shindig.gadgets.servlet.JsServlet;
@@ -55,15 +50,8 @@
import org.osgi.framework.BundleContext;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
import org.osgi.service.log.LogService;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-import com.google.inject.Stage;
-import com.google.inject.tools.jmx.Manager;
-
/**
* This service is responsible for registration and unregistration of Shindig
servlets, filters and static
* resources.
@@ -71,12 +59,6 @@
* @author ivol
*/
public class ShindigRegistrationServiceImpl implements ResourceProvider {
- /**
- * This a path to a fake servlet used to initialize the Guice context.
This servlet is registered *before* all other
- * servlets and it activates a common HttpContext in its {@link
HttpServlet#init(javax.servlet.ServletConfig)}
- * method. So all other servlets could find the Guice injector stored by
this fake servlet.
- */
- private static final String PATH_TO_FAKE_SERVLET =
"/this/is/a/fake/servlet";
// Base URLs for filters, servlets and static resources
private static final String GADGETS_BASE = "/gadgets";
@@ -93,36 +75,67 @@
private static final String OAUTH_BASE = "/oauth";
private static final String ECHO_BASE = GADGETS_BASE + "/api/echo";
- private static final String WINK_REST_BASE = "/rest/services";
-
// These variables are injected by the Felix dependency manager
private volatile BundleContext m_bundleContext;
- private volatile ExtHttpService m_httpService;
+ private volatile HttpService m_httpService;
private volatile Component m_httpContextComponent;
private volatile LogService m_logService;
private volatile HttpContextServiceFactory m_httpContextFactoryService;
- private volatile SocialApiModule m_socialApiModule;
- private volatile OAuthModule m_oAuthModule;
- private volatile ConfigurationAdminGuiceModule
m_shindigConfigurationModule;
+ private volatile DependencyManager m_dependencyManager;
+ private volatile GuiceInjectorService m_guiceInjectorService;
// Other instance variables
- private boolean m_jmxInitialized;
- private ServletContext m_servletContext = null;
private HttpContext m_httpContext;
private List<String> m_registeredServletPaths = new ArrayList<String>();
- private AuthenticationServletFilter m_authenticationServletFilter;
/**
* The init() method is invoked by the Felix dependency manager.
*/
public void init() {
- // Create our own http context and register resources
+ // Beware! The order in which httpcontext, Guice servlet and other
services are created is very important!
+ //
+
+ // First of all we need to create our own http context to register
resources, filters and servlets
m_httpContextComponent =
m_httpContextFactoryService.create(m_bundleContext, this);
m_httpContext = (HttpContext) m_httpContextComponent.getService();
+ // Now we need to register the Guice injector servlet. This servlet
will create the Guice injector
+ // and set it onto the servlet context. The Guice injector servlet
needs to be registered on the same
+ // httpcontext, therefore we register the servlet and not the Guice
injector service itself.
+ // When the servlet is initialized it will register itself as a
GuiceInjectorServlet service (at this moment
+ // the servlet is registered with the GuiceInjectorService interface)
+ registerServlet(GuiceInjectorServiceImpl.SERVLET_ALIAS,
m_guiceInjectorService);
+
+ // Now register the authentication filter as a service. This filter
needs the Guice injector to be initialized,
+ // which is done when the GuiceInjectorServlet is initialized. So we
define a service dependency on the
+ // GuiceInjectorServlet
+ String baseMatch = "[/\\?]?.*";
+ String regex = ".*("
+ + GADGET_SERVLET_BASE + "[^/]*|"
+ + MAKEREQUEST_BASE + "[^/]*|"
+ + REST_BASE + baseMatch + "|"
+ + GADGETS_REST_BASE + baseMatch + "|"
+ + GADGETS_RPC_BASE + baseMatch + ")";
+ Dictionary<String, String> properties = new Hashtable<String,
String>();
+ properties.put("pattern", regex);
+ properties.put("service.ranking", "0");
+ properties.put("contextId", this.getResourceId());
+ Component component = m_dependencyManager.createComponent();
+ component.setImplementation(AuthenticationServletFilter.class);
+ component.setInterface(Filter.class.getName(), properties);
+
component.add(m_dependencyManager.createServiceDependency().setService(GuiceInjectorServlet.class).setRequired(
+ true));
+ m_dependencyManager.add(component);
+
+ // Append a dependency on the GuiceInjectorServlet such that any
servlets registered later on
+ // are not registered before the Guice injector is initialized
+
m_dependencyManager.createServiceDependency().setService(GuiceInjectorServlet.class.getName())
+ .setRequired(true);
+
copySecurityTokenKey();
m_logService.log(LogService.LOG_INFO, getClass().getName() + " service
initialized");
+
}
/**
@@ -130,33 +143,7 @@
*/
public void start() {
m_logService.log(LogService.LOG_INFO, "Starting " +
getClass().getName() + " service");
-
- try {
- // Initialize the GUICE context.
- initGuiceInjector(m_httpContext);
- int retryCount = 0;
- while (m_servletContext == null && retryCount < 5) {
- // TODO The servlet registration is asynchronous? Really?
- try {
- System.out.println("Fake Guice servlet not yet available,
sleeping for 1 second... ("
- + (5 - retryCount) + " retries left)");
- Thread.sleep(1000);
- }
- catch (InterruptedException i) {}
- retryCount++;
- }
-
- // Register statics, servlets and filters. This can only be done
after initializing
- // the Guice context, for that reason we do it here.
- registerResources();
- }
- catch (ServletException e) {
- m_logService.log(LogService.LOG_ERROR, "Shindig service could not
be started due to error", e);
- }
- catch (NamespaceException e) {
- m_logService.log(LogService.LOG_ERROR, "Shindig service could not
be started due to error", e);
- }
-
+ registerResources();
m_logService.log(LogService.LOG_INFO, getClass().getName() + " service
started.");
}
@@ -217,17 +204,6 @@
}
/**
- * Invoked by the Guice servlet init() method to let the main registration
service know
- * that the fake Guice servlet is initialized. This is requried before
other servlets are
- * registered within the same context
- *
- * @param servletContext the servlet context of the fake Guice servlet
- */
- private void setServletContext(ServletContext servletContext) {
- m_servletContext = servletContext;
- }
-
- /**
* This method sets the given {@link HttpService} object and initializes
all Shindig-specific servlets.
* Since it can only be invoked when the Guice context is available, it is
invoked from there
*/
@@ -236,33 +212,23 @@
// Register the gadget rendering servlet. The gadget rendering
servlet takes a gadget XML file
// (for example
http://gerculanum.appspot.com/gadgets/com.example.chessgadget.client.ChessGadget.gadget.xml)
// and converts it to HTML. 'ifr' stands for the 'iframe' way of
gadget rendering
- addServlet(m_httpContext, GADGET_SERVLET_BASE, new
GadgetRenderingServlet());
+ registerServlet(GADGET_SERVLET_BASE, new GadgetRenderingServlet());
// Register other servlets
- String[] params = { "handlers",
"org.apache.shindig.social.handlers" };
- addServlet(m_httpContext, MAKEREQUEST_BASE, new
MakeRequestServlet());
- addServlet(m_httpContext, PROXY_BASE, new ProxyServlet());
- addServlet(m_httpContext, CONCAT_BASE, new ConcatProxyServlet());
- addServlet(m_httpContext, OAUTH_CALLBACK_BASE, new
OAuthCallbackServlet());
- addServlet(m_httpContext, METADATA_BASE, new RpcServlet());
- addServlet(m_httpContext, JS_BASE, new JsServlet());
- addServlet(m_httpContext, REST_BASE, new DataServiceServlet(),
params);
- addServlet(m_httpContext, GADGETS_REST_BASE, new
DataServiceServlet(), params);
- addServlet(m_httpContext, GADGETS_RPC_BASE, new JsonRpcServlet(),
params);
- addServlet(m_httpContext, OAUTH_BASE, new AmdatuOAuthServlet(),
params);
- addServlet(m_httpContext, ECHO_BASE, new EchoServlet(), params);
-
- // Register filters
- m_authenticationServletFilter = new AuthenticationServletFilter();
- String baseMatch = "[/\\?]?.*";
- String regex = ".*("
- + GADGET_SERVLET_BASE + "[^/]*|"
- + MAKEREQUEST_BASE + "[^/]*|"
- + REST_BASE + baseMatch + "|"
- + GADGETS_REST_BASE + baseMatch + "|"
- + GADGETS_RPC_BASE + baseMatch + ")";
- m_httpService.registerFilter(m_authenticationServletFilter, regex,
null, 0, m_httpContext);
-
+ Dictionary<String, String> servletProperties = new
Hashtable<String, String>();
+ servletProperties.put("init.handlers",
"org.apache.shindig.social.handlers");
+ registerServlet(MAKEREQUEST_BASE, new MakeRequestServlet());
+ registerServlet(PROXY_BASE, new ProxyServlet());
+ registerServlet(CONCAT_BASE, new ConcatProxyServlet());
+ registerServlet(OAUTH_CALLBACK_BASE, new OAuthCallbackServlet());
+ registerServlet(METADATA_BASE, new RpcServlet());
+ registerServlet(JS_BASE, new JsServlet());
+ registerServlet(REST_BASE, new DataServiceServlet(),
servletProperties);
+ registerServlet(GADGETS_REST_BASE, new DataServiceServlet(),
servletProperties);
+ registerServlet(GADGETS_RPC_BASE, new JsonRpcServlet(),
servletProperties);
+ registerServlet(OAUTH_BASE, new AmdatuOAuthServlet(),
servletProperties);
+ registerServlet(ECHO_BASE, new EchoServlet(), servletProperties);
+
// Since /gadgets is already registered automatically by the http
context factory service,
// unregister it first.
m_httpService.unregister("/" + Activator.RESOURCE_ID);
@@ -283,129 +249,40 @@
m_httpService.unregister(m_registeredServletPaths.get(0));
m_registeredServletPaths.remove(0);
}
- m_httpService.unregisterFilter(m_authenticationServletFilter);
m_httpService.unregister("/gadgets");
m_httpService.unregister("/features");
m_httpService.unregister("/shindig");
}
- /**
- * An utility method used to add a new servlet to the HttpService object.
- *
- * @param context the HttpContext common for all servlets
- * @param path the path of the servlet
- * @param servlet the servlet to register
- * @param params parameters to add to the servlet configuration
- * @throws ServletException
- * @throws NamespaceException
- */
- private void addServlet(HttpContext context, String path, HttpServlet
servlet, String... params)
- throws ServletException, NamespaceException {
- Properties p = new Properties();
- String key = null;
- for (int i = 0; i < params.length; i++) {
- if ((i % 2) == 0) {
- key = params[i] != null ? params[i].toString() : null;
- }
- else {
- p.put(key, params[i]);
- }
- }
- m_registeredServletPaths.add(path);
- m_httpService.registerServlet(path, servlet, p, context);
+ public URL getResource(String name) {
+ return null;
}
- /**
- * @return a newly created Guice injector which is shared between all
Shindig servlets using a common HttpContext
- */
- private Injector createGuiceInjector() {
- String[] moduleNames = getGuiceModules();
- List<Module> modules = new ArrayList<Module>();
- if (moduleNames != null) {
- // First add the properties module
- modules.add(m_shindigConfigurationModule);
-
- // Now add all Guice-injected modules
- for (String moduleName : moduleNames) {
- try {
- moduleName = moduleName.trim();
- if (moduleName.length() > 0) {
- ClassLoader cl = Module.class.getClassLoader();
- Module moduleInstance = (Module)
cl.loadClass(moduleName).newInstance();
- modules.add(moduleInstance);
- }
- }
- catch (InstantiationException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
- }
- catch (ClassNotFoundException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
- }
- catch (IllegalAccessException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
- }
- catch (ClassCastException e) {
- m_logService.log(LogService.LOG_ERROR, "Could not create
Guice module", e);
- }
- }
-
- // Add our own oAuth module
- modules.add(m_oAuthModule);
-
- // Finally add our own social api module
- modules.add(m_socialApiModule);
- }
- Injector injector = Guice.createInjector(Stage.PRODUCTION, modules);
- injector.injectMembers(this);
- try {
- if (m_jmxInitialized == false) {
- Manager.manage("ShindigGuiceContext", injector);
- m_jmxInitialized = true;
- }
- }
- catch (Exception e) {
- // Ignore errors
- }
- return injector;
+ public String getResourceId() {
+ return RESOURCE_ID;
}
- private String[] getGuiceModules() {
- return new String[] {
- "org.apache.shindig.gadgets.DefaultGuiceModule",
- "org.apache.shindig.extras.ShindigExtrasGuiceModule",
- "org.apache.shindig.common.cache.ehcache.EhCacheModule" };
+ private void registerServlet(String alias, Servlet servlet) {
+ registerServlet(alias, servlet, null);
}
/**
- * This method creates a fake servlet which is registered *before* all
others servlets and used to initialize the
- * Guice injector for all other servlets sharing the given HttpContext.
The {@link HttpServlet#init(ServletConfig)}
- * method of this fake servlet creates a new Guice instance, configures it
and sets in the given HttpContext. The
- * same HttpContext instance will be used to register all other Shindig
servlets, so they will have access to the
- * already configured Guice.
- *
- * @param context the HttpContext instance where a Guice context will be
stored.
- * @throws ServletException
- * @throws NamespaceException
- */
- private void initGuiceInjector(HttpContext context) throws
ServletException, NamespaceException {
- addServlet(context, PATH_TO_FAKE_SERVLET, new HttpServlet() {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void init(ServletConfig config) throws ServletException {
- Injector injector = createGuiceInjector();
- ServletContext context = config.getServletContext();
-
context.setAttribute(GuiceServletContextListener.INJECTOR_ATTRIBUTE, injector);
- setServletContext(context);
- }
- });
- }
-
- public URL getResource(String name) {
- return null;
- }
-
- public String getResourceId() {
- return RESOURCE_ID;
+ * Registers a servlet whiteboard-style. Note that we should not mix
whiteboard style with direct calls to the
+ * HttpService;
+ * they do not share the same servlet context and the Guice injector is
only registered on the servlet context for
+ * the
+ * whiteboard-style http service.
+ */
+ private void registerServlet(String alias, Servlet servlet,
Dictionary<String, String> servletProperties) {
+ if (servletProperties == null) {
+ servletProperties = new Hashtable<String, String>();
+ }
+ servletProperties.put("alias", alias);
+ servletProperties.put("contextId", getResourceId());
+ Component servletComponent = m_dependencyManager.createComponent();
+ servletComponent.setImplementation(servlet);
+ servletComponent.setInterface(Servlet.class.getName(),
servletProperties);
+ m_dependencyManager.add(servletComponent);
+ m_registeredServletPaths.add(alias);
}
}
Modified: trunk/src/main/resources/conf/felix-config.properties
==============================================================================
--- trunk/src/main/resources/conf/felix-config.properties (original)
+++ trunk/src/main/resources/conf/felix-config.properties Thu Nov 4
16:06:52 2010
@@ -114,3 +114,4 @@
org.apache.felix.http.jettyEnabled=true
org.apache.felix.http.debug=true
org.apache.felix.log.storeDebug=true
+org.apache.felix.http.whiteboardEnabled=true
\ No newline at end of file