[jboss-cvs] JBossAS SVN: r100726 - in trunk: server/src/etc/conf/all/bootstrap and 4 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon Feb 8 18:24:58 EST 2010
Author: bstansberry at jboss.com
Date: 2010-02-08 18:24:57 -0500 (Mon, 08 Feb 2010)
New Revision: 100726
Added:
trunk/server/src/etc/deploy/admin-console-activator-jboss-beans.xml
trunk/server/src/etc/deploy/jbossws-console-activator-jboss-beans.xml
trunk/server/src/etc/deploy/jmx-console-activator-jboss-beans.xml
trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/
trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/ContextDemandListener.java
trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextIntegrator.java
trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextProfileManager.java
Modified:
trunk/build/build.xml
trunk/server/src/etc/conf/all/bootstrap/vfs.xml
trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java
Log:
[JBAS-7713] Activation of profiles upon receipt of first request
Modified: trunk/build/build.xml
===================================================================
--- trunk/build/build.xml 2010-02-08 22:46:23 UTC (rev 100725)
+++ trunk/build/build.xml 2010-02-08 23:24:57 UTC (rev 100726)
@@ -148,6 +148,7 @@
<!-- libs shared by the server configurations -->
<property name="install.common" value="${install.root}/common"/>
<property name="install.common.lib" value="${install.common}/lib"/>
+ <property name="install.common.deploy" value="${install.common}/deploy"/>
<!-- Configuration for the nightly build and test job -->
<property name="run.nightly.sleep" value="1"/>
@@ -332,7 +333,7 @@
<include name="jboss-local-jdbc.rar"/>
<include name="jbossweb.sar/**"/>
<include name="jboss-xa-jdbc.rar"/>
- <include name="jmx-console.war/**"/>
+ <include name="jmx-console-activator-jboss-beans.xml"/>
<include name="http-invoker.sar/**"/>
<include name="ROOT.war/**"/>
<include name="security/**"/>
@@ -360,7 +361,7 @@
<exclude name="conf/jndi.properties"/>
<!-- ORBInitialContextFactory -->
<include name="deploy/**"/>
- <exclude name="deploy/admin-console.war/**"/>
+ <!--<exclude name="deploy/admin-console-activator-jboss-beans.xml"/>-->
<exclude name="deploy/http-invoker.sar/**"/>
<exclude name="deploy/jmx-remoting.sar/**"/>
<exclude name="deploy/management/**"/>
@@ -1435,8 +1436,9 @@
</unjar>
<!-- Include the JMX console war unpacked -->
- <mkdir dir="${install.server}/all/deploy/jmx-console.war"/>
- <unjar src="${varia.module.output}/jboss-as-varia-jmx-console.war" dest="${install.server}/all/deploy/jmx-console.war"/>
+ <mkdir dir="${install.common.deploy}"/>
+ <mkdir dir="${install.common.deploy}/jmx-console.war"/>
+ <unjar src="${varia.module.output}/jboss-as-varia-jmx-console.war" dest="${install.common.deploy}/jmx-console.war"/>
<!-- Include the HTTP invoker service unpacked -->
@@ -1821,9 +1823,10 @@
</target>
<target name="install-jbossws-to-deploy">
- <!-- Install JBossWS web console to deploy directory -->
+ <!-- Install JBossWS web console to deploy directory -->
+ <mkdir dir="${install.common.deploy}"/>
<unzip src="${org.jboss.ws.native:jbossws-native-management:war}"
- dest="${install.all.deploy}/jbossws-console.war"
+ dest="${install.common.deploy}/jbossws-console.war"
/>
</target>
@@ -2312,13 +2315,9 @@
</unzip>
<!-- Install Admin Console -->
- <mkdir dir="${install.server}/all/deploy/admin-console.war"/>
+ <mkdir dir="${install.common.deploy}/admin-console.war"/>
<unjar src="${org.jboss.jopr:jopr-embedded-jbas5:war}"
- dest="${install.server}/all/deploy/admin-console.war"/>
-
- <mkdir dir="${install.server}/default/deploy/admin-console.war"/>
- <unjar src="${org.jboss.jopr:jopr-embedded-jbas5:war}"
- dest="${install.server}/default/deploy/admin-console.war"/>
+ dest="${install.common.deploy}/admin-console.war"/>
<!-- Copy varia stuff -->
Modified: trunk/server/src/etc/conf/all/bootstrap/vfs.xml
===================================================================
--- trunk/server/src/etc/conf/all/bootstrap/vfs.xml 2010-02-08 22:46:23 UTC (rev 100725)
+++ trunk/server/src/etc/conf/all/bootstrap/vfs.xml 2010-02-08 23:24:57 UTC (rev 100726)
@@ -21,6 +21,10 @@
<value><inject bean="VfsNamesExceptionHandler"/></value>
</entry>
<entry>
+ <key>${jboss.common.base.url}/deploy</key>
+ <value><inject bean="VfsNamesExceptionHandler"/></value>
+ </entry>
+ <entry>
<key>${jboss.server.lib.url}</key>
<value><inject bean="VfsNamesExceptionHandler"/></value>
</entry>
Added: trunk/server/src/etc/deploy/admin-console-activator-jboss-beans.xml
===================================================================
--- trunk/server/src/etc/deploy/admin-console-activator-jboss-beans.xml (rev 0)
+++ trunk/server/src/etc/deploy/admin-console-activator-jboss-beans.xml 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <bean name="AdminConsoleActivator" class="org.jboss.web.tomcat.service.ondemand.OnDemandContextProfileManager">
+
+ <property name="profileService"><inject bean="ProfileService"/></property>
+ <property name="profileFactory"><inject bean="ProfileFactory"/></property>
+ <property name="onDemandContextIntegrator"><inject bean="WebServer"/></property>
+
+ <property name="contextName">admin-console</property>
+
+ <!-- Build a profile from the contents of this single URI -->
+ <property name="singleURI">${jboss.common.base.url}deploy${/}admin-console.war</property>
+
+ <!--
+ Whether activation of the profile (i.e. deployment of the URI contents)
+ should be deferred until the first request (true) or done as part of
+ the start of this bean (false).
+
+ WARNING: This configuration option may be altered in a subsequent AS 6.0
+ milestone release.
+
+ FIXME: https://jira.jboss.org/jira/browse/JBAS-7714
+ -->
+ <property name="activateOnDemand">${jboss.as.deployment.ondemand:true}</property>
+
+ </bean>
+
+</deployment>
Property changes on: trunk/server/src/etc/deploy/admin-console-activator-jboss-beans.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Added: trunk/server/src/etc/deploy/jbossws-console-activator-jboss-beans.xml
===================================================================
--- trunk/server/src/etc/deploy/jbossws-console-activator-jboss-beans.xml (rev 0)
+++ trunk/server/src/etc/deploy/jbossws-console-activator-jboss-beans.xml 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <bean name="JBossWSConsoleActivator" class="org.jboss.web.tomcat.service.ondemand.OnDemandContextProfileManager">
+
+ <property name="profileService"><inject bean="ProfileService"/></property>
+ <property name="profileFactory"><inject bean="ProfileFactory"/></property>
+ <property name="onDemandContextIntegrator"><inject bean="WebServer"/></property>
+
+ <property name="contextName">jbossws</property>
+
+ <!-- Build a profile from the contents of this single URI -->
+ <property name="singleURI">${jboss.common.base.url}deploy${/}jbossws-console.war</property>
+
+ <!--
+ Whether activation of the profile (i.e. deployment of the URI contents)
+ should be deferred until the first request (true) or done as part of
+ the start of this bean (false).
+
+ WARNING: This configuration option may be altered in a subsequent AS 6.0
+ milestone release.
+
+ FIXME: https://jira.jboss.org/jira/browse/JBAS-7714
+ -->
+ <property name="activateOnDemand">${jboss.as.deployment.ondemand:true}</property>
+
+ </bean>
+
+</deployment>
Property changes on: trunk/server/src/etc/deploy/jbossws-console-activator-jboss-beans.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Added: trunk/server/src/etc/deploy/jmx-console-activator-jboss-beans.xml
===================================================================
--- trunk/server/src/etc/deploy/jmx-console-activator-jboss-beans.xml (rev 0)
+++ trunk/server/src/etc/deploy/jmx-console-activator-jboss-beans.xml 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+ <bean name="JmxConsoleActivator" class="org.jboss.web.tomcat.service.ondemand.OnDemandContextProfileManager">
+
+ <property name="profileService"><inject bean="ProfileService"/></property>
+ <property name="profileFactory"><inject bean="ProfileFactory"/></property>
+ <property name="onDemandContextIntegrator"><inject bean="WebServer"/></property>
+
+ <property name="contextName">jmx-console</property>
+
+ <!-- Build a profile from the contents of this single URI -->
+ <property name="singleURI">${jboss.common.base.url}deploy${/}jmx-console.war</property>
+
+ <!--
+ Whether activation of the profile (i.e. deployment of the URI contents)
+ should be deferred until the first request (true) or done as part of
+ the start of this bean (false).
+
+ WARNING: This configuration option may be altered in a subsequent AS 6.0
+ milestone release.
+
+ FIXME: https://jira.jboss.org/jira/browse/JBAS-7714
+ -->
+ <property name="activateOnDemand">${jboss.as.deployment.ondemand:true}</property>
+
+ </bean>
+
+</deployment>
Property changes on: trunk/server/src/etc/deploy/jmx-console-activator-jboss-beans.xml
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java 2010-02-08 22:46:23 UTC (rev 100725)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java 2010-02-08 23:24:57 UTC (rev 100726)
@@ -26,8 +26,13 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executor;
import javax.management.MBeanServer;
@@ -45,8 +50,9 @@
import org.apache.catalina.startup.Catalina;
import org.apache.catalina.startup.CatalinaProperties;
import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.http.mapper.Mapper;
+import org.apache.tomcat.util.http.mapper.OnDemandContextMappingListener;
import org.apache.tomcat.util.modeler.Registry;
-import org.jboss.bootstrap.api.as.server.JBossASServer;
import org.jboss.bootstrap.api.lifecycle.LifecycleState;
import org.jboss.bootstrap.spi.as.server.JBossASServerProvider;
import org.jboss.kernel.spi.dependency.KernelController;
@@ -65,6 +71,8 @@
import org.jboss.web.tomcat.metadata.ServiceMetaData;
import org.jboss.web.tomcat.metadata.ValveMetaData;
import org.jboss.web.tomcat.security.HttpServletRequestPolicyContextHandler;
+import org.jboss.web.tomcat.service.ondemand.ContextDemandListener;
+import org.jboss.web.tomcat.service.ondemand.OnDemandContextIntegrator;
import org.jboss.web.tomcat.service.session.SessionIDGenerator;
import org.jboss.xb.binding.Unmarshaller;
import org.jboss.xb.binding.UnmarshallerFactory;
@@ -86,7 +94,7 @@
* @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
* @version $Revision$
*/
-public class TomcatService extends ServiceMBeanSupport implements NotificationListener, TomcatServiceMBean
+public class TomcatService extends ServiceMBeanSupport implements NotificationListener, TomcatServiceMBean, OnDemandContextIntegrator
{
/** The associated Tomcat deployer * */
@@ -97,7 +105,13 @@
// Use a flag because isInShutdown doesn't appear to be correct
private boolean connectorsRunning = false;
-
+
+ private final Set<ContextDemandAdapter> contextDemandAdapters =
+ Collections.synchronizedSet(new HashSet<ContextDemandAdapter>());
+
+ private final Map<String, Mapper> mappers =
+ Collections.synchronizedMap(new HashMap<String, Mapper>());
+
// Dependency inject the Executor pojo
public Executor getExecutor()
@@ -218,7 +232,15 @@
service.setName(serviceMetaData.getName());
service.setServer(catalinaServer);
catalinaServer.addService(service);
+
+ // Integrate support for on-demand contexts
+ Mapper mapper = service.getMapper();
+ mappers.put(service.getName(), mapper);
+ ContextDemandAdapter adapter = new ContextDemandAdapter(service.getName());
+ mapper.registerOnDemandContextMappingListener(adapter);
+ contextDemandAdapters.add(adapter);
+
// Server/Service/Executor
// Executor is useless in JBoss: the Executor will get injected in the executor field
// and used directly
@@ -766,4 +788,87 @@
super.unsetKernelControllerContext(controllerContext);
JBossWebMicrocontainerBeanLocator.setKernelController(null);
}
+
+ public void registerContextDemandListener(ContextDemandListener listener)
+ {
+ for (ContextDemandAdapter adapter : contextDemandAdapters)
+ {
+ adapter.registerContextDemandListener(listener);
+ }
+ }
+
+ public void removeContextDemandListener(ContextDemandListener listener)
+ {
+ for (ContextDemandAdapter adapter : contextDemandAdapters)
+ {
+ adapter.removeContextDemandListener(listener);
+ }
+ }
+
+ public void registerOnDemandContext(String serviceName, String hostName, String contextName)
+ {
+ Mapper mapper = mappers.get(serviceName);
+ if (mapper != null)
+ {
+ // ensure the path starts w/ slash or Mapper won't match it correctly
+ if (contextName.length() > 0 && ('/' != contextName.charAt(0)))
+ {
+ contextName = "/" + contextName;
+ }
+ mapper.addOnDemandContext(hostName, contextName);
+ }
+ else
+ {
+ log.warn("Cannot register on-demand context for unknown engine " + serviceName);
+ }
+ }
+
+ public void removeOnDemandContext(String serviceName, String hostName, String contextName)
+ {
+ Mapper mapper = mappers.get(serviceName);
+ if (mapper != null)
+ {
+ mapper.removeContext(hostName, contextName);
+ }
+ else
+ {
+ log.warn("Cannot remove on-demand context for unknown engine " + serviceName);
+ }
+ }
+
+ private class ContextDemandAdapter implements OnDemandContextMappingListener
+ {
+ private final String engineName;
+ private final Set<ContextDemandListener> contextDemandListeners =
+ Collections.synchronizedSet(new HashSet<ContextDemandListener>());
+
+ private ContextDemandAdapter(String engineName)
+ {
+ this.engineName = engineName;
+ }
+
+ public void onDemandContextMapped(String hostName, String contextName)
+ {
+ for (ContextDemandListener listener : contextDemandListeners)
+ {
+ listener.contextDemanded(this.engineName, hostName, contextName);
+ }
+ }
+
+ private void registerContextDemandListener(ContextDemandListener listener)
+ {
+ if (listener != null )
+ {
+ contextDemandListeners.add(listener);
+ }
+ }
+
+ private void removeContextDemandListener(ContextDemandListener listener)
+ {
+ if (listener != null )
+ {
+ contextDemandListeners.remove(listener);
+ }
+ }
+ }
}
Added: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/ContextDemandListener.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/ContextDemandListener.java (rev 0)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/ContextDemandListener.java 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.web.tomcat.service.ondemand;
+
+/**
+ * Interface implemented by listeners that wish to be notified of requests
+ * for as-yet-undeployed "on-demand" web applications. It is expected that the
+ * typical implementation of this interface would trigger deployment of the web
+ * application.
+ *
+ * @author Brian Stansberry
+ *
+ * @version $Revision$
+ */
+public interface ContextDemandListener
+{
+ /**
+ * Notification that a request has been received for a web application
+ * previously {@link OnDemandContextIntegrator#registerContextDemandListener(ContextDemandListener)
+ * registered with JBoss Web} as eligible for on-demand deployment.
+ * <p>
+ * Implementors of this interface should assume that the notification will be
+ * received before the web server has handled the request and that any handling
+ * of the request is either being done by the calling thread or will block
+ * until the <code>contextDemanded</code> call has returned.
+ * </p>
+ *
+ *
+ * @param serviceName the name of the JBoss Web <code>Service</code> that
+ * includes the connector that received the request.
+ * Will not be <code>null</code>.
+ * @param hostName the name of the JBoss Web <code>Host</code> that is the
+ * virtual host associated with the request.
+ * Will not be <code>null</code>.
+ * @param contextName the name of the on-demand web application context, i.e.
+ * the context path portion of the request URL, with
+ * any leading and trailing / removed.
+ * Will not be <code>null</code>.
+ */
+ void contextDemanded(String serviceName, String hostName, String contextName);
+}
Property changes on: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/ContextDemandListener.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Added: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextIntegrator.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextIntegrator.java (rev 0)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextIntegrator.java 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,86 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat, Inc, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.ondemand;
+
+/**
+ * Mediates between any {@link ContextDemandListener}s and JBoss Web, allowing
+ * JBoss Web to be made aware of the presence of on-demand applications and
+ * for the listeners to be notified when a user request for an on-demand
+ * application has arrived. An implementation of this interface is responsible
+ * for finding and interacting with the relevant JBoss Web components, freeing
+ * the listeners from that responsibility.
+ *
+ * @author Brian Stansberry
+ *
+ * @version $Revision$
+ */
+public interface OnDemandContextIntegrator
+{
+ /**
+ * Registers a listener to receive callbacks when a request is received
+ * for an on-demand web application.
+ *
+ * @param listener the listener
+ */
+ void registerContextDemandListener(ContextDemandListener listener);
+
+ /**
+ * Removes a listener from the set of listeners receiving callbacks when a
+ * request is received for an on-demand web application.
+ *
+ * @param listener the listener
+ */
+ void removeContextDemandListener(ContextDemandListener listener);
+
+ /**
+ * Configures JBoss Web to recognize requests for the given connectors, virtual
+ * host and web application context as being for an as-yet-undeployed
+ * "on-demand" web application.
+ *
+ * @param serviceName the name of the JBoss Web <code>Service</code> that
+ * includes the connectors that will receive requests for
+ * the on-demand web application. Cannot be <code>null</code>.
+ * @param hostName the name of the JBoss Web <code>Host</code> that is the
+ * virtual host for on-demand web application.
+ * Cannot be <code>null</code>.
+ * @param contextName the name of the on-demand web application context, i.e.
+ * the context path portion of URLs that target it, with
+ * any leading and trailing / removed
+ */
+ void registerOnDemandContext(String serviceName, String hostName, String contextName);
+
+ /**
+ * Configures JBoss Web to no longer recognize requests for the given
+ * connectors, virtual host and web application context.
+ *
+ * @param serviceName the name of the JBoss Web <code>Service</code> that
+ * includes the connectors that will receive requests for
+ * the on-demand web application. Cannot be <code>null</code>.
+ * @param hostName the name of the JBoss Web <code>Host</code> that is the
+ * virtual host for on-demand web application. Cannot be <code>null</code>.
+ * @param contextName the name of the on-demand web application context, i.e.
+ * the context path portion of URLs that target it, with
+ * any leading and trailing / removed
+ */
+ void removeOnDemandContext(String serviceName, String hostName, String contextName);
+
+}
\ No newline at end of file
Property changes on: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextIntegrator.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Added: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextProfileManager.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextProfileManager.java (rev 0)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextProfileManager.java 2010-02-08 23:24:57 UTC (rev 100726)
@@ -0,0 +1,668 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat, Inc, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.web.tomcat.service.ondemand;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.jboss.logging.Logger;
+import org.jboss.profileservice.spi.NoSuchProfileException;
+import org.jboss.profileservice.spi.Profile;
+import org.jboss.profileservice.spi.ProfileKey;
+import org.jboss.profileservice.spi.ProfileService;
+import org.jboss.profileservice.spi.metadata.ProfileMetaData;
+import org.jboss.profileservice.spi.metadata.ProfileSourceMetaData;
+import org.jboss.profileservice.spi.metadata.SubProfileMetaData;
+import org.jboss.system.server.profile.repository.metadata.AbstractProfileSourceMetaData;
+import org.jboss.system.server.profile.repository.metadata.BasicProfileMetaData;
+import org.jboss.system.server.profile.repository.metadata.BasicSubProfileMetaData;
+import org.jboss.system.server.profile.repository.metadata.HotDeploymentProfileSourceMetaData;
+import org.jboss.system.server.profile.repository.metadata.ImmutableProfileSourceMetaData;
+import org.jboss.system.server.profileservice.repository.AbstractProfileFactory;
+
+/**
+ * {@link ContextDemandListener} that creates and registers a {@link ProfileService}
+ * {@link Profile} and then {@link #activateProfile() activates it} when
+ * it receives a notification that a web request wishes to access a targetted
+ * application.
+ *
+ * TODO: deal with host name aliases and multiple contexts
+ *
+ * TODO: The ProfileService integration aspect of this class duplicates
+ * equivalent functionality used for clustering's deploy-hasingleton directory
+ * deployment. Both solve the same conceptual problem of an external event
+ * triggering activation of a profile. Abstract this out and put it in a
+ * shared location.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class OnDemandContextProfileManager implements ContextDemandListener
+{
+ public static final String DEFAULT_SERVICE_NAME = "jboss.web";
+ public static final String DEFAULT_HOST_NAME = "localhost";
+ public static final String DEFAULT_ROOT_WAR_PROFILE_NAME = "ROOT.war";
+
+ /** The profile service */
+ private ProfileService profileService;
+ /** The factory for creating profiles */
+ private AbstractProfileFactory profileFactory;
+ /** Integration hook into JBoss Web */
+ private OnDemandContextIntegrator contextIntegrator;
+
+ /** The list of URIs to scan */
+ private List<URI> uriList = new CopyOnWriteArrayList<URI>();
+
+ protected final Logger log = Logger.getLogger(getClass());
+
+ /** Whether this node has activated its profile */
+ private boolean activated;
+
+ /** The profile service key domain */
+ private String profileDomain;
+
+ /** The profile service key server */
+ private String profileServer;
+
+ /** The profile service key name */
+ private String profileName;
+
+ /** The profile service key */
+ private ProfileKey profileKey;
+
+ /** Name of the JBoss Web service we associate with */
+ private String serviceName = DEFAULT_SERVICE_NAME;
+ /** Name of the JBoss Web virtual host we associate with */
+ private String hostName = DEFAULT_HOST_NAME;
+ /** Name of the JBoss Web context we associate with */
+ private String contextName;
+ /** contextName with a preceding / (if not root context) */
+ private String contextPath; // TODO do something smarter
+
+ private boolean activateOnDemand = true;
+
+ // ----------------------------------------------------------- Constructors
+
+ /**
+ * Create a new OnDemandContextProfileManager.
+ */
+ public OnDemandContextProfileManager()
+ {
+ super();
+ }
+
+ // ---------------------------------------------------------- Properties
+
+ /**
+ * Gets the list of URIs that will be included as the content of the
+ * profile when it is activated.
+ *
+ * @return the list. Will not be <code>null</code>
+ */
+ public List<URI> getURIList()
+ {
+ return new ArrayList<URI>(uriList);
+ }
+
+ /**
+ * Sets the list of URIs that will be included as the content of the
+ * profile when it is activated.
+ *
+ * @param list the list. Cannot be <code>null</code>
+ * @throws IOException
+ * @throws IllegalArgumentException if <code>list</code> is <code>null</code>
+ */
+ public void setURIList(final List<URI> list) throws IOException
+ {
+ if (list == null)
+ {
+ throw new IllegalArgumentException("list argument cannot be null");
+ }
+
+ // start out with a fresh list
+ uriList.clear();
+
+ for(int n = 0; n < list.size(); n ++)
+ {
+ URI uri = list.get(n);
+ if (uri == null)
+ {
+ throw new IllegalArgumentException("list element["+n+"] is null");
+ }
+
+ if( uriList.add(uri) == true )
+ {
+ log.debug("Added URI: " + uri);
+ }
+ }
+ log.debug("URI list: " + uriList);
+ }
+
+ /**
+ * Returns the single URI that is to be associated with the profile, or
+ * <code>null</code> if there is less than or more than one such URI.
+ *
+ * @return the URI or <code>null</code>
+ */
+ public URI getSingleURI()
+ {
+ List<URI> list = getURIList();
+ return list.size() == 1 ? list.get(0) : null;
+ }
+
+ /**
+ * Convenience method for {@link #setURIList(List) setting the list of URIs}
+ * to include in the profile to a single URI.
+ *
+ * @param deploymentURI the URI. Cannot be <code>null</code>
+ * @throws IOException
+ * @throws IllegalArgumentException if deploymentURI is <code>null</code>
+ */
+ public void setSingleURI(URI deploymentURI) throws IOException
+ {
+ if (deploymentURI == null)
+ {
+ throw new IllegalArgumentException("deploymentURI argument cannot be null");
+ }
+ List<URI> list = Arrays.asList(deploymentURI);
+ setURIList(list);
+ }
+
+ /**
+ * Gets the value that should be used for the
+ * {@link ProfileKey#getDomain() domain} portion of
+ * the on-demand @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @return the domain, or <code>null</code> if not set
+ */
+ public String getProfileDomain()
+ {
+ return profileDomain;
+ }
+
+ /**
+ * Sets the value that should be used for the
+ * {@link ProfileKey#getDomain() domain} portion of
+ * the singleton @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @param profileDomain the domain, or <code>null</code>
+ */
+ public void setProfileDomain(String profileDomain)
+ {
+ this.profileDomain = profileDomain;
+ }
+
+ /**
+ * Gets the value that should be used for the
+ * {@link ProfileKey#getServer() server} portion of
+ * the on-demand @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @return the server, or <code>null</code> if not set
+ */
+ public String getProfileServer()
+ {
+ return profileServer;
+ }
+
+ /**
+ * Sets the value that should be used for the
+ * {@link ProfileKey#getServer() server} portion of
+ * the on-demand @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @param profileServer the server, or <code>null</code>
+ */
+ public void setProfileServer(String profileServer)
+ {
+ this.profileServer = profileServer;
+ }
+
+ /**
+ * Gets the value that should be used for the
+ * {@link ProfileKey#getName() name} portion of
+ * the on-demand @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @return the name, or <code>null</code> if not set
+ */
+ public String getProfileName()
+ {
+ if (profileName == null)
+ {
+ if ("".equals(contextName))
+ {
+ profileName = DEFAULT_ROOT_WAR_PROFILE_NAME;
+ }
+ else
+ {
+ profileName = contextName + ".war";
+ }
+ }
+ return profileName;
+ }
+
+ /**
+ * Sets the value that should be used for the
+ * {@link ProfileKey#getName() name} portion of
+ * the singleton @{link Profile}'s {@link #getProfileKey() ProfileKey}.
+ *
+ * @param profileName the name, or <code>null</code>
+ */
+ public void setProfileName(String profileName)
+ {
+ this.profileName = profileName;
+ }
+
+ /**
+ * Gets whether this object has activated its profile.
+ *
+ * @return <code>true</code> if {@link #activateProfile()} has successfully
+ * completed and {@link #releaseProfile()} has not been called;
+ * <code>false</code> otherwise.
+ */
+ public boolean isActivated()
+ {
+ return activated;
+ }
+
+
+
+ public String getServiceName()
+ {
+ return serviceName;
+ }
+
+ public void setServiceName(String serviceName)
+ {
+ if (serviceName == null)
+ {
+ throw new IllegalArgumentException("serviceName is null");
+ }
+ this.serviceName = serviceName;
+ }
+
+ public String getHostName()
+ {
+ return hostName;
+ }
+
+ public void setHostName(String hostName)
+ {
+ if (hostName == null)
+ {
+ throw new IllegalArgumentException("hostName is null");
+ }
+ this.hostName = hostName;
+ }
+
+ public String getContextName()
+ {
+ return contextName;
+ }
+
+ public void setContextName(String contextName)
+ {
+ if (contextName == null)
+ {
+ throw new IllegalArgumentException("contextName is null");
+ }
+ if ("ROOT".equals(contextName) || "/ROOT".equals(contextName))
+ {
+ contextName = "";
+ }
+ this.contextName = contextName;
+ }
+
+ /**
+ * Sets the ProfileService reference.
+ *
+ * @param profileService the profileService. Cannot be <code>null</code>
+ *
+ * @throws IllegalArgumentException if <code>profileService</code> is <code>null</code>
+ */
+ public void setProfileService(ProfileService profileService)
+ {
+ if (profileService == null)
+ {
+ throw new IllegalArgumentException("profileService is null");
+ }
+
+ this.profileService = profileService;
+ }
+
+ /**
+ * Sets the factory that should be used to create the on-demand Profile.
+ *
+ * @param profileFactory the factory Cannot be <code>null</code>
+ *
+ * @throws IllegalArgumentException if <code>profileFactory</code> is <code>null</code>
+ */
+ public void setProfileFactory(AbstractProfileFactory profileFactory)
+ {
+ if (profileFactory == null)
+ {
+ throw new IllegalArgumentException("profileFactory is null");
+ }
+ this.profileFactory = profileFactory;
+ }
+
+ /**
+ * Sets the {@link OnDemandContextIntegrator} used to integrate with the
+ * web server
+ *
+ * @param contextManager the manager. Cannot be <code>null</code>
+ *
+ * @throws IllegalArgumentException if <code>contextManager</code> is <code>null</code>
+ */
+ public void setOnDemandContextIntegrator(OnDemandContextIntegrator contextManager)
+ {
+ if (contextManager == null)
+ {
+ throw new IllegalArgumentException("contextManager is null");
+ }
+ this.contextIntegrator = contextManager;
+ }
+
+ /**
+ * Gets whether the profile should be activated on during the {@link #start()}
+ * phase of this bean's deployment rather than on receipt of an HTTP request.
+ * This property allows a simple configuration to turn off the "on-demand"
+ * behavior for environments (e.g. production servers) where a more
+ * deterministic startup is appropriate.
+ *
+ * @return <code>false</code> if the profile should be activated as part of
+ * startup of this bean; <code>true</code> if activation should
+ * be deferred until an HTTP request is received. Default is
+ * <code>true</code>
+ *
+ * @deprecated This is a temporary API for AS 6.0.0.M2; something else
+ * may replace it in later releases
+ */
+ public boolean isActivateOnDemand()
+ {
+ return activateOnDemand;
+ }
+
+ /**
+ * Sets whether the profile should be activated on during the {@link #start()}
+ * phase of this bean's deployment rather than on receipt of an HTTP request.
+ * This property allows a simple configuration to turn off the "on-demand"
+ * behavior for environments (e.g. production servers) where a more
+ * deterministic startup is appropriate.
+ *
+ * @param activateOnDemand <code>false</code> if the profile should be
+ * activated as part of startup of this bean;
+ * <code>true</code> if activation should be
+ * deferred until an HTTP request is received.
+ *
+ * @deprecated This is a temporary API for AS 6.0.0.M2; something else
+ * may replace it in later releases
+ */
+ public void setActivateOnDemand(boolean activateOnDemand)
+ {
+ this.activateOnDemand = activateOnDemand;
+ }
+
+ // -------------------------------------------------- ContextDemandListener
+
+ public void contextDemanded(String serviceName, String hostName, String contextName)
+ {
+ if (this.contextPath.equals(contextName)
+ && this.hostName.equals(hostName)
+ && this.serviceName.equals(serviceName))
+ {
+ try
+ {
+ activateProfile();
+ }
+ catch (Exception e)
+ {
+ log.error("Unable to activate profile " + getProfileKey(), e);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------- Public
+
+ /**
+ * Builds a profile from the {@link #getURIList() URI list} and registers
+ * it under the configured {@link #getProfileKey()}.
+ */
+ public void start() throws Exception
+ {
+ if (this.profileFactory == null)
+ {
+ throw new IllegalStateException("Must configure ProfileFactory");
+ }
+
+ if (profileService == null)
+ {
+ throw new IllegalStateException("Must configure ProfileService");
+ }
+
+ if (contextIntegrator == null)
+ {
+ throw new IllegalStateException("Must configure OnDemandContextManager");
+ }
+
+ if (serviceName == null)
+ {
+ throw new IllegalStateException("Must configure serviceName");
+ }
+
+ if (hostName == null)
+ {
+ throw new IllegalStateException("Must configure hostName");
+ }
+
+ if (contextName == null)
+ {
+ throw new IllegalStateException("Must configure contextName");
+ }
+
+ URI[] rootURIs = uriList.toArray(new URI[uriList.size()]);
+ // TODO add dependencies on bootstrap profiles
+ String[] rootSubProfiles = new String[0];
+ // Create a hotdeployment profile
+ ProfileMetaData metadata = createProfileMetaData(true, rootURIs, rootSubProfiles);
+
+ Profile profile = profileFactory.createProfile(getProfileKey(), metadata);
+ profileService.registerProfile(profile);
+
+ if (this.activateOnDemand)
+ {
+ contextIntegrator.registerContextDemandListener(this);
+ contextPath = (contextName.length() == 0 || '/' == contextName.charAt(0) ? contextName : "/" + contextName);
+ contextIntegrator.registerOnDemandContext(serviceName, hostName, contextPath);
+ }
+ else
+ {
+ // FIXME we don't validate as we expect the PS to do it at the end
+ // of startup; need to check if this is correct
+ activateProfile(false);
+ }
+ }
+
+ /**
+ * Unregisters the profile registered in {@link #start()}.
+ */
+ public void stop() throws Exception
+ {
+ ProfileKey profKey = getProfileKey();
+ if (profileService != null && profKey != null)
+ {
+ try
+ {
+ // Inactivate first if needed
+ if (profileService.getActiveProfileKeys().contains(profKey))
+ {
+ releaseProfile();
+ }
+
+ profileService.unregisterProfile(profKey);
+ }
+ catch (NoSuchProfileException e)
+ {
+ log.warn("Could not unregister unknown profile " + profKey);
+ }
+ }
+ }
+
+ /**
+ * Tells the ProfileService to
+ * {@link ProfileService#activateProfile(ProfileKey) activate the on-demand profile}.
+ */
+ public void activateProfile() throws Exception
+ {
+ activateProfile(true);
+ }
+
+ /**
+ * Gets the key for the {@link Profile} that we activate and release.
+ *
+ * @return the key. Will not return <code>null</code>
+ *
+ * @see #getProfileDomain()
+ * @see #getProfileServer()
+ * @see #getProfileName()
+ */
+ public ProfileKey getProfileKey()
+ {
+ if (this.profileKey == null)
+ {
+ this.profileKey = new ProfileKey(getProfileDomain(), getProfileServer(), getProfileName());
+ }
+ return this.profileKey;
+ }
+
+ // -------------------------------------------------------------- Protected
+
+ /**
+ * Create a profile repository source meta data.
+ *
+ * @param type the repository type.
+ * @param uri the uri
+ * @return the profile source meta data.
+ */
+ protected ProfileSourceMetaData createSource(URI[] uris, boolean hotDeployment)
+ {
+ AbstractProfileSourceMetaData source = null;
+ if(hotDeployment)
+ {
+ source = new HotDeploymentProfileSourceMetaData();
+ }
+ else
+ {
+ source = new ImmutableProfileSourceMetaData();
+ }
+ List<String> sources = new ArrayList<String>();
+ for(URI uri : uris)
+ sources.add(uri.toString());
+ source.setSources(sources);
+ return source;
+ }
+
+ // ---------------------------------------------------------------- Private
+
+
+ /**
+ * Create a profile meta data.
+ *
+ * @param name the profile name.
+ * @param repositoryType the repository type.
+ * @param uris the repository uris.
+ * @param subProfiles a list of profile dependencies.
+ * @return the profile meta data.
+ */
+ private ProfileMetaData createProfileMetaData(boolean hotDeployment, URI[] uris, String[] subProfiles)
+ {
+ // Create profile
+ BasicProfileMetaData metaData = new BasicProfileMetaData();
+ metaData.setDomain(getProfileDomain());
+ metaData.setServer(getProfileServer());
+ metaData.setName(getProfileName());
+
+ // Create profile sources
+ ProfileSourceMetaData source = createSource(uris, hotDeployment);
+ metaData.setSource(source);
+
+ List<SubProfileMetaData> profileList = new ArrayList<SubProfileMetaData>();
+ for(String subProfile : subProfiles)
+ {
+ BasicSubProfileMetaData md = new BasicSubProfileMetaData();
+ md.setName(subProfile);
+ profileList.add(md);
+ }
+ metaData.setSubprofiles(profileList);
+
+ return metaData;
+ }
+
+ private synchronized void activateProfile(boolean validate) throws Exception
+ {
+ if (this.profileService == null)
+ {
+ throw new IllegalStateException("Must configure the ProfileService");
+ }
+ ProfileKey profKey = getProfileKey();
+ if (this.profileService.getActiveProfileKeys().contains(profKey) == false)
+ {
+ this.profileService.activateProfile(getProfileKey());
+ if (validate)
+ {
+ // Validate if the activation was successful
+ this.profileService.validateProfile(getProfileKey());
+ }
+
+ this.activated = true;
+ }
+ else
+ {
+ log.warn("Profile " + profKey + " is already activated");
+ }
+
+ }
+
+ /**
+ * Tells the ProfileService to {@link ProfileService#releaseProfile(ProfileKey) release the profile}.
+ * Called by the HASingletonController when we are no longer the singleton master.
+ */
+ private synchronized void releaseProfile() throws Exception
+ {
+ if (this.activated)
+ {
+ try
+ {
+ this.profileService.deactivateProfile(getProfileKey());
+ }
+ catch (NoSuchProfileException e)
+ {
+ log.warn("No Profile is registered under key " + getProfileKey());
+ }
+
+ this.activated = false;
+ }
+ }
+
+}
Property changes on: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/ondemand/OnDemandContextProfileManager.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
More information about the jboss-cvs-commits
mailing list