1 // ========================================================================
2 // Copyright (c) 2009 Mortbay, Inc.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // Contributors:
13 // Greg Wilkins - initial API and implementation
14 // ========================================================================
15 package org.eclipse.jetty.osgi.boot;
16
17 import java.io.File;
18 import java.io.FilenameFilter;
19 import java.io.IOException;
20
21 import org.eclipse.jetty.deploy.App;
22 import org.eclipse.jetty.deploy.AppProvider;
23 import org.eclipse.jetty.deploy.DeploymentManager;
24 import org.eclipse.jetty.deploy.providers.ContextProvider;
25 import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
26 import org.eclipse.jetty.server.handler.ContextHandler;
27 import org.eclipse.jetty.util.resource.Resource;
28
29 /**
30 * AppProvider for OSGi. Supports the configuration of ContextHandlers and
31 * WebApps. Extends the AbstractAppProvider to support the scanning of context
32 * files located outside of the bundles.
33 * <p>
34 * This provider must not be called outside of jetty.boot: it should always be
35 * called via the OSGi service listener.
36 * </p>
37 * <p>
38 * This provider supports the same set of parameters than the WebAppProvider as
39 * it supports the deployment of WebAppContexts. Except for the scanning of the
40 * webapps directory.
41 * </p>
42 */
43 public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
44 {
45
46 private boolean _extractWars = false;
47 private boolean _parentLoaderPriority = false;
48 private String _defaultsDescriptor;
49 private String _tldBundles;
50
51 /**
52 * When a context file corresponds to a deployed bundle and is changed we
53 * reload the corresponding bundle.
54 */
55 private static class Filter implements FilenameFilter
56 {
57 OSGiAppProvider _enclosedInstance;
58
59 public boolean accept(File dir, String name)
60 {
61 if (!new File(dir,name).isDirectory())
62 {
63 String contextName = getDeployedAppName(name);
64 if (contextName != null)
65 {
66 App app = _enclosedInstance.getDeployedApps().get(contextName);
67 return app != null;
68 }
69 }
70 return false;
71 }
72 }
73
74 /**
75 * @param contextFileName
76 * for example myContext.xml
77 * @return The context, for example: myContext; null if this was not a
78 * suitable contextFileName.
79 */
80 private static String getDeployedAppName(String contextFileName)
81 {
82 String lowername = contextFileName.toLowerCase();
83 if (lowername.endsWith(".xml"))
84 {
85 String contextName = contextFileName.substring(0,lowername.length() - ".xml".length());
86 return contextName;
87 }
88 return null;
89 }
90
91 /**
92 * Default OSGiAppProvider consutructed when none are defined in the
93 * jetty.xml configuration.
94 *
95 * @param contextsDir
96 */
97 public OSGiAppProvider()
98 {
99 super(new Filter());
100 ((Filter)super._filenameFilter)._enclosedInstance = this;
101 }
102
103 /**
104 * Default OSGiAppProvider consutructed when none are defined in the
105 * jetty.xml configuration.
106 *
107 * @param contextsDir
108 */
109 public OSGiAppProvider(File contextsDir) throws IOException
110 {
111 this();
112 setMonitoredDir(Resource.newResource(contextsDir.toURI()));
113 }
114
115 /**
116 * Returns the ContextHandler that was created by WebappRegistractionHelper
117 *
118 * @see AppProvider
119 */
120 public ContextHandler createContextHandler(App app) throws Exception
121 {
122 // return pre-created Context
123 if (app.getContextId() != null)
124 {
125 return app.getContextHandler();
126 }
127 // for some reason it was not defined when the App was constructed.
128 // we don't support this situation at this point.
129 // once the WebAppRegistrationHelper is refactored, the code
130 // that creates the ContextHandler will actually be here.
131 throw new IllegalStateException("The App must be passed the " + "instance of the ContextHandler when it is construsted");
132 }
133
134 /**
135 * @see AppProvider
136 */
137 public void setDeploymentManager(DeploymentManager deploymentManager)
138 {
139 // _manager=deploymentManager;
140 super.setDeploymentManager(deploymentManager);
141 }
142
143 /**
144 * @param context
145 * @throws Exception
146 */
147 public void addContext(ContextHandler context) throws Exception
148 {
149 // TODO apply configuration specific to this provider
150
151 // wrap context as an App
152 App app = new App(getDeploymentManager(),this,context.getDisplayName(),context);
153 getDeployedApps().put(context.getDisplayName(),app);
154 getDeploymentManager().addApp(app);
155 }
156
157 /**
158 * Called by the scanner of the context files directory. If we find the
159 * corresponding deployed App we reload it by returning the App. Otherwise
160 * we return null and nothing happens: presumably the corresponding OSGi
161 * webapp is not ready yet.
162 *
163 * @return the corresponding already deployed App so that it will be
164 * reloaded. Otherwise returns null.
165 */
166 @Override
167 protected App createApp(String filename)
168 {
169 // find the corresponding bundle and ContextHandler or WebAppContext
170 // and reload the corresponding App.
171 // see the 2 pass of the refactoring of the WebAppRegistrationHelper.
172 String name = getDeployedAppName(filename);
173 if (name != null)
174 {
175 return getDeployedApps().get(name);
176 }
177 return null;
178 }
179
180 public void removeContext(ContextHandler context) throws Exception
181 {
182 App app = getDeployedApps().remove(context.getDisplayName());
183 if (app != null)
184 {
185 getDeploymentManager().removeApp(app);
186 }
187 }
188
189 // //copied from WebAppProvider as the parameters are identical.
190 // //only removed the parameer related to extractWars.
191 /* ------------------------------------------------------------ */
192 /**
193 * Get the parentLoaderPriority.
194 *
195 * @return the parentLoaderPriority
196 */
197 public boolean isParentLoaderPriority()
198 {
199 return _parentLoaderPriority;
200 }
201
202 /* ------------------------------------------------------------ */
203 /**
204 * Set the parentLoaderPriority.
205 *
206 * @param parentLoaderPriority
207 * the parentLoaderPriority to set
208 */
209 public void setParentLoaderPriority(boolean parentLoaderPriority)
210 {
211 _parentLoaderPriority = parentLoaderPriority;
212 }
213
214 /* ------------------------------------------------------------ */
215 /**
216 * Get the defaultsDescriptor.
217 *
218 * @return the defaultsDescriptor
219 */
220 public String getDefaultsDescriptor()
221 {
222 return _defaultsDescriptor;
223 }
224
225 /* ------------------------------------------------------------ */
226 /**
227 * Set the defaultsDescriptor.
228 *
229 * @param defaultsDescriptor
230 * the defaultsDescriptor to set
231 */
232 public void setDefaultsDescriptor(String defaultsDescriptor)
233 {
234 _defaultsDescriptor = defaultsDescriptor;
235 }
236
237 /**
238 * The context xml directory. In fact it is the directory watched by the
239 * scanner.
240 */
241 public File getContextXmlDirAsFile()
242 {
243 try
244 {
245 Resource monitoredDir = getMonitoredDir();
246 if (monitoredDir == null)
247 return null;
248 return monitoredDir.getFile();
249 }
250 catch (IOException e)
251 {
252 e.printStackTrace();
253 return null;
254 }
255 }
256
257 /* ------------------------------------------------------------ */
258 /**
259 * The context xml directory. In fact it is the directory watched by the
260 * scanner.
261 */
262 public String getContextXmlDir()
263 {
264 try
265 {
266 Resource monitoredDir = getMonitoredDir();
267 if (monitoredDir == null)
268 return null;
269 return monitoredDir.getFile().toURI().toString();
270 }
271 catch (IOException e)
272 {
273 e.printStackTrace();
274 return null;
275 }
276 }
277
278 /* ------------------------------------------------------------ */
279 /**
280 * Set the directory in which to look for context XML files.
281 * <p>
282 * If a webapp call "foo/" or "foo.war" is discovered in the monitored
283 * directory, then the ContextXmlDir is examined to see if a foo.xml file
284 * exists. If it does, then this deployer will not deploy the webapp and the
285 * ContextProvider should be used to act on the foo.xml file.
286 *
287 * @see ContextProvider
288 * @param contextsDir
289 */
290 public void setContextXmlDir(String contextsDir)
291 {
292 setMonitoredDir(contextsDir);
293 }
294
295 /**
296 * @param tldBundles Comma separated list of bundles that contain tld jars
297 * that should be setup on the jetty instances created here.
298 */
299 public void setTldBundles(String tldBundles)
300 {
301 _tldBundles = tldBundles;
302 }
303
304 /**
305 * @return The list of bundles that contain tld jars that should be setup
306 * on the jetty instances created here.
307 */
308 public String getTldBundles()
309 {
310 return _tldBundles;
311 }
312
313 }