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