View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.deploy.providers;
20  
21  import java.io.File;
22  import java.io.FilenameFilter;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.concurrent.CopyOnWriteArrayList;
30  
31  import org.eclipse.jetty.deploy.App;
32  import org.eclipse.jetty.deploy.AppProvider;
33  import org.eclipse.jetty.deploy.DeploymentManager;
34  import org.eclipse.jetty.util.Scanner;
35  import org.eclipse.jetty.util.annotation.ManagedAttribute;
36  import org.eclipse.jetty.util.annotation.ManagedObject;
37  import org.eclipse.jetty.util.component.AbstractLifeCycle;
38  import org.eclipse.jetty.util.log.Log;
39  import org.eclipse.jetty.util.log.Logger;
40  import org.eclipse.jetty.util.resource.Resource;
41  
42  /**
43   */
44  @ManagedObject("Abstract Provider for loading webapps")
45  public abstract class ScanningAppProvider extends AbstractLifeCycle implements AppProvider
46  {
47      private static final Logger LOG = Log.getLogger(ScanningAppProvider.class);
48  
49      private Map<String, App> _appMap = new HashMap<String, App>();
50  
51      private DeploymentManager _deploymentManager;
52      protected FilenameFilter _filenameFilter;
53      private final List<Resource> _monitored= new CopyOnWriteArrayList<>();
54      private boolean _recursive = false;
55      private int _scanInterval = 10;
56      private Scanner _scanner;
57  
58      /* ------------------------------------------------------------ */
59      private final Scanner.DiscreteListener _scannerListener = new Scanner.DiscreteListener()
60      {
61          @Override
62          public void fileAdded(String filename) throws Exception
63          {
64              ScanningAppProvider.this.fileAdded(filename);
65          }
66  
67          @Override
68          public void fileChanged(String filename) throws Exception
69          {
70              ScanningAppProvider.this.fileChanged(filename);
71          }
72  
73          @Override
74          public void fileRemoved(String filename) throws Exception
75          {
76              ScanningAppProvider.this.fileRemoved(filename);
77          }
78      };
79  
80      /* ------------------------------------------------------------ */
81      protected ScanningAppProvider()
82      {
83      }
84      
85      /* ------------------------------------------------------------ */
86      protected ScanningAppProvider(FilenameFilter filter)
87      {
88          _filenameFilter = filter;
89      }
90  
91      /* ------------------------------------------------------------ */
92      protected void setFilenameFilter(FilenameFilter filter)
93      {
94          if (isRunning())
95              throw new IllegalStateException();
96          _filenameFilter = filter;
97      }
98      
99      /* ------------------------------------------------------------ */
100     /**
101      * @return The index of currently deployed applications.
102      */
103     protected Map<String, App> getDeployedApps()
104     {
105         return _appMap;
106     }
107 
108     /* ------------------------------------------------------------ */
109     /**
110      * Called by the Scanner.DiscreteListener to create a new App object.
111      * Isolated in a method so that it is possible to override the default App
112      * object for specialized implementations of the AppProvider.
113      * 
114      * @param filename
115      *            The file that is the context.xml. It is resolved by
116      *            {@link Resource#newResource(String)}
117      * @return The App object for this particular context definition file.
118      */
119     protected App createApp(String filename)
120     {
121         return new App(_deploymentManager,this,filename);
122     }
123 
124     /* ------------------------------------------------------------ */
125     @Override
126     protected void doStart() throws Exception
127     {
128         if (LOG.isDebugEnabled()) 
129             LOG.debug(this.getClass().getSimpleName() + ".doStart()");
130         if (_monitored.size()==0)
131             throw new IllegalStateException("No configuration dir specified");
132 
133         LOG.info("Deployment monitor " + _monitored + " at interval " + _scanInterval);
134         List<File> files = new ArrayList<>();
135         for (Resource resource:_monitored)
136         {
137             if (resource.exists() && resource.getFile().canRead())
138                 files.add(resource.getFile());
139             else
140                 LOG.warn("Does not exist: "+resource);
141         }
142         
143         _scanner = new Scanner();
144         _scanner.setScanDirs(files);
145         _scanner.setScanInterval(_scanInterval);
146         _scanner.setRecursive(_recursive);
147         _scanner.setFilenameFilter(_filenameFilter);
148         _scanner.setReportDirs(true);
149         _scanner.addListener(_scannerListener);
150         _scanner.start();
151     }
152 
153     /* ------------------------------------------------------------ */
154     @Override
155     protected void doStop() throws Exception
156     {
157         if (_scanner!=null)
158         {
159             _scanner.stop();
160             _scanner.removeListener(_scannerListener);
161             _scanner = null;
162         }
163     }
164     
165     /* ------------------------------------------------------------ */
166     protected boolean exists(String path)
167     {
168         return _scanner.exists(path);
169     }
170 
171     /* ------------------------------------------------------------ */
172     protected void fileAdded(String filename) throws Exception
173     {
174         if (LOG.isDebugEnabled()) 
175             LOG.debug("added {}",filename);
176         App app = ScanningAppProvider.this.createApp(filename);
177         if (app != null)
178         {
179             _appMap.put(filename,app);
180             _deploymentManager.addApp(app);
181         }
182     }
183 
184     /* ------------------------------------------------------------ */
185     protected void fileChanged(String filename) throws Exception
186     {
187         if (LOG.isDebugEnabled()) 
188             LOG.debug("changed {}",filename);
189         App app = _appMap.remove(filename);
190         if (app != null)
191         {
192             _deploymentManager.removeApp(app);
193         }
194         app = ScanningAppProvider.this.createApp(filename);
195         if (app != null)
196         {
197             _appMap.put(filename,app);
198             _deploymentManager.addApp(app);
199         }
200     }
201     
202     /* ------------------------------------------------------------ */
203     protected void fileRemoved(String filename) throws Exception
204     {
205         if (LOG.isDebugEnabled()) 
206             LOG.debug("removed {}",filename);
207         App app = _appMap.remove(filename);
208         if (app != null)
209             _deploymentManager.removeApp(app);
210     }
211     
212     /* ------------------------------------------------------------ */
213     /**
214      * Get the deploymentManager.
215      * 
216      * @return the deploymentManager
217      */
218     public DeploymentManager getDeploymentManager()
219     {
220         return _deploymentManager;
221     }
222 
223 
224     /* ------------------------------------------------------------ */
225     public Resource getMonitoredDirResource()
226     {
227         if (_monitored.size()==0)
228             return null;
229         if (_monitored.size()>1)
230             throw new IllegalStateException();
231         return _monitored.get(0);
232     }
233 
234     /* ------------------------------------------------------------ */
235     public String getMonitoredDirName()
236     {
237         Resource resource=getMonitoredDirResource();
238         return resource==null?null:resource.toString();
239     }
240 
241     /* ------------------------------------------------------------ */
242     @ManagedAttribute("scanning interval to detect changes which need reloaded")
243     public int getScanInterval()
244     {
245         return _scanInterval;
246     }
247 
248     /* ------------------------------------------------------------ */
249     @ManagedAttribute("recursive scanning supported")
250     public boolean isRecursive()
251     {
252         return _recursive;
253     }
254 
255     /* ------------------------------------------------------------ */
256     @Override
257     public void setDeploymentManager(DeploymentManager deploymentManager)
258     {
259         _deploymentManager = deploymentManager;
260     }
261     
262     /* ------------------------------------------------------------ */
263     public void setMonitoredResources(List<Resource> resources)
264     {
265         _monitored.clear();
266         _monitored.addAll(resources);
267     }
268     
269     /* ------------------------------------------------------------ */
270     public List<Resource> getMonitoredResources()
271     {
272         return Collections.unmodifiableList(_monitored);
273     }
274     
275     /* ------------------------------------------------------------ */
276     public void setMonitoredDirResource(Resource resource)
277     {
278         setMonitoredResources(Collections.singletonList(resource));
279     }
280 
281     /* ------------------------------------------------------------ */
282     public void addScannerListener(Scanner.Listener listener)
283     {
284         _scanner.addListener(listener);
285     }
286     
287     /* ------------------------------------------------------------ */
288     /**
289      * @param dir
290      *            Directory to scan for context descriptors or war files
291      */
292     public void setMonitoredDirName(String dir)
293     {
294         setMonitoredDirectories(Collections.singletonList(dir));
295     }
296 
297     /* ------------------------------------------------------------ */
298     public void setMonitoredDirectories(Collection<String> directories)
299     {
300         try
301         {
302             List<Resource> resources = new ArrayList<>();
303             for (String dir:directories)
304                 resources.add(Resource.newResource(dir));
305             setMonitoredResources(resources);
306         }
307         catch (Exception e)
308         {
309             throw new IllegalArgumentException(e);
310         }
311     }
312     
313     /* ------------------------------------------------------------ */
314     protected void setRecursive(boolean recursive)
315     {
316         _recursive = recursive;
317     }
318 
319     /* ------------------------------------------------------------ */
320     public void setScanInterval(int scanInterval)
321     {
322         _scanInterval = scanInterval;
323     }
324 }