1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.deployment.hot;
18
19 import org.apache.geronimo.gbean.GBeanLifecycle;
20 import org.apache.geronimo.gbean.GBeanInfo;
21 import org.apache.geronimo.gbean.GBeanInfoBuilder;
22 import org.apache.geronimo.gbean.AbstractName;
23 import org.apache.geronimo.gbean.AbstractNameQuery;
24 import org.apache.geronimo.system.serverinfo.ServerInfo;
25 import org.apache.geronimo.deployment.plugin.factories.DeploymentFactoryImpl;
26 import org.apache.geronimo.deployment.plugin.jmx.JMXDeploymentManager;
27 import org.apache.geronimo.deployment.cli.DeployUtils;
28 import org.apache.geronimo.common.DeploymentException;
29 import org.apache.geronimo.kernel.config.PersistentConfigurationList;
30 import org.apache.geronimo.kernel.config.ConfigurationManager;
31 import org.apache.geronimo.kernel.config.Configuration;
32 import org.apache.geronimo.kernel.config.DeploymentWatcher;
33 import org.apache.geronimo.kernel.Kernel;
34 import org.apache.geronimo.kernel.repository.Artifact;
35 import org.apache.geronimo.kernel.repository.MissingDependencyException;
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39 import javax.enterprise.deploy.spi.DeploymentManager;
40 import javax.enterprise.deploy.spi.TargetModuleID;
41 import javax.enterprise.deploy.spi.Target;
42 import javax.enterprise.deploy.spi.exceptions.DeploymentManagerCreationException;
43 import javax.enterprise.deploy.spi.status.ProgressObject;
44 import javax.enterprise.deploy.spi.factories.DeploymentFactory;
45
46 import java.io.File;
47 import java.util.Set;
48 import java.util.Iterator;
49
50 /**
51 * A directory-scanning hot deployer
52 *
53 * @version $Rev: 437623 $ $Date: 2006-08-28 02:48:23 -0700 (Mon, 28 Aug 2006) $
54 */
55 public class DirectoryHotDeployer implements HotDeployer, DeploymentWatcher, GBeanLifecycle {
56 private static final Log log = LogFactory.getLog(DirectoryHotDeployer.class);
57
58
59 private static final String BAD_LAYOUT_MESSAGE = "CANNOT DEPLOY: It looks like you unpacked an application or module " +
60 "directly into the hot deployment directory. THIS DOES NOT WORK. You need to unpack into a " +
61 "subdirectory directly under the hot deploy directory. For example, if the hot deploy directory " +
62 "is 'deploy/' and your file is 'webapp.war' then you could unpack it into a directory 'deploy/webapp.war/'";
63 private DirectoryMonitor monitor;
64 private String path;
65 private ServerInfo serverInfo;
66 private ConfigurationManager configManager;
67 private int pollIntervalMillis;
68 private String deploymentURI = "deployer:geronimo:inVM";
69 private String deploymentUser;
70 private String deploymentPassword;
71 private transient Kernel kernel;
72 private transient DeploymentFactory factory;
73 private transient TargetModuleID[] startupModules = null;
74 private transient boolean serverRunning = false;
75
76 public DirectoryHotDeployer(String path, int pollIntervalMillis, ServerInfo serverInfo, ConfigurationManager configManager, Kernel kernel) {
77 this.path = path;
78 this.serverInfo = serverInfo;
79 this.pollIntervalMillis = pollIntervalMillis;
80 this.kernel = kernel;
81 this.configManager = configManager;
82 }
83
84 public void deployed(Artifact id) {
85
86 }
87
88 public void undeployed(Artifact id) {
89
90 monitor.removeModuleId(id);
91 }
92
93 public String getPath() {
94 return path;
95 }
96
97 public void setPath(String path) {
98 this.path = path;
99 }
100
101 public ServerInfo getServerInfo() {
102 return serverInfo;
103 }
104
105 public void setServerInfo(ServerInfo serverInfo) {
106 this.serverInfo = serverInfo;
107 }
108
109 public int getPollIntervalMillis() {
110 return pollIntervalMillis;
111 }
112
113 public void setPollIntervalMillis(int pollIntervalMillis) {
114 this.pollIntervalMillis = pollIntervalMillis;
115 }
116
117 public String getDeploymentURI() {
118 return deploymentURI;
119 }
120
121 public void setDeploymentURI(String deploymentURI) {
122 if (deploymentURI != null && !deploymentURI.trim().equals("")) {
123 this.deploymentURI = deploymentURI.trim();
124 }
125 }
126
127 public String getDeploymentUser() {
128 return deploymentUser;
129 }
130
131 public void setDeploymentUser(String deploymentUser) {
132 this.deploymentUser = deploymentUser;
133 }
134
135 public String getDeploymentPassword() {
136 return deploymentPassword;
137 }
138
139 public void setDeploymentPassword(String deploymentPassword) {
140 this.deploymentPassword = deploymentPassword;
141 }
142
143 public void doStart() throws Exception {
144 if (factory == null) {
145 factory = new DeploymentFactoryImpl();
146 }
147 File dir = serverInfo.resolve(path);
148 if (!dir.exists()) {
149 if (!dir.mkdirs()) {
150 throw new IllegalStateException("Hot deploy directory " + dir.getAbsolutePath() + " does not exist and cannot be created!");
151 }
152 } else if (!dir.canRead() || !dir.isDirectory()) {
153 throw new IllegalStateException("Hot deploy directory " + dir.getAbsolutePath() + " is not a readable directory!");
154 }
155 DeploymentManager mgr = null;
156 try {
157 mgr = getDeploymentManager();
158 Target[] targets = mgr.getTargets();
159 startupModules = mgr.getAvailableModules(null, targets);
160 mgr.release();
161 mgr = null;
162 monitor = new DirectoryMonitor(dir, this, pollIntervalMillis);
163 log.debug("Hot deploy scanner intialized; starting main loop.");
164 Thread t = new Thread(monitor, "Geronimo hot deploy scanner");
165 t.setDaemon(true);
166 t.start();
167 } finally {
168 if (mgr != null) mgr.release();
169 }
170 }
171
172 public void doStop() throws Exception {
173 monitor.close();
174 }
175
176 public void doFail() {
177 if (monitor != null) {
178 monitor.close();
179 }
180 }
181
182 public boolean isFileDeployed(File file, String configId) {
183 try {
184 DeployUtils.identifyTargetModuleIDs(startupModules, configId, true).toArray(new TargetModuleID[0]);
185 return true;
186 } catch (DeploymentException e) {
187 log.debug("Found new file in deploy directory on startup with ID " + configId);
188 return false;
189 }
190 }
191
192 public boolean isServerRunning() {
193 if (serverRunning) {
194 return true;
195 }
196
197
198 Set configLists = kernel.listGBeans(new AbstractNameQuery(PersistentConfigurationList.class.getName()));
199 for (Iterator i = configLists.iterator(); i.hasNext();) {
200 AbstractName configListName = (AbstractName) i.next();
201 try {
202 Boolean result = (Boolean) kernel.getAttribute(configListName, "kernelFullyStarted");
203 if (!result.booleanValue()) {
204 return false;
205 }
206 } catch (Exception e) {
207 log.warn("Hot deployer unable to determine whether kernel is started", e);
208 }
209 }
210 serverRunning = true;
211 return true;
212 }
213
214 public long getDeploymentTime(File file, String configId) {
215 try {
216 Artifact art = configManager.getArtifactResolver().resolveInClassLoader(Artifact.create(configId));
217 Configuration config = configManager.getConfiguration(art);
218 return config.getCreated();
219 } catch (MissingDependencyException e) {
220 log.error("Unknown configuration "+configId);
221 return -1;
222 }
223 }
224
225 public void started() {
226 startupModules = null;
227 log.debug("Initialization complete; directory scanner entering normal scan mode");
228 }
229
230 public boolean validateFile(File file, String configId) {
231
232 if (file.isDirectory() && (file.getName().equals("WEB-INF") || file.getName().equals("META-INF"))) {
233 log.error("(" + file.getName() + ") " + BAD_LAYOUT_MESSAGE);
234 return false;
235 }
236 return true;
237 }
238
239 public String fileAdded(File file) {
240 log.info("Deploying " + file.getName());
241 DeploymentManager mgr = null;
242 TargetModuleID[] modules = null;
243 boolean completed = false;
244 try {
245 mgr = getDeploymentManager();
246 Target[] targets = mgr.getTargets();
247 ProgressObject po;
248 if (DeployUtils.isJarFile(file) || file.isDirectory()) {
249 po = mgr.distribute(targets, file, null);
250 } else {
251 po = mgr.distribute(targets, null, file);
252 }
253 waitForProgress(po);
254 if (po.getDeploymentStatus().isCompleted()) {
255 modules = po.getResultTargetModuleIDs();
256 po = mgr.start(modules);
257 waitForProgress(po);
258 if (po.getDeploymentStatus().isCompleted()) {
259 completed = true;
260 } else {
261 log.warn("Unable to start some modules for " + file.getAbsolutePath());
262 }
263 modules = po.getResultTargetModuleIDs();
264 for (int i = 0; i < modules.length; i++) {
265 TargetModuleID result = modules[i];
266 log.info(DeployUtils.reformat("Deployed " + result.getModuleID() + (targets.length > 1 ? " to " + result.getTarget().getName() : "") + (result.getWebURL() == null ? "" : " @ " + result.getWebURL()), 4, 72));
267 if (result.getChildTargetModuleID() != null) {
268 for (int j = 0; j < result.getChildTargetModuleID().length; j++) {
269 TargetModuleID child = result.getChildTargetModuleID()[j];
270 log.info(DeployUtils.reformat(" `-> " + child.getModuleID() + (child.getWebURL() == null ? "" : " @ " + child.getWebURL()), 4, 72));
271 }
272 }
273 }
274 } else {
275 log.error("Unable to deploy: " + po.getDeploymentStatus().getMessage());
276 return null;
277 }
278 } catch (DeploymentManagerCreationException e) {
279 log.error("Unable to open deployer", e);
280 return null;
281 } catch (DeploymentException e) {
282 log.error("Unable to determine if file is a jar", e);
283 } finally {
284 if (mgr != null) mgr.release();
285 }
286 if (completed && modules != null) {
287 if (modules.length == 1) {
288 return modules[0].getModuleID();
289 } else {
290 return "";
291 }
292 } else if (modules != null) {
293 return "";
294 } else {
295 return null;
296 }
297 }
298
299 private DeploymentManager getDeploymentManager() throws DeploymentManagerCreationException {
300 DeploymentManager manager = factory.getDeploymentManager(deploymentURI, deploymentUser, deploymentPassword);
301 if (manager instanceof JMXDeploymentManager) {
302 ((JMXDeploymentManager) manager).setLogConfiguration(false, true);
303 }
304 return manager;
305 }
306
307 public boolean fileRemoved(File file, String configId) {
308 log.info("Undeploying " + file.getName());
309 DeploymentManager mgr = null;
310 try {
311 mgr = getDeploymentManager();
312 Target[] targets = mgr.getTargets();
313 TargetModuleID[] ids = mgr.getAvailableModules(null, targets);
314 ids = (TargetModuleID[]) DeployUtils.identifyTargetModuleIDs(ids, configId, true).toArray(new TargetModuleID[0]);
315 ProgressObject po = mgr.undeploy(ids);
316 waitForProgress(po);
317 if (po.getDeploymentStatus().isCompleted()) {
318 TargetModuleID[] modules = po.getResultTargetModuleIDs();
319 for (int i = 0; i < modules.length; i++) {
320 TargetModuleID result = modules[i];
321 log.info(DeployUtils.reformat("Undeployed " + result.getModuleID() + (targets.length > 1 ? " to " + result.getTarget().getName() : ""), 4, 72));
322 }
323 } else {
324 log.error("Unable to undeploy " + file.getAbsolutePath() + "(" + configId + ")" + po.getDeploymentStatus().getMessage());
325 return false;
326 }
327 } catch (DeploymentManagerCreationException e) {
328 log.error("Unable to open deployer", e);
329 return false;
330 } catch (Exception e) {
331 log.error("Unable to undeploy", e);
332 return false;
333 } finally {
334 if (mgr != null) mgr.release();
335 }
336 return true;
337 }
338
339 public void fileUpdated(File file, String configId) {
340 log.info("Redeploying " + file.getName());
341 DeploymentManager mgr = null;
342 try {
343 mgr = getDeploymentManager();
344 Target[] targets = mgr.getTargets();
345 TargetModuleID[] ids = mgr.getAvailableModules(null, targets);
346 ids = (TargetModuleID[]) DeployUtils.identifyTargetModuleIDs(ids, configId, true).toArray(new TargetModuleID[0]);
347 ProgressObject po;
348 if (DeployUtils.isJarFile(file) || file.isDirectory()) {
349 po = mgr.redeploy(ids, file, null);
350 } else {
351 po = mgr.redeploy(ids, null, file);
352 }
353 waitForProgress(po);
354 if (po.getDeploymentStatus().isCompleted()) {
355 TargetModuleID[] modules = po.getResultTargetModuleIDs();
356 for (int i = 0; i < modules.length; i++) {
357 TargetModuleID result = modules[i];
358 log.info(DeployUtils.reformat("Redeployed " + result.getModuleID() + (targets.length > 1 ? " to " + result.getTarget().getName() : "") + (result.getWebURL() == null ? "" : " @ " + result.getWebURL()), 4, 72));
359 if (result.getChildTargetModuleID() != null) {
360 for (int j = 0; j < result.getChildTargetModuleID().length; j++) {
361 TargetModuleID child = result.getChildTargetModuleID()[j];
362 log.info(DeployUtils.reformat(" `-> " + child.getModuleID() + (child.getWebURL() == null ? "" : " @ " + child.getWebURL()), 4, 72));
363 }
364 }
365 }
366 } else {
367 log.error("Unable to undeploy " + file.getAbsolutePath() + "(" + configId + ")" + po.getDeploymentStatus().getMessage());
368 }
369 } catch (DeploymentManagerCreationException e) {
370 log.error("Unable to open deployer", e);
371 } catch (Exception e) {
372 log.error("Unable to undeploy", e);
373 } finally {
374 if (mgr != null) mgr.release();
375 }
376 }
377
378 private void waitForProgress(ProgressObject po) {
379 while (po.getDeploymentStatus().isRunning()) {
380 try {
381 Thread.sleep(100);
382 } catch (InterruptedException e) {
383 log.error(e.getMessage(), e);
384 }
385 }
386 }
387
388 public static final GBeanInfo GBEAN_INFO;
389
390 static {
391 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(DirectoryHotDeployer.class);
392
393 infoFactory.addAttribute("path", String.class, true, true);
394 infoFactory.addAttribute("pollIntervalMillis", int.class, true, true);
395
396
397 infoFactory.addAttribute("deploymentURI", String.class, true, true);
398 infoFactory.addAttribute("deploymentUser", String.class, true, true);
399 infoFactory.addAttribute("deploymentPassword", String.class, true, true);
400
401 infoFactory.addReference("ConfigManager", ConfigurationManager.class, "ConfigurationManager");
402 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean");
403 infoFactory.addAttribute("kernel", Kernel.class, false, false);
404 infoFactory.addInterface(HotDeployer.class);
405
406 infoFactory.setConstructor(new String[]{"path", "pollIntervalMillis", "ServerInfo", "ConfigManager", "kernel"});
407
408 GBEAN_INFO = infoFactory.getBeanInfo();
409 }
410
411 public static GBeanInfo getGBeanInfo() {
412 return GBEAN_INFO;
413 }
414 }