1 package org.eclipse.jetty.deploy.providers;
2 //========================================================================
3 //Copyright 2009-2012 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 //The Eclipse Public License is available at
9 //http://www.eclipse.org/legal/epl-v10.html
10 //The Apache License v2.0 is available at
11 //http://www.opensource.org/licenses/apache2.0.php
12 //You may elect to redistribute this code under either of these licenses.
13 //========================================================================
14
15 import java.io.File;
16 import java.io.FilenameFilter;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19
20 import org.eclipse.jetty.deploy.App;
21 import org.eclipse.jetty.deploy.util.FileID;
22 import org.eclipse.jetty.server.handler.ContextHandler;
23 import org.eclipse.jetty.util.URIUtil;
24 import org.eclipse.jetty.util.resource.Resource;
25 import org.eclipse.jetty.webapp.WebAppContext;
26
27 /* ------------------------------------------------------------ */
28 /** Context directory App Provider.
29 * <p>This specialization of {@link ScanningAppProvider} is the
30 * replacement for old (and deprecated) <code>org.eclipse.jetty.deploy.WebAppDeployer</code> and it will scan a directory
31 * only for war files or directories files.</p>
32 * <p>
33 * Webapps with names root or starting with root- are deployed at /.
34 * If the name is in the format root-hostname, then the webapp is deployed
35 * at / in the virtual host hostname.
36 */
37 public class WebAppProvider extends ScanningAppProvider
38 {
39 private boolean _extractWars = false;
40 private boolean _parentLoaderPriority = false;
41 private String _defaultsDescriptor;
42 private Filter _filter;
43 private File _tempDirectory;
44 private String[] _configurationClasses;
45
46 public static class Filter implements FilenameFilter
47 {
48 private File _contexts;
49
50 public boolean accept(File dir, String name)
51 {
52 if (!dir.exists())
53 {
54 return false;
55 }
56 String lowername = name.toLowerCase();
57
58 File file = new File(dir,name);
59 // is it not a directory and not a war ?
60 if (!file.isDirectory() && !lowername.endsWith(".war"))
61 {
62 return false;
63 }
64
65 //ignore hidden files
66 if (lowername.startsWith("."))
67 return false;
68
69 if (file.isDirectory())
70 {
71 // is it a directory for an existing war file?
72 if (new File(dir,name+".war").exists() ||
73 new File(dir,name+".WAR").exists())
74
75 return false;
76
77 //is it a sccs dir?
78 if ("cvs".equals(lowername) || "cvsroot".equals(lowername))
79 return false;
80 }
81
82 // is there a contexts config file
83 if (_contexts!=null)
84 {
85 String context=name;
86 if (!file.isDirectory())
87 {
88 context=context.substring(0,context.length()-4);
89 }
90 if (new File(_contexts,context+".xml").exists() ||
91 new File(_contexts,context+".XML").exists() )
92 {
93 return false;
94 }
95 }
96
97 return true;
98 }
99 }
100
101 /* ------------------------------------------------------------ */
102 public WebAppProvider()
103 {
104 super(new Filter());
105 _filter=(Filter)_filenameFilter;
106 setScanInterval(0);
107 }
108
109 /* ------------------------------------------------------------ */
110 /** Get the extractWars.
111 * @return the extractWars
112 */
113 public boolean isExtractWars()
114 {
115 return _extractWars;
116 }
117
118 /* ------------------------------------------------------------ */
119 /** Set the extractWars.
120 * @param extractWars the extractWars to set
121 */
122 public void setExtractWars(boolean extractWars)
123 {
124 _extractWars = extractWars;
125 }
126
127 /* ------------------------------------------------------------ */
128 /** Get the parentLoaderPriority.
129 * @return the parentLoaderPriority
130 */
131 public boolean isParentLoaderPriority()
132 {
133 return _parentLoaderPriority;
134 }
135
136 /* ------------------------------------------------------------ */
137 /** Set the parentLoaderPriority.
138 * @param parentLoaderPriority the parentLoaderPriority to set
139 */
140 public void setParentLoaderPriority(boolean parentLoaderPriority)
141 {
142 _parentLoaderPriority = parentLoaderPriority;
143 }
144
145 /* ------------------------------------------------------------ */
146 /** Get the defaultsDescriptor.
147 * @return the defaultsDescriptor
148 */
149 public String getDefaultsDescriptor()
150 {
151 return _defaultsDescriptor;
152 }
153
154 /* ------------------------------------------------------------ */
155 /** Set the defaultsDescriptor.
156 * @param defaultsDescriptor the defaultsDescriptor to set
157 */
158 public void setDefaultsDescriptor(String defaultsDescriptor)
159 {
160 _defaultsDescriptor = defaultsDescriptor;
161 }
162
163 /* ------------------------------------------------------------ */
164 public String getContextXmlDir()
165 {
166 return _filter._contexts==null?null:_filter._contexts.toString();
167 }
168
169 /* ------------------------------------------------------------ */
170 /**
171 * Set the directory in which to look for context XML files.
172 * <p>
173 * If a webapp call "foo/" or "foo.war" is discovered in the monitored
174 * directory, then the ContextXmlDir is examined to see if a foo.xml
175 * file exists. If it does, then this deployer will not deploy the webapp
176 * and the ContextProvider should be used to act on the foo.xml file.
177 * @see ContextProvider
178 * @param contextsDir
179 */
180 public void setContextXmlDir(String contextsDir)
181 {
182 try
183 {
184 _filter._contexts=Resource.newResource(contextsDir).getFile();
185 }
186 catch (MalformedURLException e)
187 {
188 throw new RuntimeException(e);
189 }
190 catch (IOException e)
191 {
192 throw new RuntimeException(e);
193 }
194 }
195
196
197 /* ------------------------------------------------------------ */
198 /**
199 * @param configurations The configuration class names.
200 */
201 public void setConfigurationClasses(String[] configurations)
202 {
203 _configurationClasses = configurations==null?null:(String[])configurations.clone();
204 }
205
206 /* ------------------------------------------------------------ */
207 /**
208 *
209 */
210 public String[] getConfigurationClasses()
211 {
212 return _configurationClasses;
213 }
214
215 /**
216 * Set the Work directory where unpacked WAR files are managed from.
217 * <p>
218 * Default is the same as the <code>java.io.tmpdir</code> System Property.
219 *
220 * @param directory the new work directory
221 */
222 public void setTempDir(File directory)
223 {
224 _tempDirectory = directory;
225 }
226
227 /**
228 * Get the user supplied Work Directory.
229 *
230 * @return the user supplied work directory (null if user has not set Temp Directory yet)
231 */
232 public File getTempDir()
233 {
234 return _tempDirectory;
235 }
236
237 /* ------------------------------------------------------------ */
238 public ContextHandler createContextHandler(final App app) throws Exception
239 {
240 Resource resource = Resource.newResource(app.getOriginId());
241 File file = resource.getFile();
242 if (!resource.exists())
243 throw new IllegalStateException("App resouce does not exist "+resource);
244
245 String context = file.getName();
246
247 if (file.isDirectory())
248 {
249 // must be a directory
250 }
251 else if (FileID.isWebArchiveFile(file))
252 {
253 // Context Path is the same as the archive.
254 context = context.substring(0,context.length() - 4);
255 }
256 else
257 {
258 throw new IllegalStateException("unable to create ContextHandler for "+app);
259 }
260
261 // Ensure "/" is Not Trailing in context paths.
262 if (context.endsWith("/") && context.length() > 0)
263 {
264 context = context.substring(0,context.length() - 1);
265 }
266
267 // Start building the webapplication
268 WebAppContext wah = new WebAppContext();
269 wah.setDisplayName(context);
270
271 // special case of archive (or dir) named "root" is / context
272 if (context.equalsIgnoreCase("root"))
273 {
274 context = URIUtil.SLASH;
275 }
276 else if (context.toLowerCase().startsWith("root-"))
277 {
278 int dash=context.toLowerCase().indexOf('-');
279 String virtual = context.substring(dash+1);
280 wah.setVirtualHosts(new String[]{virtual});
281 context = URIUtil.SLASH;
282 }
283
284 // Ensure "/" is Prepended to all context paths.
285 if (context.charAt(0) != '/')
286 {
287 context = "/" + context;
288 }
289
290
291 wah.setContextPath(context);
292 wah.setWar(file.getAbsolutePath());
293 if (_defaultsDescriptor != null)
294 {
295 wah.setDefaultsDescriptor(_defaultsDescriptor);
296 }
297 wah.setExtractWAR(_extractWars);
298 wah.setParentLoaderPriority(_parentLoaderPriority);
299 if (_configurationClasses != null)
300 {
301 wah.setConfigurationClasses(_configurationClasses);
302 }
303
304 if (_tempDirectory != null)
305 {
306 /* Since the Temp Dir is really a context base temp directory,
307 * Lets set the Temp Directory in a way similar to how WebInfConfiguration does it,
308 * instead of setting the
309 * WebAppContext.setTempDirectory(File).
310 * If we used .setTempDirectory(File) all webapps will wind up in the
311 * same temp / work directory, overwriting each others work.
312 */
313 wah.setAttribute(WebAppContext.BASETEMPDIR,_tempDirectory);
314 }
315 return wah;
316 }
317
318 }