View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.deployment.impl;
18  
19  import java.io.File;
20  import java.io.FileFilter;
21  import java.io.FileNotFoundException;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.HashMap;
27  import java.util.Iterator;
28  import java.util.StringTokenizer;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.jetspeed.components.portletregistry.PortletRegistry;
33  import org.apache.jetspeed.deployment.DeploymentEvent;
34  import org.apache.jetspeed.deployment.DeploymentEventListener;
35  import org.apache.jetspeed.deployment.DeploymentException;
36  import org.apache.jetspeed.deployment.DeploymentManager;
37  import org.apache.jetspeed.deployment.DeploymentObject;
38  import org.apache.jetspeed.deployment.DeploymentStatus;
39  
40  /***
41   * <p>
42   * StandardDeploymentManager
43   * </p>
44   * Implementation of {@link org.apache.jetspeed.deployment.DeploymentManager}
45   * 
46   * @author <a href="mailto:weaver@apache.org">Scott T. Weaver </a>
47   * @version $Id: StandardDeploymentManager.java 517121 2007-03-12 07:45:49Z ate $
48   */
49  public class StandardDeploymentManager implements DeploymentManager
50  {
51      private static final FileFilter readmeIgnoringFileFilter = new FileFilter()
52      {
53          public boolean accept(File file)
54          {
55              return !file.getName().equalsIgnoreCase("README.txt");
56          }
57      };
58      
59      protected Log               log = LogFactory.getLog("deployment");
60      protected FileSystemScanner scanner;
61      protected PortletRegistry   registry;
62      protected Collection        deploymentListeners;
63      protected long              scanningDelay;
64      protected String            stagingDirectories;
65      protected File[]            stagingDirectoriesAsFiles;
66      protected HashMap           ignoredFiles;
67  
68      /***
69       * @param stagingDirectories
70       * @param scanningDelay
71       * @param deploymentListeners
72       */
73      public StandardDeploymentManager(String stagingDirectories, long scanningDelay, Collection deploymentListeners)
74      {
75          this.scanningDelay = scanningDelay;
76          this.stagingDirectories = stagingDirectories;
77          StringTokenizer dirTokenizer = new StringTokenizer(stagingDirectories, ",");
78          this.stagingDirectoriesAsFiles = new File[dirTokenizer.countTokens()];
79          int i = 0;
80          while (dirTokenizer.hasMoreTokens())
81          {
82              this.stagingDirectoriesAsFiles[i] = new File(dirTokenizer.nextToken());
83              i++;
84          }
85  
86          this.deploymentListeners = deploymentListeners;
87          this.ignoredFiles = new HashMap();
88      }
89  
90      /***
91       * <p>
92       * start
93       * </p>
94       * 
95       * @see org.picocontainer.Startable#start()
96       */
97      public void start()
98      {
99  
100         log.info("Starting auto deployment service: " + getClass().getName());
101 
102         log.info("Deployment scanning delay: " + scanningDelay);
103 
104         log.info("Deployment staging directory: " + stagingDirectories);
105 
106         for (int i = 0; i < stagingDirectoriesAsFiles.length; i++)
107         {
108             if (!stagingDirectoriesAsFiles[i].exists())
109             {
110                 log
111                                 .error(stagingDirectoriesAsFiles[i].getAbsolutePath()
112                                        + " does not exist, auto deployment disabled.");
113                 stop();
114                 return;
115             }
116         }
117 
118         // initialize listeners (where needed)
119         Iterator itr = deploymentListeners.iterator();
120         while (itr.hasNext())
121         {
122             ((DeploymentEventListener) itr.next()).initialize();
123         }
124 
125         if (scanningDelay > -1)
126         {
127             try
128             {
129                 scanner = new FileSystemScanner(Thread.currentThread().getThreadGroup(),
130                                                 "Autodeployment File Scanner Thread");
131 
132                 scanner.setDaemon(true);
133                 // scanner.setContextClassLoader(Thread.currentThread().getContextClassLoader());
134                 scanner.setContextClassLoader(getClass().getClassLoader());
135                 scanner.start();
136                 log.info("Deployment scanner successfuly started!");
137             }
138             catch (Exception e)
139             {
140                 log.warn(
141                          "Unable to intialize Catalina Portlet Application Manager.  Auto deployment will be disabled: "
142                                                                                                     + e.toString(), e);
143 
144                 stop();
145                 return;
146             }
147         }
148         else
149         {
150             log.info("Scanning delay set to " + scanningDelay
151                      + " has disabled automatic scanning of staging directory.");
152         }
153 
154     }
155 
156     /***
157      * <p>
158      * stop
159      * </p>
160      * 
161      * @see org.picocontainer.Startable#stop()
162      */
163     public void stop()
164     {
165         if (scanner != null)
166         {
167             scanner.safeStop();
168         }
169     }
170     
171     public synchronized DeploymentStatus deploy(File aFile) throws DeploymentException
172     {
173         DeploymentObject deploymentObject = new StandardDeploymentObject(aFile);
174         DeploymentEvent event = null;
175         try
176         {
177             event = new DeploymentEventImpl(deploymentObject);
178             dispatch(event);
179         }
180         finally
181         {
182             if ( deploymentObject != null )
183             {
184                 try
185                 {
186                     deploymentObject.close();
187                 }
188                 catch (IOException e)
189                 {                    
190                 }
191             }
192         }
193         return event;
194     }
195 
196     public void fireDeploymentEvent()
197     {
198         File[] stagedFiles = getAllStagedFiles();
199         for (int i = 0; i < stagedFiles.length; i++)
200         {
201             // check for new deployment
202             File aFile = stagedFiles[i];
203             if (aFile.isFile() && !ignoreFile(aFile))
204             {
205                 DeploymentStatus status = null;
206                 Exception de = null;
207                 try
208                 {
209                     status = deploy(aFile);
210                 }
211                 catch (Exception e)
212                 {                    
213                     de = e;
214                 }
215                 
216                 if ( status != null && status.getStatus() == DeploymentStatus.STATUS_OKAY )
217                 {
218                     if (aFile.exists())
219                     {
220                         log.info("File: " + aFile.getAbsolutePath() + " deployed");
221                         boolean result = aFile.delete();
222                         if (!result)
223                         {
224                            	log.error("Failed to remove: " + aFile);
225                         }
226                     }
227                 }
228                 else
229                 {
230                     if (status == null || status.getStatus() == DeploymentStatus.STATUS_EVAL)
231                     {
232                         log.warn("Unrecognized file " + aFile.getAbsolutePath());
233                     }
234                     else if ( de != null )
235                     {
236                         log.error("Failure deploying " + aFile.getAbsolutePath(), de);
237                     }
238                     else
239                     {
240                         log.error("Failure deploying " + aFile.getAbsolutePath());
241                     }
242                     ignoredFiles.put(aFile.getAbsolutePath(), new Long(aFile.lastModified()));
243                 }
244             }
245         }
246     }
247 
248     /***
249      * <p>
250      * dispatch
251      * </p>
252      * 
253      * @see org.apache.jetspeed.deployment.DeploymentManager#dispatch(org.apache.jetspeed.deployment.DeploymentEvent)
254      * @param event
255      */
256     public void dispatch(DeploymentEvent event)
257     {
258         try
259         {
260             Iterator itr = deploymentListeners.iterator();
261             while (itr.hasNext())
262             {
263                 DeploymentEventListener listener = (DeploymentEventListener) itr.next();
264                 listener.invokeDeploy(event);
265                 if (event.getStatus() != DeploymentStatus.STATUS_EVAL)
266                 {
267                     break;
268                 }
269             }
270         }
271         catch (DeploymentException e)
272         {
273             log.error(e.getMessage(), e);
274             event.setStatus(DeploymentStatus.STATUS_FAILED);
275         }
276     }
277 
278     /***
279      * <p>
280      * ignoreFile
281      * </p>
282      * 
283      * @param fileName
284      * @return
285      */
286     protected boolean ignoreFile(File aFile)
287     {
288         Long previousModified = (Long) ignoredFiles.get(aFile.getAbsolutePath());
289         if (previousModified != null)
290         {
291             if (previousModified.longValue() != aFile.lastModified())
292             {
293                 ignoredFiles.remove(aFile.getAbsolutePath());
294             }
295             else
296             {
297                 return true;
298             }
299         }
300         return false;
301     }
302 
303     /***
304      * <p>
305      * getAllStagedFiles
306      * </p>
307      * 
308      * @return
309      */
310     protected File[] getAllStagedFiles()
311     {
312         ArrayList fileList = new ArrayList();
313         for (int i = 0; i < stagingDirectoriesAsFiles.length; i++)
314         {
315             fileList.addAll(Arrays.asList(stagingDirectoriesAsFiles[i].listFiles(readmeIgnoringFileFilter)));
316         }
317 
318         return (File[]) fileList.toArray(new File[fileList.size()]);
319     }
320 
321     public class FileSystemScanner extends Thread
322     {
323 
324         private boolean started = true;
325 
326         public FileSystemScanner(ThreadGroup threadGroup, String name) throws FileNotFoundException, IOException
327         {
328             super(threadGroup, name);
329             setPriority(MIN_PRIORITY);
330         }
331 
332         /***
333          * @see java.lang.Runnable#run()
334          */
335         public void run()
336         {
337             // use a double scanningDelay at startup to give the App Server some time to wake up...
338             // see: http://issues.apache.org/jira/browse/JS2-261
339             try
340             {
341                 //
342                 // this is just too abusive for server class machines
343                 // and modern CPU/RAM configurations... if one REALLY
344                 // needs to slow the startup sequence, edit this setting
345                 // in WEB-INF/conf/jetspeed.properties:
346                 //
347                 // autodeployment.delay=10000
348                 //
349                 //sleep(scanningDelay*2);
350                 sleep(scanningDelay);
351             }
352             catch (InterruptedException e)
353             {
354             }
355             while (started)
356             {
357                 fireDeploymentEvent();
358 
359                 try
360                 {
361                     sleep(scanningDelay);
362                 }
363                 catch (InterruptedException e)
364                 {
365 
366                 }
367             }
368         }
369 
370         /***
371          * notifies a switch variable that exits the watcher's montior loop started in the <code>run()</code> method.
372          */
373         public void safeStop()
374         {
375             started = false;
376         }
377 
378     }
379 
380 }