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