001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.deployment.impl;
018:
019: import java.io.File;
020: import java.io.FileFilter;
021: import java.io.FileNotFoundException;
022: import java.io.IOException;
023: import java.util.ArrayList;
024: import java.util.Arrays;
025: import java.util.Collection;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.StringTokenizer;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.apache.jetspeed.components.portletregistry.PortletRegistry;
033: import org.apache.jetspeed.deployment.DeploymentEvent;
034: import org.apache.jetspeed.deployment.DeploymentEventListener;
035: import org.apache.jetspeed.deployment.DeploymentException;
036: import org.apache.jetspeed.deployment.DeploymentManager;
037: import org.apache.jetspeed.deployment.DeploymentObject;
038: import org.apache.jetspeed.deployment.DeploymentStatus;
039:
040: /**
041: * <p>
042: * StandardDeploymentManager
043: * </p>
044: * Implementation of {@link org.apache.jetspeed.deployment.DeploymentManager}
045: *
046: * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
047: * @version $Id: StandardDeploymentManager.java 517121 2007-03-12 07:45:49Z ate $
048: */
049: public class StandardDeploymentManager implements DeploymentManager {
050: private static final FileFilter readmeIgnoringFileFilter = new FileFilter() {
051: public boolean accept(File file) {
052: return !file.getName().equalsIgnoreCase("README.txt");
053: }
054: };
055:
056: protected Log log = LogFactory.getLog("deployment");
057: protected FileSystemScanner scanner;
058: protected PortletRegistry registry;
059: protected Collection deploymentListeners;
060: protected long scanningDelay;
061: protected String stagingDirectories;
062: protected File[] stagingDirectoriesAsFiles;
063: protected HashMap ignoredFiles;
064:
065: /**
066: * @param stagingDirectories
067: * @param scanningDelay
068: * @param deploymentListeners
069: */
070: public StandardDeploymentManager(String stagingDirectories,
071: long scanningDelay, Collection deploymentListeners) {
072: this .scanningDelay = scanningDelay;
073: this .stagingDirectories = stagingDirectories;
074: StringTokenizer dirTokenizer = new StringTokenizer(
075: stagingDirectories, ",");
076: this .stagingDirectoriesAsFiles = new File[dirTokenizer
077: .countTokens()];
078: int i = 0;
079: while (dirTokenizer.hasMoreTokens()) {
080: this .stagingDirectoriesAsFiles[i] = new File(dirTokenizer
081: .nextToken());
082: i++;
083: }
084:
085: this .deploymentListeners = deploymentListeners;
086: this .ignoredFiles = new HashMap();
087: }
088:
089: /**
090: * <p>
091: * start
092: * </p>
093: *
094: * @see org.picocontainer.Startable#start()
095: */
096: public void start() {
097:
098: log.info("Starting auto deployment service: "
099: + getClass().getName());
100:
101: log.info("Deployment scanning delay: " + scanningDelay);
102:
103: log.info("Deployment staging directory: " + stagingDirectories);
104:
105: for (int i = 0; i < stagingDirectoriesAsFiles.length; i++) {
106: if (!stagingDirectoriesAsFiles[i].exists()) {
107: log.error(stagingDirectoriesAsFiles[i]
108: .getAbsolutePath()
109: + " does not exist, auto deployment disabled.");
110: stop();
111: return;
112: }
113: }
114:
115: // initialize listeners (where needed)
116: Iterator itr = deploymentListeners.iterator();
117: while (itr.hasNext()) {
118: ((DeploymentEventListener) itr.next()).initialize();
119: }
120:
121: if (scanningDelay > -1) {
122: try {
123: scanner = new FileSystemScanner(Thread.currentThread()
124: .getThreadGroup(),
125: "Autodeployment File Scanner Thread");
126:
127: scanner.setDaemon(true);
128: // scanner.setContextClassLoader(Thread.currentThread().getContextClassLoader());
129: scanner.setContextClassLoader(getClass()
130: .getClassLoader());
131: scanner.start();
132: log.info("Deployment scanner successfuly started!");
133: } catch (Exception e) {
134: log
135: .warn(
136: "Unable to intialize Catalina Portlet Application Manager. Auto deployment will be disabled: "
137: + e.toString(), e);
138:
139: stop();
140: return;
141: }
142: } else {
143: log
144: .info("Scanning delay set to "
145: + scanningDelay
146: + " has disabled automatic scanning of staging directory.");
147: }
148:
149: }
150:
151: /**
152: * <p>
153: * stop
154: * </p>
155: *
156: * @see org.picocontainer.Startable#stop()
157: */
158: public void stop() {
159: if (scanner != null) {
160: scanner.safeStop();
161: }
162: }
163:
164: public synchronized DeploymentStatus deploy(File aFile)
165: throws DeploymentException {
166: DeploymentObject deploymentObject = new StandardDeploymentObject(
167: aFile);
168: DeploymentEvent event = null;
169: try {
170: event = new DeploymentEventImpl(deploymentObject);
171: dispatch(event);
172: } finally {
173: if (deploymentObject != null) {
174: try {
175: deploymentObject.close();
176: } catch (IOException e) {
177: }
178: }
179: }
180: return event;
181: }
182:
183: public void fireDeploymentEvent() {
184: File[] stagedFiles = getAllStagedFiles();
185: for (int i = 0; i < stagedFiles.length; i++) {
186: // check for new deployment
187: File aFile = stagedFiles[i];
188: if (aFile.isFile() && !ignoreFile(aFile)) {
189: DeploymentStatus status = null;
190: Exception de = null;
191: try {
192: status = deploy(aFile);
193: } catch (Exception e) {
194: de = e;
195: }
196:
197: if (status != null
198: && status.getStatus() == DeploymentStatus.STATUS_OKAY) {
199: if (aFile.exists()) {
200: log.info("File: " + aFile.getAbsolutePath()
201: + " deployed");
202: boolean result = aFile.delete();
203: if (!result) {
204: log.error("Failed to remove: " + aFile);
205: }
206: }
207: } else {
208: if (status == null
209: || status.getStatus() == DeploymentStatus.STATUS_EVAL) {
210: log.warn("Unrecognized file "
211: + aFile.getAbsolutePath());
212: } else if (de != null) {
213: log.error("Failure deploying "
214: + aFile.getAbsolutePath(), de);
215: } else {
216: log.error("Failure deploying "
217: + aFile.getAbsolutePath());
218: }
219: ignoredFiles.put(aFile.getAbsolutePath(), new Long(
220: aFile.lastModified()));
221: }
222: }
223: }
224: }
225:
226: /**
227: * <p>
228: * dispatch
229: * </p>
230: *
231: * @see org.apache.jetspeed.deployment.DeploymentManager#dispatch(org.apache.jetspeed.deployment.DeploymentEvent)
232: * @param event
233: */
234: public void dispatch(DeploymentEvent event) {
235: try {
236: Iterator itr = deploymentListeners.iterator();
237: while (itr.hasNext()) {
238: DeploymentEventListener listener = (DeploymentEventListener) itr
239: .next();
240: listener.invokeDeploy(event);
241: if (event.getStatus() != DeploymentStatus.STATUS_EVAL) {
242: break;
243: }
244: }
245: } catch (DeploymentException e) {
246: log.error(e.getMessage(), e);
247: event.setStatus(DeploymentStatus.STATUS_FAILED);
248: }
249: }
250:
251: /**
252: * <p>
253: * ignoreFile
254: * </p>
255: *
256: * @param fileName
257: * @return
258: */
259: protected boolean ignoreFile(File aFile) {
260: Long previousModified = (Long) ignoredFiles.get(aFile
261: .getAbsolutePath());
262: if (previousModified != null) {
263: if (previousModified.longValue() != aFile.lastModified()) {
264: ignoredFiles.remove(aFile.getAbsolutePath());
265: } else {
266: return true;
267: }
268: }
269: return false;
270: }
271:
272: /**
273: * <p>
274: * getAllStagedFiles
275: * </p>
276: *
277: * @return
278: */
279: protected File[] getAllStagedFiles() {
280: ArrayList fileList = new ArrayList();
281: for (int i = 0; i < stagingDirectoriesAsFiles.length; i++) {
282: fileList.addAll(Arrays.asList(stagingDirectoriesAsFiles[i]
283: .listFiles(readmeIgnoringFileFilter)));
284: }
285:
286: return (File[]) fileList.toArray(new File[fileList.size()]);
287: }
288:
289: public class FileSystemScanner extends Thread {
290:
291: private boolean started = true;
292:
293: public FileSystemScanner(ThreadGroup threadGroup, String name)
294: throws FileNotFoundException, IOException {
295: super (threadGroup, name);
296: setPriority(MIN_PRIORITY);
297: }
298:
299: /**
300: * @see java.lang.Runnable#run()
301: */
302: public void run() {
303: // use a double scanningDelay at startup to give the App Server some time to wake up...
304: // see: http://issues.apache.org/jira/browse/JS2-261
305: try {
306: //
307: // this is just too abusive for server class machines
308: // and modern CPU/RAM configurations... if one REALLY
309: // needs to slow the startup sequence, edit this setting
310: // in WEB-INF/conf/jetspeed.properties:
311: //
312: // autodeployment.delay=10000
313: //
314: //sleep(scanningDelay*2);
315: sleep(scanningDelay);
316: } catch (InterruptedException e) {
317: }
318: while (started) {
319: fireDeploymentEvent();
320:
321: try {
322: sleep(scanningDelay);
323: } catch (InterruptedException e) {
324:
325: }
326: }
327: }
328:
329: /**
330: * notifies a switch variable that exits the watcher's montior loop started in the <code>run()</code> method.
331: */
332: public void safeStop() {
333: started = false;
334: }
335:
336: }
337:
338: }
|