001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.server.deployment;
023:
024: import org.jboss.deployment.DeploymentInfo;
025: import org.jboss.deployment.SubDeployer;
026: import org.jboss.portal.jems.as.system.AbstractJBossService;
027: import org.jboss.web.WebApplication;
028: import org.xml.sax.EntityResolver;
029:
030: import javax.management.Notification;
031: import javax.management.NotificationListener;
032: import javax.management.ObjectName;
033: import java.net.URL;
034: import java.util.ArrayList;
035: import java.util.Collection;
036: import java.util.Collections;
037: import java.util.HashMap;
038: import java.util.Iterator;
039: import java.util.Map;
040:
041: /**
042: * Relay web deployments. When a web deployment occurs, it is abstracted into a PortalWebApp object that provides a
043: * consistent way to getPortalObjectContext informations and modify the web application.
044: * <p/>
045: * When this service stops it does not send undeployment notifications, therefore it is up to the client of this service
046: * to perform any cleanup task associated to a deployment web application. The purpose of this is that most of the time
047: * clients of this service will be stopped before this one and they would receive undeployments in a not started state.
048: *
049: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
050: * @version $Revision: 8784 $
051: */
052: public abstract class WebAppIntercepter extends AbstractJBossService
053: implements NotificationListener {
054:
055: /** WARDeployer. */
056: private ObjectName interceptedDeployer;
057:
058: /** A copy of the WARDeployer used for notification subscription removal. */
059: private ObjectName currentInterceptedDeployer;
060:
061: /** The current deployements. */
062: private Map deployments;
063:
064: /** The factory creating the portal web app objects. */
065: private PortalWebAppFactory factory;
066:
067: /** The right classloader for fixing the issue with the fact that the classloader is not good on event notifications. */
068: private ClassLoader classLoader;
069:
070: /** The entity resolver for jboss-app.xml. */
071: private EntityResolver jbossAppEntityResolver;
072:
073: public WebAppIntercepter() {
074: deployments = Collections.synchronizedMap(new HashMap());
075: classLoader = Thread.currentThread().getContextClassLoader();
076: }
077:
078: public EntityResolver getJBossAppEntityResolver() {
079: return jbossAppEntityResolver;
080: }
081:
082: public void setJBossAppEntityResolver(
083: EntityResolver jbossAppEntityResolver) {
084: this .jbossAppEntityResolver = jbossAppEntityResolver;
085: }
086:
087: /** Set the deployer on this service. */
088: public void setInterceptedDeployer(ObjectName interceptedDeployer) {
089: this .interceptedDeployer = interceptedDeployer;
090: }
091:
092: /** Return the intercepted deployer. */
093: public ObjectName getInterceptedDeployer() {
094: return interceptedDeployer;
095: }
096:
097: /** Clone and return the deployed URLs. */
098: public Collection getDeployedURLs() {
099: return new ArrayList(deployments.keySet());
100: }
101:
102: private WebApplication findWebApp(DeploymentInfo info)
103: throws Exception {
104: // Get all the deployed web applications, our must be among these
105: Iterator iterator = (Iterator) server.getAttribute(
106: interceptedDeployer, "DeployedApplications");
107: while (iterator.hasNext()) {
108: WebApplication webApp = (WebApplication) iterator.next();
109: if (info == webApp.getDeploymentInfo()) {
110: return webApp;
111: }
112: }
113:
114: // Not found
115: return null;
116: }
117:
118: /** Only take care of start notifications. */
119: public void handleNotification(Notification notification,
120: Object handback) {
121: String type = notification.getType();
122: boolean start = SubDeployer.START_NOTIFICATION.equals(type);
123: boolean stop = SubDeployer.STOP_NOTIFICATION.equals(type);
124:
125: // Do we do something ?
126: if (start || stop) {
127: // The previous loader
128: ClassLoader previousLoader = Thread.currentThread()
129: .getContextClassLoader();
130:
131: try {
132: // This call is coming with the MainDeployer classloader as context loader
133: // For this call we change the context loader to the container one.
134: Thread.currentThread().setContextClassLoader(
135: classLoader);
136:
137: // Create the portal web app
138: DeploymentInfo info = (DeploymentInfo) notification
139: .getUserData();
140:
141: //
142: URL keyURL = info.url;
143:
144: //
145: if (start) {
146: WebApplication webApp = findWebApp(info);
147: PortalWebApp pwa = factory.create(webApp,
148: jbossAppEntityResolver);
149: deployments.put(keyURL, pwa);
150: log
151: .debug("Seen URL " + keyURL
152: + " about to deploy");
153: deploy(pwa);
154: }
155: if (stop) {
156: // Look if we have something for that url
157: PortalWebApp pwa = (PortalWebApp) deployments
158: .remove(keyURL);
159:
160: // Notify
161: if (pwa != null) {
162: log.debug("Undeploying URL " + keyURL);
163: undeploy(pwa);
164: }
165: }
166: } catch (Exception e) {
167: log
168: .error(
169: "Cannot handle the intercepted deployment",
170: e);
171: } finally {
172: // Put previous context loader back
173: Thread.currentThread().setContextClassLoader(
174: previousLoader);
175: }
176: }
177: }
178:
179: /** Start listening to the deployer notifications. */
180: protected void startService() throws Exception {
181: if (interceptedDeployer != null) {
182: // Create factory
183: factory = new PortalWebAppFactory(server);
184:
185: // Copy the name for the stop phase
186: currentInterceptedDeployer = interceptedDeployer;
187:
188: // Register to notifications
189: log
190: .debug("Start listening notifications from intercepted deployer"
191: + currentInterceptedDeployer);
192: server.addNotificationListener(currentInterceptedDeployer,
193: this , null, null);
194:
195: // Scans all the previously deployed applications
196: Iterator iterator = (Iterator) server.getAttribute(
197: currentInterceptedDeployer, "DeployedApplications");
198: log.debug("Scan previously deployed web applications");
199: while (iterator.hasNext()) {
200: WebApplication webApp = (WebApplication) iterator
201: .next();
202: URL keyURL = webApp.getDeploymentInfo().url;
203: if (!deployments.containsKey(keyURL)) {
204: PortalWebApp pwa = factory.create(webApp,
205: jbossAppEntityResolver);
206: deployments.put(keyURL, pwa);
207: log
208: .debug("Seen URL " + keyURL
209: + " about to deploy");
210: deploy(pwa);
211: }
212: }
213:
214: } else {
215: throw new Exception("No intercepted deployer name present");
216: }
217: }
218:
219: /** Stop listening to the deployer notifications. */
220: protected void stopService() throws Exception {
221: if (currentInterceptedDeployer != null) {
222: // Remove all previously deployed applications
223: for (Iterator i = deployments.entrySet().iterator(); i
224: .hasNext();) {
225: Map.Entry entry = (Map.Entry) i.next();
226: URL keyURL = (URL) entry.getKey();
227: PortalWebApp pwa = (PortalWebApp) entry.getValue();
228: i.remove();
229: log
230: .debug("Removing web application with URL "
231: + keyURL);
232: undeploy(pwa);
233: }
234:
235: // Do not listen notifications anymore
236: log
237: .debug("Stop listening notifications from intercepted deployer"
238: + currentInterceptedDeployer);
239: server.removeNotificationListener(
240: currentInterceptedDeployer, this );
241:
242: // Remove factory
243: factory = null;
244:
245: //
246: currentInterceptedDeployer = null;
247: }
248: }
249:
250: /** Perform the deploy notification. */
251: protected abstract void deploy(PortalWebApp pwa);
252:
253: /** Perform the undeploy notification. */
254: protected abstract void undeploy(PortalWebApp pwa);
255:
256: }
|