You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ri...@apache.org on 2009/12/16 15:22:05 UTC
svn commit: r891246 - in /geronimo/sandbox/rick: ./ rfc66/ rfc66/src/
rfc66/src/main/ rfc66/src/main/java/ rfc66/src/main/java/org/
rfc66/src/main/java/org/apache/ rfc66/src/main/java/org/apache/geronimo/
rfc66/src/main/java/org/apache/geronimo/osgi/ r...
Author: rickmcguire
Date: Wed Dec 16 14:22:04 2009
New Revision: 891246
URL: http://svn.apache.org/viewvc?rev=891246&view=rev
Log:
Some initial work on a Geronimo RFC 66 webcontainer. This probably should be redone using a different
approach, and some of this is already obsolete (it predates the merge of djencks initial OSGi
restructuring).
Added:
geronimo/sandbox/rick/
geronimo/sandbox/rick/rfc66/
geronimo/sandbox/rick/rfc66/src/
geronimo/sandbox/rick/rfc66/src/main/
geronimo/sandbox/rick/rfc66/src/main/java/
geronimo/sandbox/rick/rfc66/src/main/java/org/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/jetty/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java (with props)
geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java (with props)
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,475 @@
+/*
+ * 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.geronimo.osgi.web;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.transaction.UserTransaction;
+
+import org.apache.InstanceManager;
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.osgi.BundleClassLoader;
+import org.apache.geronimo.tomcat.util.SecurityHolder;
+import org.apache.tomcat.TomcatContext;
+
+/**
+ * Base class for implementing web container-specific
+ * OSGi contexts.
+ * @version $Rev$ $Date$
+ */
+public class AbstractOSGiWebAppContext {
+ // the bundle where this application resides
+ protected Bundle bundle;
+ // the fully resolved context path
+ protected String path;
+ // our wrappered class loader
+ protected ClassLoader classLoader;
+ // The parsed web.xml descriptor
+ protected WebApp webApp;
+ // Indicates whether this is using javaee
+ protected boolean isJavaee = false;
+ // Our ClassFinder instance for processing annotations.
+ protected ClassFinder classFinder;
+
+ public AbstractOSGiWebAppContext(Bundle bundle, String contextPath) {
+ this.bundle = bundle;
+ this.path = contextPath.startsWith("/") ? contextPath : "/" + contextPath;
+ // we give the container a classloader wrapped around the bundle
+ this.classLoader = new BundleClassLoader(bundle);
+ // process the WEB-INF/web.xml file and perform some initial validation.
+ parseWebXml();
+ }
+
+
+ /**
+ * Locate and parse a WEB-INF/web.xml file located in
+ * a WAB.
+ */
+ protected void parseWebXml() {
+ try {
+ // look for a web.xml file in the bundle
+ URL specDDUrl = bundle.getEntry("WEB-INF/web.xml");
+
+ // read in the entire specDD as a string, we need this for getDeploymentDescriptor
+ // on the J2ee management object
+ String specDD = DeploymentUtil.readAll(specDDUrl);
+
+ // we found web.xml, if it won't parse that's an error.
+ XmlObject parsed = XmlBeansUtil.parse(specDD);
+ //Dont save updated xml if it isn't javaee
+ XmlCursor cursor = parsed.newCursor();
+ try {
+ cursor.toStartDoc();
+ cursor.toFirstChild();
+ isJavaee = "http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI());
+ } finally {
+ cursor.dispose();
+ }
+ WebAppDocument webAppDoc = convertToServletSchema(parsed);
+ webApp = webAppDoc.getWebApp();
+ check(webApp);
+ } catch (XmlException e) {
+ // Output the bundle informatin in the error
+ throw new DeploymentException("Error parsing web.xml for " + bundle, e);
+ } catch (Exception e) {
+ isJavaee = true;
+ //else ignore as jee5 allows optional spec dd for .war's
+ }
+
+ // if there was no file, simplify by using a default instance.
+ if (webApp == null)
+ webApp = WebAppType.Factory.newInstance();
+ }
+
+
+ /**
+ * Normalize the document to use the 2.5 servlet specification.
+ *
+ * @param xmlObject The source input file.
+ *
+ * @return A normalized XML document.
+ * @exception XmlException
+ */
+ protected WebAppDocument convertToServletSchema(XmlObject xmlObject) throws XmlException {
+
+ String schemaLocationURL = "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd";
+ String version = "2.5";
+ XmlCursor cursor = xmlObject.newCursor();
+ try {
+ cursor.toStartDoc();
+ cursor.toFirstChild();
+ if ("http://java.sun.com/xml/ns/j2ee".equals(cursor.getName().getNamespaceURI())) {
+ SchemaConversionUtils.convertSchemaVersion(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, schemaLocationURL, version);
+ XmlObject result = xmlObject.changeType(WebAppDocument.type);
+ XmlBeansUtil.validateDD(result);
+ return (WebAppDocument) result;
+ }
+
+ if ("http://java.sun.com/xml/ns/javaee".equals(cursor.getName().getNamespaceURI())) {
+ SchemaConversionUtils.convertSchemaVersion(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, schemaLocationURL, version);
+ XmlObject result = xmlObject.changeType(WebAppDocument.type);
+ XmlBeansUtil.validateDD(result);
+ return (WebAppDocument) result;
+ }
+
+ //otherwise assume DTD
+ XmlDocumentProperties xmlDocumentProperties = cursor.documentProperties();
+ String publicId = xmlDocumentProperties.getDoctypePublicId();
+ boolean is22 = "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN".equals(publicId);
+ if ("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN".equals(publicId) ||
+ is22) {
+ XmlCursor moveable = xmlObject.newCursor();
+ try {
+ moveable.toStartDoc();
+ moveable.toFirstChild();
+
+ SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.JAVAEE_NAMESPACE, schemaLocationURL, version);
+ cursor.toStartDoc();
+ cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "web-app");
+ cursor.toFirstChild();
+ SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
+ SchemaConversionUtils.convertToJNDIEnvironmentRefsGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
+ cursor.push();
+ if (cursor.toNextSibling(TAGLIB)) {
+ cursor.toPrevSibling();
+ moveable.toCursor(cursor);
+ cursor.beginElement("jsp-config", SchemaConversionUtils.JAVAEE_NAMESPACE);
+ while (moveable.toNextSibling(TAGLIB)) {
+ moveable.moveXml(cursor);
+ }
+ }
+ cursor.pop();
+ do {
+ String name = cursor.getName().getLocalPart();
+ if ("filter".equals(name) || "servlet".equals(name) || "context-param".equals(name)) {
+ cursor.push();
+ cursor.toFirstChild();
+ SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
+ while (cursor.toNextSibling(SchemaConversionUtils.JAVAEE_NAMESPACE, "init-param")) {
+ cursor.push();
+ cursor.toFirstChild();
+ SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.JAVAEE_NAMESPACE, cursor, moveable);
+ cursor.pop();
+ }
+ cursor.pop();
+ cursor.push();
+ if (cursor.toChild(SchemaConversionUtils.JAVAEE_NAMESPACE, "jsp-file")) {
+ String jspFile = cursor.getTextValue();
+ if (!jspFile.startsWith("/")){
+ if (is22) {
+ cursor.setTextValue("/" + jspFile);
+ } else {
+ throw new XmlException("jsp-file does not start with / and this is not a 2.2 web app: " + jspFile);
+ }
+ }
+ }
+ cursor.pop();
+ }
+ } while (cursor.toNextSibling());
+ } finally {
+ moveable.dispose();
+ }
+ }
+ } finally {
+ cursor.dispose();
+ }
+ XmlObject result = xmlObject.changeType(WebAppDocument.type);
+ if (result != null) {
+ XmlBeansUtil.validateDD(result);
+ return (WebAppDocument) result;
+ }
+ XmlBeansUtil.validateDD(xmlObject);
+ return (WebAppDocument) xmlObject;
+ }
+
+ /**
+ * Perform some validation on the web.xml information.
+ *
+ * @param webApp The source configuration file information.
+ *
+ * @exception DeploymentException
+ */
+ protected static void check(WebAppType webApp) throws DeploymentException {
+ checkURLPattern(webApp);
+ checkMultiplicities(webApp);
+ }
+
+ /**
+ * Validate that the urlPatterns defined in the configuration
+ * file conform to URL constraints.
+ *
+ * @param webApp The source configuration data.
+ *
+ * @exception DeploymentException
+ */
+ private static void checkURLPattern(WebAppType webApp) throws DeploymentException {
+
+ FilterMappingType[] filterMappings = webApp.getFilterMappingArray();
+ for (FilterMappingType filterMapping : filterMappings) {
+ UrlPatternType[] urlPatterns = filterMapping.getUrlPatternArray();
+ for (int j = 0; (urlPatterns != null) && (j < urlPatterns.length); j++) {
+ checkString(urlPatterns[j].getStringValue().trim());
+ }
+ }
+
+ ServletMappingType[] servletMappings = webApp.getServletMappingArray();
+ for (ServletMappingType servletMapping : servletMappings) {
+ UrlPatternType[] urlPatterns = servletMapping.getUrlPatternArray();
+ for (int j = 0; (urlPatterns != null) && (j < urlPatterns.length); j++) {
+ checkString(urlPatterns[j].getStringValue().trim());
+ }
+ }
+
+ SecurityConstraintType[] constraints = webApp.getSecurityConstraintArray();
+ for (SecurityConstraintType constraint : constraints) {
+ WebResourceCollectionType[] collections = constraint.getWebResourceCollectionArray();
+ for (WebResourceCollectionType collection : collections) {
+ UrlPatternType[] patterns = collection.getUrlPatternArray();
+ for (UrlPatternType pattern : patterns) {
+ checkString(pattern.getStringValue().trim());
+ }
+ }
+ }
+ }
+
+ protected static void checkString(String pattern) throws DeploymentException {
+ //j2ee_1_4.xsd explicitly requires preserving all whitespace. Do not trim.
+ if (pattern.indexOf(0x0D) >= 0) throw new DeploymentException("<url-pattern> must not contain CR(#xD)");
+ if (pattern.indexOf(0x0A) >= 0) throw new DeploymentException("<url-pattern> must not contain LF(#xA)");
+ }
+
+ private static void checkMultiplicities(WebAppType webApp) throws DeploymentException {
+ if (webApp.getSessionConfigArray().length > 1)
+ throw new DeploymentException("Multiple <session-config> elements found");
+ if (webApp.getJspConfigArray().length > 1)
+ throw new DeploymentException("Multiple <jsp-config> elements found");
+ if (webApp.getLoginConfigArray().length > 1)
+ throw new DeploymentException("Multiple <login-config> elements found");
+ }
+
+ protected void configureBasicWebModuleAttributes() throws DeploymentException {
+ if (!webApp.getMetadataComplete()) {
+ // Create a classfinder and populate it for processing the configuration.
+ // classFinder in the module will convey whether metadata-complete is set (or not)
+ classFinder = createWebAppClassFinder(webApp, webModule);
+ }
+ // do we have potential annotations to process? Go look for security annotations
+ if (classFinder != null) {
+ SecurityAnnotationHelper.processAnnotations(webApp, classFinder);
+ }
+ //N.B. we use the ear context which has all the gbeans we could possibly be looking up from this ear.
+ //nope, persistence units can be in the war.
+ //This means that you cannot use the default environment of the web builder to add configs that will be searched.
+ getNamingBuilders().buildNaming(webApp, vendorPlan, webModule, buildingContext);
+
+ Map compContext = NamingBuilder.JNDI_KEY.get(buildingContext);
+ Holder holder = NamingBuilder.INJECTION_KEY.get(buildingContext);
+
+ webModule.getSharedContext().put(WebModule.WEB_APP_DATA, webModuleData);
+ webModule.getSharedContext().put(NamingBuilder.JNDI_KEY, compContext);
+ webModule.getSharedContext().put(NamingBuilder.INJECTION_KEY, holder);
+ if (moduleContext.getServerName() != null) {
+ webModuleData.setReferencePattern("J2EEServer", moduleContext.getServerName());
+ }
+ if (!webModule.isStandAlone()) {
+ webModuleData.setReferencePattern("J2EEApplication", earContext.getModuleName());
+ }
+
+ webModuleData.setAttribute("holder", holder);
+
+ //Add dependencies on managed connection factories and ejbs in this app
+ //This is overkill, but allows for people not using java:comp context (even though we don't support it)
+ //and sidesteps the problem of circular references between ejbs.
+ if (earContext != moduleContext) {
+ addGBeanDependencies(earContext, webModuleData);
+ }
+
+ webModuleData.setAttribute("componentContext", compContext);
+ webModuleData.setReferencePattern("TransactionManager", moduleContext.getTransactionManagerName());
+ webModuleData.setReferencePattern("TrackedConnectionAssociator", moduleContext.getConnectionTrackerName());
+ }
+
+
+ /**
+ * Retrieve the fully resolved context path for this instance.
+ *
+ * @return The fully resolved context path.
+ */
+ public String getContextPath() {
+ return path;
+ }
+
+ /**
+ * Set the container context for this application. This is
+ * is set by the container when the app is deployed.
+ *
+ * @param ctx The new context for this application.
+ */
+ public void setContext(Context ctx) {
+ context = ctx;
+ // set the bundle context attribute in the servlet context
+ context.getServletContainer().setAttribute(ATTRIBUTE_BUNDLE_CONTEXT, bundle.getBundleContext());
+ if (context instanceof StandardContext) {
+ statsProvider = new ModuleStats((StandardContext)context);
+ }
+ }
+
+ /**
+ * Retrieve the deployment context for this application.
+ *
+ * @return The container-provided deployment context.
+ */
+ public Context getContext() {
+ return context,
+ }
+
+ /**
+ * Return the docbase for this application context.
+ *
+ * @return Always returns "" since we can't portably map this to a file
+ * location.
+ */
+ public String getDocBase() {
+ return ""; // the bundle is installed, and doesn't really have a docbase location
+ }
+
+ public SecurityHolder getSecurityHolder() {
+ // we don't have a security holder to work about
+ return null;
+ }
+
+ public void String getVirtualServer() {
+ // no virtual server either
+ return null;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public UserTransaction getUserTransaction() {
+ return null;
+ }
+
+ public javax.naming.Context getJndiContext() {
+ return null;
+ }
+
+ public Kernel getKernel() {
+ return null;
+ }
+
+ public Set getApplicationManagedSecurityResources() {
+ return null;
+ }
+
+ public TrackedConnectionAssociator getTrackedConnectionAssociator() {
+ return null;
+ }
+
+ public Set getUnshareableResources() {
+ return null;
+ }
+
+ public Realm getRealm() {
+ return null;
+ }
+
+ public Valve getClusteredValve() {
+ return null;
+ }
+
+ public List getValveChain() {
+ return null;
+ }
+
+ public List getLifecycleListenerChain() {
+ return null;
+ }
+
+ public CatalinaCluster getCluster() {
+ return null;
+ }
+
+ public Manager getManager() {
+ return null;
+ }
+
+ public boolean isCrossContext() {
+ return false;
+ }
+
+ public String getWorkDir() {
+ return workDir;
+ }
+
+ public boolean isDisableCookies() {
+ return false;
+ }
+
+ public Map getWebServices() {
+ return null;
+ }
+
+ /**
+ * Create an instance manager for this WAB context. This
+ * is basically an empty context that's dummied up.
+ *
+ * @return A dummy, empty, InstanceManager instance.
+ */
+ public InstanceManager getInstanceManager() {
+ return new TomcatInstanceManager(holder, classLoader, new ImmutableContext(new HashMap(), false));
+ }
+
+ // JSR 77 statistics - The static values are initialized at the time of
+ // creation, getStats return fresh value everytime
+ public Stats getStats() {
+ if (resetStats) {
+ resetStats = false;
+ return statsProvider.getStats();
+ }
+ else {
+ return statsProvider.updateStats();
+ }
+ }
+
+ public void resetStats() {
+ resetStats = true;
+ }
+
+
+ /**
+ * Perform resource cleanup when the servlet context is
+ * destroyed.
+ */
+ public destroy() {
+ statsProvider = null;
+ }
+}
+
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/AbstractOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,235 @@
+/*
+ * 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.geronimo.osgi.web.extender;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.transaction.UserTransaction;
+
+import org.apache.InstanceManager;
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.osgi.BundleClassLoader;
+import org.apache.geronimo.tomcat.util.SecurityHolder;
+import org.apache.tomcat.TomcatContext;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class TomcatOSGiWebAppContext implements TomcatContext, StatisticsProvider {
+ // the bundle where this application resides
+ protected Bundle bundle;
+ // the fully resolved context path
+ protected String path;
+ // the Tomcat-specific context
+ protected Context context = context;
+ // our wrappered class loader
+ protected ClassLoader classLoader;
+ // the working directory for JSP compilation
+ protected File workDir;
+ // a Holder used for annotation processing. We just
+ // create a default empty one
+ protected final Holder holder;
+ // used for managing the usage statistics
+ private ModuleStats statsProvider;
+ private boolean resetStats = true;
+
+
+
+ public TomcatOSGiWebAppContext(Bundle bundle, String contextPath) {
+ this.bundle = bundle;
+ this.path = contextPath.startsWith("/") ? contextPath : "/" + contextPath;
+ // we give the container a classloader wrapped around the bundle
+ this.classLoader = new BundleClassLoader(bundle);
+
+ // get the root of the framework provided persistence area
+ File base = bundle.getBundleContext().getDataFile("");
+ // create a working directory for this bundle, and attempt to create it.
+ workDir = new File(base, "webApp");
+ workDir.mkdir();
+ // the container requires this, but a default empty one
+ // is sufficient
+ this.holder = new Holder();
+ }
+
+ /**
+ * Retrieve the fully resolved context path for this instance.
+ *
+ * @return The fully resolved context path.
+ */
+ public String getContextPath() {
+ return path;
+ }
+
+ /**
+ * Set the container context for this application. This is
+ * is set by the container when the app is deployed.
+ *
+ * @param ctx The new context for this application.
+ */
+ public void setContext(Context ctx) {
+ context = ctx;
+ // set the bundle context attribute in the servlet context
+ context.getServletContainer().setAttribute(ATTRIBUTE_BUNDLE_CONTEXT, bundle.getBundleContext());
+ if (context instanceof StandardContext) {
+ statsProvider = new ModuleStats((StandardContext)context);
+ }
+ }
+
+ /**
+ * Retrieve the deployment context for this application.
+ *
+ * @return The container-provided deployment context.
+ */
+ public Context getContext() {
+ return context,
+ }
+
+ /**
+ * Return the docbase for this application context.
+ *
+ * @return Always returns "" since we can't portably map this to a file
+ * location.
+ */
+ public String getDocBase() {
+ return ""; // the bundle is installed, and doesn't really have a docbase location
+ }
+
+ public SecurityHolder getSecurityHolder() {
+ // we don't have a security holder to work about
+ return null;
+ }
+
+ public void String getVirtualServer() {
+ // no virtual server either
+ return null;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public UserTransaction getUserTransaction() {
+ return null;
+ }
+
+ public javax.naming.Context getJndiContext() {
+ return null;
+ }
+
+ public Kernel getKernel() {
+ return null;
+ }
+
+ public Set getApplicationManagedSecurityResources() {
+ return null;
+ }
+
+ public TrackedConnectionAssociator getTrackedConnectionAssociator() {
+ return null;
+ }
+
+ public Set getUnshareableResources() {
+ return null;
+ }
+
+ public Realm getRealm() {
+ return null;
+ }
+
+ public Valve getClusteredValve() {
+ return null;
+ }
+
+ public List getValveChain() {
+ return null;
+ }
+
+ public List getLifecycleListenerChain() {
+ return null;
+ }
+
+ public CatalinaCluster getCluster() {
+ return null;
+ }
+
+ public Manager getManager() {
+ return null;
+ }
+
+ public boolean isCrossContext() {
+ return false;
+ }
+
+ public String getWorkDir() {
+ return workDir;
+ }
+
+ public boolean isDisableCookies() {
+ return false;
+ }
+
+ public Map getWebServices() {
+ return null;
+ }
+
+ /**
+ * Create an instance manager for this WAB context. This
+ * is basically an empty context that's dummied up.
+ *
+ * @return A dummy, empty, InstanceManager instance.
+ */
+ public InstanceManager getInstanceManager() {
+ return new TomcatInstanceManager(holder, classLoader, new ImmutableContext(new HashMap(), false));
+ }
+
+ // JSR 77 statistics - The static values are initialized at the time of
+ // creation, getStats return fresh value everytime
+ public Stats getStats() {
+ if (resetStats) {
+ resetStats = false;
+ return statsProvider.getStats();
+ }
+ else {
+ return statsProvider.updateStats();
+ }
+ }
+
+ public void resetStats() {
+ resetStats = true;
+ }
+
+
+ /**
+ * Perform resource cleanup when the servlet context is
+ * destroyed.
+ */
+ public destroy() {
+ statsProvider = null;
+ }
+}
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,373 @@
+/*
+ * 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.geronimo.osgi.web.extender;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URL;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.aries.blueprint.container.WebContainerEventDispatcher;
+import org.apache.geronimo.tomcat.TomcatContext;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An instance of a WAB deployed to an available Web Container
+ * instance.
+ * @version $Rev$, $Date$
+ */
+public class WebApplicationImpl implements WebApplication, Runnable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(WebApplicationImpl.class);
+
+ // the bundle where the web application resides
+ private final Bundle bundle;
+ // the deployed context path from the bundle headers
+ private final String contextPath;
+ // the extender bundle that's handling this deployment
+ private final Bundle extenderBundle;
+ // the dispatcher service used for handling events.
+ private final WebContainerEventDispatcher eventDispatcher;
+ // our threadpool for asynch dispatch operations
+ private final ScheduledExecutorService executors;
+ private final AtomicBoolean scheduled = new AtomicBoolean();
+ // our servlet context
+ private ServletContext *context;
+ // the container we deploy to
+ private WebContainerService container;
+
+ private static final String CLASSPATH_HEADER = "Bundle-ClassPath";
+ private static final String WEB_INF_CLASSES = "WEB-INF/classes";
+
+ // service properties published when the app deploys
+ private static final String CONTEXT_SYMBOLIC_NAME_PROPERTY = "osgi.web.symbolicname";
+ private static final String CONTEXT_VERSION_PROPERTY = "osgi.web.version";
+ private static final String CONTEXT_CONTEXT_PATH_PROPERTY = "osgi.web.contextpath";
+
+ /**
+ * Construct a WebApplicationImp object to represent a
+ * WAB-resident application.
+ *
+ * @param bundle The bundle containing the WAB.
+ * @param extenderBundle
+ * The RFC 66 container managing the deployment.
+ * @param eventDispatcher
+ * The event dispatcher for broadcasting state changes.
+ * @param executors The common thread pool for scheduling asynchronous processing.
+ * @param contextPath
+ * The context path from the WAB headers.
+ */
+ public WebApplicationImpl(Bundle bundle, Bundle extenderBundle, WebContainerService container, WebContainerEventDispatcher eventDispatcher, ScheduledExecutorService executors, String contextPath) {
+ this.bundleContext = bundleContext;
+ this.extenderBundle = extenderBundle;
+ this.eventDispatcher = eventDispatcher;
+ this.contextPath = contextPath;
+ this.executors = executors;
+ this.container = container;
+ // create an access control context for performing
+ // registration activities
+ if (System.getSecurityManager() != null) {
+ this.accessControlContext = createAccessControlContext();
+ }
+ }
+
+ /**
+ * Provide access to the bundle where the application resides.
+ *
+ * @return The Bundle instance for the WAB.
+ */
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+
+ /**
+ * Retrieve the extender bundle hosting this application instance.
+ *
+ * @return The extender Bundle instance.
+ */
+ public Bundle getExtenderBundle() {
+ return extenderBundle;
+ }
+
+ /**
+ * Get the event dispatcher instance associated with this
+ * application.
+ *
+ * @return The configured event dispatcher information.
+ */
+ public WebContainerEventDispatcher getEventDispatcher() {
+ return eventDispatcher;
+ }
+
+ /**
+ * Schedule this handler for deployment processing.
+ */
+ public void schedule() {
+ // only one scheduled startup at a time.
+ if (scheduled.compareAndSet(false, true)) {
+ executors.submit(this);
+ }
+ }
+
+ /**
+ * Run the application deployment process in a separate thread.
+ */
+ public void run() {
+ scheduled.set(false);
+ synchronized (scheduled) {
+ doRun();
+ }
+ }
+
+ // private methods for managing event broadcasts.
+ private void deploying() {
+ eventDispatcher.deploying(bundle, contextPath);
+ }
+
+ private void deployed() {
+ eventDispatcher.deployed(bundle, contextPath);
+ }
+
+
+ private void undeploying() {
+ eventDispatcher.undeploying(bundle, contextPath);
+ }
+
+ private void undeployed() {
+ eventDispatcher.undeployed(bundle, contextPath);
+ }
+
+ private void failed(Throwable cause) {
+ eventDispatcher.failed(bundle, contextPath, cause);
+ }
+
+ /**
+ * This method must be called inside a synchronized block to ensure this method is not run concurrently
+ */
+ private void doRun() {
+ try {
+ if (destroyed) {
+ return;
+ }
+ LOGGER.debug("Running web container container for bundle {}", getBundle().getSymbolicName());
+ // send out a broadcast alert that we're going to do this
+ deploying();
+ // validate all of the required elements of the WAB
+ validateMetadata();
+ // ask the container to deploy this
+ container.deploy(this);
+ // register the servlet context
+ registerServletContext();
+ // send out the deployed event
+ deployed();
+ } catch (Throwable t) {
+ state = State.Failed;
+ LOGGER.error("Unable to start web application for bundle " + getBundle().getSymbolicName(), t);
+ // broadcast a failure event
+ failed();
+ }
+ }
+
+
+ /**
+ * Register the ServletContext for this web application
+ * in the service registry
+ */
+ private void registerServletContext() {
+ Properties props = new Properties();
+ props.put(BlueprintConstants.CONTEXT_SYMBOLIC_NAME_PROPERTY, bundleContext.getBundle().getSymbolicName());
+ props.put(BlueprintConstants.CONTEXT_VERSION_PROPERTY, getBundleVersion(bundleContext.getBundle()));
+ props.put(BlueprintConstants.CONTEXT_CONTEXT_PATH_PROPERTY, contextPath);
+ registration = registerService(new String [] { ServletContext.class.getName() }, this.getServletContext(), props);
+ }
+
+
+ /**
+ * unregister the ServletContext for this web application
+ * in the service registry
+ */
+ private void unregisterServletContext() {
+ // unregister the servlet context instance
+ registration.unregister();
+ }
+
+ /**
+ * Register a service using the access control context of
+ * the hosting bundle.
+ *
+ * @param classes The interface classes for the service.
+ * @param service The service instance.
+ * @param properties The service properties.
+ *
+ * @return The ServiceRegistration instance for a successful registration.
+ */
+ public ServiceRegistration registerService(final String[] classes, final Object service, final Dictionary properties) {
+ if (accessControlContext == null) {
+ return bundleContext.registerService(classes, service, properties);
+ } else {
+ return AccessController.doPrivileged(new PrivilegedAction<ServiceRegistration>() {
+ public ServiceRegistration run() {
+ return bundleContext.registerService(classes, service, properties);
+ }
+ }, accessControlContext);
+ }
+ }
+
+ /**
+ * Create an AccessControlContext instance that allows
+ * the web bundle's permission set to be used for extender
+ * operations.
+ *
+ * @return An AccessControlContext that delegates to the BundleContext.
+ */
+ private AccessControlContext createAccessControlContext() {
+ return new AccessControlContext(AccessController.getContext(),
+ new DomainCombiner() {
+ public ProtectionDomain[] combine(ProtectionDomain[] arg0,
+ ProtectionDomain[] arg1) {
+ return new ProtectionDomain[] { new ProtectionDomain(null, null) {
+ public boolean implies(Permission permission) {
+ return bundle.getBundleContext().hasPermission(permission);
+ }
+ }
+ };
+ }
+ });
+ }
+
+ public AccessControlContext getAccessControlContext() {
+ return accessControlContext;
+ }
+
+ /**
+ * Undeploy a web application.
+ */
+ public void undeploy() {
+ destroyed = true;
+ // send the undeploying event
+ undeploying();
+ // remove this from the servlet container
+ container.undeploy(this);
+ // remove the servlet context
+ unregisterServletContext();
+ // finished with the undeploy operation
+ undeployed();
+ LOGGER.debug("Web container destroyed: {}", this.bundle);
+ }
+
+
+ /**
+ * Set a container-specific context object for this web
+ * application as an opaque object.
+ *
+ * @param context The new context.
+ */
+ public void setContext(Object context) {
+ // this is the main context
+ this.context = context;
+ }
+
+
+ /**
+ * Retrieve the context associated with the application
+ *
+ * @return
+ */
+ public Object getContext() {
+ return context;
+ }
+
+
+ /**
+ * Set the servlet context associated with this web app. This
+ * will be registered as a service instance.
+ *
+ * @param servletContext
+ * The target servlet context.
+ */
+ public void setServletContext(ServletContext *servletContext) {
+ this.servletContext = servletContext;
+ }
+
+
+ /**
+ * Request the ServletContext instance associated with this
+ * application.
+ *
+ * @return
+ */
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+
+ /**
+ * Validate the spec-defined constraints on a WAB. These
+ * constraints are:
+ *
+ * 1) If the WAB bundle class path specifies WEB-INF/classes, it
+ * must be the first entry in the class path.
+ *
+ * 2) If the WAB contains a WEB-INF/classes directory, then
+ * that directory must be list as the first entry on the
+ * Bundle-Classpath.
+ */
+ public void validateMetadata() {
+ String classPathHeader = (String) bundle.getHeaders().get("Bundle-ClassPath");
+ // the default header
+ if (classPathHeader == null) {
+ classPathHeader = ".";
+ }
+
+ // split this into the individual path elements
+ String[] pathes = classPathHeader.split(",");
+ int webInfPath = -1;
+ // scan for WEB-INF/classes on the class path. If there, it must
+ // be the first entry
+ for (int i = 0; i < webInfPath.length; i++) {
+ if (pathes[i].equals(WEB_INF_CLASSES)) {
+ if (i > 0) {
+ throw new IllegalArgumentException("WEB-INF/classes must be first entry in the bundle classpath");
+ }
+ // mark it as the first item
+ webInfPath = 0;
+ break
+ }
+ }
+
+ // now check if the bundle contains a WEB-INF/classes directory. If one is there, then
+ // it is required to be the first entry in the bundle classpath.
+ URL webClasses = bundle.getEntry(WEB_INF_CLASSES);
+ if (webClasses != null && webInfPatch != 0) {
+ throw new IllegalArgumentException("WEB-INF/classes must be first entry in the bundle classpath");
+ }
+ }
+}
+
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebApplicationImpl.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,177 @@
+/**
+ * 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.aries.blueprint.container;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.aries.blueprint.utils.JavaUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
+import org.osgi.service.blueprint.container.BlueprintEvent;
+import org.osgi.service.blueprint.container.BlueprintListener;
+import org.osgi.service.blueprint.container.EventConstants;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Support for dispatching Web container lifecycle events to
+ * the EventAdmin service, if it's available.
+ * @version $Rev$, $Date$
+ */
+public class WebContainerEventDispatcher {
+
+ public static final String DEPLOYING = "org/osgi/service/web/DEPLOYING";
+ public static final String DEPLOYED = "org/osgi/service/web/DEPLOYED";
+ public static final String UNDEPLOYING = "org/osgi/service/web/UNDEPLOYING";
+ public static final String UNDEPLOYED = "org/osgi/service/web/UNDEPLOYED";
+ public static final String FAILED = "org/osgi/service/web/FAILED";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(WebContainerEventDispatcher.class);
+
+ // our service tracker for the EventAdmin service
+ private ServiceTracker tracker;
+ // the extender bundle we're working on behalf of
+ private Bundle extenderBundle;
+
+
+ public WebContainerEventDispatcher(final BundleContext bundleContext) {
+ // this will track the availability of the EventAdmin service when we need to dispatch
+ tracker = new ServiceTracker(context, org.osgi.service.event.EventAdmin, null);
+ tracker.open();
+ }
+
+
+ /**
+ * Dispatch a deploying event
+ *
+ * @param bundle The bundle we're deploying.
+ * @param contextPath
+ * The context path information from the bundle.
+ */
+ public void deploying(Bundle bundle, String contextPath) {
+ dispatch(DEPLOYING, bundle, contextPath, null);
+ }
+
+
+ /**
+ * Dispatch a deployed event
+ *
+ * @param bundle The bundle we're deploying.
+ * @param contextPath
+ * The context path information from the bundle.
+ */
+ public void deployed(Bundle bundle, String contextPath) {
+ dispatch(DEPLOYED, bundle, contextPath, null);
+ }
+
+
+ /**
+ * Dispatch an undeploying event
+ *
+ * @param bundle The bundle we're undeploying.
+ * @param contextPath
+ * The context path information from the bundle.
+ */
+ public void undeploying(Bundle bundle, String contextPath) {
+ dispatch(UNDEPLOYING, bundle, contextPath, null);
+ }
+
+
+ /**
+ * Dispatch an undeployed event
+ *
+ * @param bundle The bundle we're undeploying.
+ * @param contextPath
+ * The context path information from the bundle.
+ */
+ public void undeployed(Bundle bundle, String contextPath) {
+ dispatch(UNDEPLOYED, bundle, contextPath, null);
+ }
+
+
+ /**
+ * Dispatch a FAILED event
+ *
+ * @param bundle The bundle we're attempting to deploy
+ * @param contextPath
+ * The context path information from the bundle.
+ */
+ public void failed(Bundle bundle, String contextPath, Throwable cause) {
+ dispatch(FAILREd, bundle, contextPath, cause);
+ }
+
+ /**
+ * Dispatch an event to the appropriate listeners.
+ *
+ * @param topic The event topic.
+ * @param bundle The bundle hosting the web application.
+ * @param contextPath
+ * The contextPath information from the bundle.
+ * @param cause The potential cause information for the exception.
+ */
+ public void dispatch(String topic, Bundle bundle, String contextPath, Throwable cause) {
+ EventAdmin eventAdmin = (EventAdmin) tracker.getService();
+ if (eventAdmin == null) {
+ return;
+ }
+
+ Dictionary<String,Object> props = new Hashtable<String,Object>();
+ props.put(EventConstants.TYPE, event.getType());
+ props.put(EventConstants.EVENT, event);
+ props.put(EventConstants.TIMESTAMP, System.currentTimeMillis());
+ props.put(EventConstants.BUNDLE, bundle);
+ props.put(EventConstants.BUNDLE_SYMBOLICNAME, bundle.getSymbolicName());
+ props.put(EventConstants.BUNDLE_ID, bundle.getBundleId());
+ props.put(EventConstants.BUNDLE_VERSION, getBundleVersion(bundle));
+ props.put("context.path", contextPath);
+ props.put(EventConstants.EXTENDER_BUNDLE, extenderBundle);
+ props.put(EventConstants.EXTENDER_BUNDLE_ID, extenderBundle.getBundleId());
+ props.put(EventConstants.EXTENDER_BUNDLE_SYMBOLICNAME, extenderBundle.getSymbolicName());
+ props.put(EventConstants.EXTENDER_BUNDLE_VERSION, getBundleVersion(extenderBundle));
+ if (cause != null) {
+ props.put(EventConstants.EXCEPTION, cause);
+ }
+ eventAdmin.postEvent(new Event(topic, props));
+ }
+
+ public void destroy() {
+ this.tracker.close();
+ }
+
+ private Version getBundleVersion(Bundle bundle) {
+ Dictionary headers = bundle.getHeaders();
+ String version = (String)headers.get(Constants.BUNDLE_VERSION);
+ return (version != null) ? Version.parseVersion(version) : Version.emptyVerion;
+ }
+}
+
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerEventDispatcher.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,196 @@
+/**
+ * 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.geronimo.osgi.web.extender;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An extender bundle to manage deployment of Web
+ * Application Bundles (WABs) to the RFC 66 web container.
+ * @version $Rev$, $Date$
+ */
+public class WebContainerExtender implements BundleActivator, SynchronousBundleListener {
+ // the header that identifies a bundle as being a WAB
+ public final static String WEB_CONTEXT_PATH_HEADER = "Web-ContextPath";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(BlueprintExtender.class);
+
+ private BundleContext context;
+ private ScheduledExecutorService executors;
+ private Map<Bundle, WebApplicationBundle> wabs;
+ private WebContainerEventDispatcher eventDispatcher;
+
+ /**
+ * Activate the bundle and initialize the extender instance.
+ *
+ * @param context The BundleContext for our bundle.
+ */
+ public void start(BundleContext context) {
+ LOGGER.debug("Starting blueprint extender...");
+
+ this.context = context;
+ eventDispatcher = new WebContainerEventDispatcher(context);
+ executors = Executors.newScheduledThreadPool(3);
+ containers = new HashMap<Bundle, WebApplicationBundle>();
+
+ // start listening for bundle events
+ context.addBundleListener(this);
+ LOGGER.debug("Blueprint extender started");
+ }
+
+
+ /**
+ * Handle initial startup processing once we've been activated
+ * and have web container service that we can deploy to.
+ */
+ protected void handleInitialStartup() {
+ // we need to check all of the active bundles at startup to see if
+ // there are any WABs installed that require startup.
+ Bundle[] bundles = context.getBundles();
+ for (Bundle b : bundles) {
+ // If the bundle is active, check it
+ if (b.getState() == Bundle.ACTIVE) {
+ checkBundle(b);
+ // Also check bundles in the starting state with a lazy activation policy
+ } else if (b.getState() == Bundle.STARTING) {
+ String activationPolicyHeader = (String) b.getHeaders().get(Constants.BUNDLE_ACTIVATIONPOLICY);
+ if (activationPolicyHeader != null && activationPolicyHeader.startsWith(Constants.ACTIVATION_LAZY)) {
+ checkBundle(b);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Shutdown the extender bundle at termination time.
+ *
+ * @param context Our BundleContext.
+ */
+ public void stop(BundleContext context) {
+ LOGGER.debug("Stopping blueprint extender...");
+ context.removeBundleListener(this);
+ // There's no shutdown ordering of the containers, so just
+ // iterate over the list
+ for (WebApplication wab : wabs) {
+ destroyContext(wab);
+ }
+
+ this.eventDispatcher.destroy();
+ executors.shutdown();
+ LOGGER.debug("Blueprint extender stopped");
+ }
+
+ /**
+ * Handle state changes in the bundles to determine if
+ * it is time to start or destroy an instance.
+ *
+ * @param event The broadcast event.
+ */
+ public void bundleChanged(BundleEvent event) {
+ Bundle bundle = event.getBundle();
+ // we start processing these upon a lazy activation.
+ if (event.getType() == BundleEvent.LAZY_ACTIVATION) {
+ checkBundle(bundle);
+ } else if (event.getType() == BundleEvent.STARTED) {
+ // the bundle is fully started. This might be a transition to
+ // the STARTED state for a lazy activated bundle, so only process
+ // this if the bundles not already in our active list.
+ WebApplication wab = wabs.get(bundle);
+ // not seen this one before, go check if it requires processing
+ // and kick off the deployment if required.
+ if (wab == null) {
+ checkBundle(bundle);
+ }
+ } else if (event.getType() == BundleEvent.STOPPING) {
+ // a bundle is stopping. Check to see if this is one we're managing
+ // and kick off the processing.
+ WebApplication wab = wabs.get(bundle);
+ // If this bundle is one we've processed, handle the undeployment
+ // and shutdown of the bundle.
+ if (wab != null) {
+ destroyContext(wab);
+ }
+ }
+ }
+
+ /**
+ * Destroy a web application deployment, either as a result
+ * of the host bundle getting started, the extended getting stopped,
+ * or the hosting Web Container service going away.
+ *
+ * @param wab The deployed application.
+ */
+ private void destroyContext(WebApplication wab) {
+ // remove from our global list before destroying
+ Bundle bundle = wab.getBundle();
+
+ wabs.remove(bundle);
+ LOGGER.debug("Destroying ServletContext for bundle {}", bundle.getSymbolicName());
+ // destroy the context
+ wab.destroy();
+ // and broadcast the destroy event
+ eventDispatcher.contextDestroyed(bundle);
+ }
+
+ /**
+ * Check a started bundle to detect if this bundle
+ * should be handled by this extender instance.
+ *
+ * @param bundle The source bundle.
+ */
+ private void checkBundle(Bundle bundle) {
+ LOGGER.debug("Scanning bundle {} for WAB application", bundle.getSymbolicName());
+ try {
+ List<Object> pathList = new ArrayList<Object>();
+ String contextPathHeader = (String) bundle.getHeaders().get(WEB_CONTEXT_PATH_HEADER);
+ // a WAB MUST have the Web-ContextPath header or it must be ignored by the extender.
+ if (contextPathHeader == null) {
+ LOGGER.debug("No web container application found in bundle {}", bundle.getSymbolicName());
+ return;
+ }
+ LOGGER.debug("Found web container application in bundle {} with context path: {}", bundle.getSymbolicName(), contextPathHeader);
+ WebApplicationBundle webApp = new WebApplicationBundle(bundle, context.getBundle(), eventDispatcher, webContainer, executors, contextPathHeader);
+ wabs.put(bundle, webApp);
+ webApp.schedule();
+ } catch (Throwable t) {
+ eventDispatcher.dispatch(new WebContainerEvent(WebContainerEvent.FAILURE, bundle, context.getBundle(), t));
+ }
+ }
+}
+
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/extender/WebContainerExtender.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,363 @@
+/*
+ * 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.geronimo.osgi.web.extender;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.transaction.UserTransaction;
+
+import org.apache.InstanceManager;
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.osgi.BundleClassLoader;
+import org.apache.geronimo.tomcat.util.SecurityHolder;
+import org.apache.tomcat.TomcatContext;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class TomcatOSGiWebAppContext implements TomcatContext, StatisticsProvider {
+ // the Tomcat-specific deployment descriptor
+ TomcatWebAppType tomcatWebApp;
+ // the working directory for JSP compilation
+ protected File workDir;
+ // a Holder used for annotation processing. We just
+ // create a default empty one
+ protected final Holder holder;
+ // used for managing the usage statistics
+ protected ModuleStats statsProvider;
+ protected boolean resetStats = true;
+ // our displayable name, if any
+ protected String displayName;
+ // our virtual server name, if configured
+ protected String virtualServer;
+
+ public TomcatOSGiWebAppContext(Bundle bundle, String contextPath) {
+ super(bundle, contextPath);
+
+ // parse the vendor-specific deployment descriptor
+ tomcatWebApp = getTomcatWebApp();
+
+ // get the root of the framework provided persistence area
+ File base = bundle.getBundleContext().getDataFile("");
+ // create a working directory for this bundle, and attempt to create it.
+ workDir = new File(base, "webApp");
+ workDir.mkdir();
+ // the container requires this, but a default empty one
+ // is sufficient
+ this.holder = new Holder();
+ }
+
+
+ TomcatWebAppType getTomcatWebApp() throws DeploymentException {
+ XmlObject rawPlan = null;
+ try {
+ // load the geronimo-web.xml from either the supplied plan or from the earFile
+ try {
+ // look for Geronimo-specific file first
+ URL path = bundle.getEntry("WEB-INF/geronimo-web.xml");
+ try {
+ rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
+ } catch (FileNotFoundException e) {
+ path = DeploymentUtil.createJarURL(moduleFile, "WEB-INF/geronimo-tomcat.xml");
+ try {
+ rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
+ } catch (FileNotFoundException e1) {
+ log.warn("Web application in bundle " + bundle + " does not contain a WEB-INF/geronimo-web.xml deployment plan. This may or may not be a problem, depending on whether you have things like resource references that need to be resolved.");
+ }
+ }
+ } catch (IOException e) {
+ log.warn("Failed to load geronimo-web.xml for bundle " + bundle, e);
+ }
+
+ TomcatWebAppType tomcatWebApp;
+ if (rawPlan != null) {
+ XmlObject webPlan = new GenericToSpecificPlanConverter(GerTomcatDocument.type.getDocumentElementName().getNamespaceURI(),
+ TomcatWebAppDocument.type.getDocumentElementName().getNamespaceURI(), "tomcat").convertToSpecificPlan(rawPlan);
+ tomcatWebApp = (TomcatWebAppType) webPlan.changeType(TomcatWebAppType.type);
+ XmlBeansUtil.validateDD(tomcatWebApp);
+ } else {
+ // create a default plae
+ tomcatWebApp = TomcatWebAppType.Factory.newInstance();
+ }
+ return tomcatWebApp;
+ } catch (XmlException e) {
+ throw new DeploymentException("xml problem for web app in bundle " + bundle, e);
+ }
+ }
+
+ protected void configureContext() throws DeploymentException {
+// configureBasicWebModuleAttributes(webApp, tomcatWebApp, moduleContext, earContext, webModule, webModuleData);
+ try {
+ //get Tomcat display-name
+ if (webApp.getDisplayNameArray().length > 0) {
+ displayName = webApp.getDisplayNameArray()[0].getStringValue();
+ }
+
+ // Process the Tomcat container-config elements
+ if (tomcatWebApp.isSetHost()) {
+ virtualServer = tomcatWebApp.getHost().trim();
+ }
+ if (tomcatWebApp.isSetCrossContext()) {
+ crossContext = true;
+ }
+ if (tomcatWebApp.isSetDisableCookies()) {
+ disableCookies = true;
+ }
+
+// if (tomcatWebApp.isSetTomcatRealm()) {
+// String tomcatRealm = tomcatWebApp.getTomcatRealm().trim();
+// AbstractName realmName = earContext.getNaming().createChildName(moduleName, tomcatRealm, RealmGBean.GBEAN_INFO.getJ2eeType());
+// webModuleData.setReferencePattern("TomcatRealm", realmName);
+// }
+
+// if (tomcatWebApp.isSetValveChain()) {
+// String valveChain = tomcatWebApp.getValveChain().trim();
+// AbstractName valveName = earContext.getNaming().createChildName(moduleName, valveChain, ValveGBean.J2EE_TYPE);
+// webModuleData.setReferencePattern("TomcatValveChain", valveName);
+// }
+
+// if (tomcatWebApp.isSetListenerChain()) {
+// String listenerChain = tomcatWebApp.getListenerChain().trim();
+// AbstractName listenerName = earContext.getNaming().createChildName(moduleName, listenerChain, LifecycleListenerGBean.J2EE_TYPE);
+// webModuleData.setReferencePattern("LifecycleListenerChain", listenerName);
+// }
+
+// if (tomcatWebApp.isSetCluster()) {
+// String cluster = tomcatWebApp.getCluster().trim();
+// AbstractName clusterName = earContext.getNaming().createChildName(moduleName, cluster, CatalinaClusterGBean.J2EE_TYPE);
+// webModuleData.setReferencePattern("Cluster", clusterName);
+// }
+
+// if (tomcatWebApp.isSetManager()) {
+// String manager = tomcatWebApp.getManager().trim();
+// AbstractName managerName = earContext.getNaming().createChildName(moduleName, manager, ManagerGBean.J2EE_TYPE);
+// webModuleData.setReferencePattern(TomcatWebAppContext.GBEAN_REF_MANAGER_RETRIEVER, managerName);
+// }
+
+// Boolean distributable = webApp.getDistributableArray().length == 1 ? TRUE : FALSE;
+// if (TRUE == distributable) {
+// clusteringBuilders.build(tomcatWebApp, earContext, moduleContext);
+// if (null == webModuleData.getReferencePatterns(TomcatWebAppContext.GBEAN_REF_CLUSTERED_VALVE_RETRIEVER)) {
+// log.warn("No clustering builders configured: app will not be clustered");
+// }
+// }
+
+
+ if (tomcatWebApp.isSetSecurityRealmName()) {
+ if (earContext.getSecurityConfiguration() == null) {
+ throw new DeploymentException("You have specified a <security-realm-name> for the web bundle " + bundle + " but no <security> configuration (role mapping) is supplied in the Geronimo plan for the web application");
+ }
+
+ SecurityHolder securityHolder = new SecurityHolder();
+ String securityRealmName = tomcatWebApp.getSecurityRealmName().trim();
+
+ webModuleData.setReferencePattern("RunAsSource", (AbstractNameQuery)earContext.getGeneralData().get(ROLE_MAPPER_DATA_NAME));
+ webModuleData.setReferencePattern("ConfigurationFactory", new AbstractNameQuery(null, Collections.singletonMap("name", securityRealmName), ConfigurationFactory.class.getName()));
+
+ /**
+ * TODO - go back to commented version when possible.
+ */
+ String policyContextID = moduleName.toString().replaceAll("[, :]", "_");
+ securityHolder.setPolicyContextID(policyContextID);
+
+ ComponentPermissions componentPermissions = buildSpecSecurityConfig(webApp);
+ earContext.addSecurityContext(policyContextID, componentPermissions);
+ //TODO WTF is this for?
+ securityHolder.setSecurity(true);
+
+ webModuleData.setAttribute("securityHolder", securityHolder);
+ //local jaspic configuration
+ if (tomcatWebApp.isSetAuthentication()) {
+ AuthenticationWrapper authType = new TomcatAuthenticationWrapper(tomcatWebApp.getAuthentication());
+ configureLocalJaspicProvider(authType, contextPath, module, webModuleData);
+ }
+
+ }
+ } catch (DeploymentException de) {
+ throw de;
+ } catch (Exception e) {
+ throw new DeploymentException("Unable to initialize GBean for web app " + module.getName(), e);
+ }
+ }
+
+ /**
+ * Retrieve the fully resolved context path for this instance.
+ *
+ * @return The fully resolved context path.
+ */
+ public String getContextPath() {
+ return path;
+ }
+
+ /**
+ * Set the container context for this application. This is
+ * is set by the container when the app is deployed.
+ *
+ * @param ctx The new context for this application.
+ */
+ public void setContext(Context ctx) {
+ context = ctx;
+ // set the bundle context attribute in the servlet context
+ context.getServletContainer().setAttribute(ATTRIBUTE_BUNDLE_CONTEXT, bundle.getBundleContext());
+ if (context instanceof StandardContext) {
+ statsProvider = new ModuleStats((StandardContext)context);
+ }
+ }
+
+ /**
+ * Retrieve the deployment context for this application.
+ *
+ * @return The container-provided deployment context.
+ */
+ public Context getContext() {
+ return context,
+ }
+
+ /**
+ * Return the docbase for this application context.
+ *
+ * @return Always returns "" since we can't portably map this to a file
+ * location.
+ */
+ public String getDocBase() {
+ return ""; // the bundle is installed, and doesn't really have a docbase location
+ }
+
+ public SecurityHolder getSecurityHolder() {
+ // we don't have a security holder to work about
+ return null;
+ }
+
+ public void String getVirtualServer() {
+ return virtualServer;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public UserTransaction getUserTransaction() {
+ return null;
+ }
+
+ public javax.naming.Context getJndiContext() {
+ return null;
+ }
+
+ public Kernel getKernel() {
+ return null;
+ }
+
+ public Set getApplicationManagedSecurityResources() {
+ return null;
+ }
+
+ public TrackedConnectionAssociator getTrackedConnectionAssociator() {
+ return null;
+ }
+
+ public Set getUnshareableResources() {
+ return null;
+ }
+
+ public Realm getRealm() {
+ return null;
+ }
+
+ public Valve getClusteredValve() {
+ return null;
+ }
+
+ public List getValveChain() {
+ return null;
+ }
+
+ public List getLifecycleListenerChain() {
+ return null;
+ }
+
+ public CatalinaCluster getCluster() {
+ return null;
+ }
+
+ public Manager getManager() {
+ return null;
+ }
+
+ public boolean isCrossContext() {
+ return false;
+ }
+
+ public String getWorkDir() {
+ return workDir;
+ }
+
+ public boolean isDisableCookies() {
+ return false;
+ }
+
+ public Map getWebServices() {
+ return null;
+ }
+
+ /**
+ * Create an instance manager for this WAB context. This
+ * is basically an empty context that's dummied up.
+ *
+ * @return A dummy, empty, InstanceManager instance.
+ */
+ public InstanceManager getInstanceManager() {
+ return new TomcatInstanceManager(holder, classLoader, new ImmutableContext(new HashMap(), false));
+ }
+
+ // JSR 77 statistics - The static values are initialized at the time of
+ // creation, getStats return fresh value everytime
+ public Stats getStats() {
+ if (resetStats) {
+ resetStats = false;
+ return statsProvider.getStats();
+ }
+ else {
+ return statsProvider.updateStats();
+ }
+ }
+
+ public void resetStats() {
+ resetStats = true;
+ }
+
+
+ /**
+ * Perform resource cleanup when the servlet context is
+ * destroyed.
+ */
+ public destroy() {
+ statsProvider = null;
+ }
+}
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebAppContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java?rev=891246&view=auto
==============================================================================
--- geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java (added)
+++ geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java Wed Dec 16 14:22:04 2009
@@ -0,0 +1,171 @@
+/*
+ * 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.geronimo.osgi.web.extender;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URL;
+import java.util.Properties;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.aries.blueprint.container.WebContainerEventDispatcher;
+import org.apache.geronimo.tomcat.TomcatContainer;
+import org.apache.geronimo.tomcat.TomcatContext;
+import org.apache.geronimo.tomcat.TomcatWebAppContext;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A service target for the RFC 66 Web Container extender to
+ * publish an application to the Geronimo-hosted Tomcat
+ * web container instance.
+ * @version $Rev$, $Date$
+ */
+public class TomcatOSGiWebContainer implements WebContainerService, GBeanLifeCycle {
+
+ private static final Logger log = LoggerFactory.getLogger(TomcatOSGiWebContainer.class);
+
+ /**
+ * The attributed used to retrieve the application bundle context.
+ */
+ public static final String ATTRIBUTE_BUNDLE_CONTEXT = "osgi-bundlecontext";
+
+ // the container we deploy to
+ protected final TomcatContainer container;
+ // our bundle context (used for registering services)
+ protected BundleContext context;
+ // our service registration
+ protected ServiceRegistration registration;
+
+ public TomcatOSGiWebContainer (BundleContext bundleContext, TomcatContainer container) throws Exception {
+ assert container != null;
+ this.container = container;
+ }
+
+ /**
+ * Retrieve the real web container instance used for deployment.
+ *
+ * @return The web container instance.
+ */
+ public WebContainer getContainer() {
+ return container;
+ }
+
+
+ /**
+ * Deploy a web application to the OSGi container.
+ *
+ * @param app The web application instance to deploy, configured as
+ * a Web Application Bundle.
+ */
+ public void deploy(WebApplication app) {
+ TomcatContext context = new TomcatOSGiWebAppContext(app.getBundle(), app.getContextPath();
+ container.addContext(context);
+ // hook up the application to its context
+ app.setContext(context);
+ // we need to explicitly set the servlet context because the app only gets
+ // an opaque view of the context object.
+ app.setServletContext(context.getContext().getServletContext());
+ //register the classloader <> dir context association so that tomcat's jndi based getResources works.
+ DirContext resources = context.getResources();
+ if (resources == null) {
+ throw new IllegalStateException("JNDI environment was not set up correctly due to previous error");
+ }
+ DirContextURLStreamHandler.bind(classLoader, resources);
+ }
+
+
+ public void undeploy(WebApplication app) {
+ TomcatContext context = (TomcatContext)app.getContext();
+ // remove this from the container
+ container.removeContext(app.context);
+ DirContextURLStreamHandler.unbind(context.getClassLoader());
+
+ log.debug("Tomcat Web App undeployed");
+ }
+
+
+ /**
+ * Start the OSGi Web App container GBean.
+ *
+ * @exception Exception
+ */
+ public void doStart() throws Exception {
+ // register ourselves as a service so that the extender can find us for deployment.
+ registration = bundleContext.registerService(WebContainerService.class.getName(), this, new Properties());
+
+ log.debug("Tomcat OSGi Web App Container started");
+ }
+
+ /**
+ * Stop the web container instance. This will remove
+ * the service registration from the OSGi registry.
+ *
+ * @exception Exception
+ */
+ public void doStop() throws Exception {
+ registration.unregister();
+ registration = null;
+ log.debug("Tomcat OSGi Web App Container stopped");
+ }
+
+ /**
+ * Handle GBean startup failures
+ */
+ public void doFail() {
+ if (registration != null) {
+ registration.unregister();
+ registration = null;
+ }
+ log.warn("Tomcat Web App Container failed");
+ }
+
+ public static final GBeanInfo GBEAN_INFO;
+ public static final String GBEAN_REF_MANAGER_RETRIEVER = "ManagerRetriever";
+
+ static {
+ GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("Tomcat OSGi Web Application Container", TomcatOSGiWebContainer.class, NameFactory.WEB_MODULE);
+
+ infoBuilder.addAttribute("bundleContext", BundleContext.class, false);
+ infoBuilder.addReference("Container", TomcatContainer.class, GBeanInfoBuilder.DEFAULT_J2EE_TYPE);
+
+ infoBuilder.addInterface(WebModule.class);
+
+ infoBuilder.setConstructor(new String[] {
+ "bundleContext",
+ "Container",
+ }
+ );
+
+ GBEAN_INFO = infoBuilder.getBeanInfo();
+ }
+
+ public static GBeanInfo getGBeanInfo() {
+ return GBEAN_INFO;
+ }
+}
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: geronimo/sandbox/rick/rfc66/src/main/java/org/apache/geronimo/osgi/web/tomcat/TomcatOSGiWebContainer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain