001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.config;
017:
018: import static org.apache.openejb.util.JarExtractor.delete;
019:
020: import java.io.Closeable;
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileOutputStream;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.util.List;
028: import java.util.Properties;
029: import java.util.jar.JarFile;
030: import javax.naming.Context;
031: import javax.naming.InitialContext;
032:
033: import org.apache.commons.cli.CommandLine;
034: import org.apache.commons.cli.CommandLineParser;
035: import org.apache.commons.cli.HelpFormatter;
036: import org.apache.commons.cli.Option;
037: import org.apache.commons.cli.OptionBuilder;
038: import org.apache.commons.cli.Options;
039: import org.apache.commons.cli.ParseException;
040: import org.apache.commons.cli.PosixParser;
041: import org.apache.openejb.OpenEJBException;
042: import org.apache.openejb.UndeployException;
043: import org.apache.openejb.NoSuchApplicationException;
044: import org.apache.openejb.assembler.Deployer;
045: import org.apache.openejb.assembler.classic.AppInfo;
046: import org.apache.openejb.assembler.classic.ClientInfo;
047: import org.apache.openejb.assembler.classic.ConnectorInfo;
048: import org.apache.openejb.assembler.classic.EjbJarInfo;
049: import org.apache.openejb.assembler.classic.EnterpriseBeanInfo;
050: import org.apache.openejb.assembler.classic.InterceptorInfo;
051: import org.apache.openejb.assembler.classic.PersistenceUnitInfo;
052: import org.apache.openejb.assembler.classic.WebAppInfo;
053: import org.apache.openejb.cli.SystemExitException;
054: import org.apache.openejb.loader.SystemInstance;
055: import org.apache.openejb.util.Messages;
056: import org.apache.openejb.util.OpenEjbVersion;
057: import org.apache.openejb.util.JarExtractor;
058:
059: /**
060: * Deploy EJB beans
061: */
062: public class Deploy {
063:
064: private static Messages messages = new Messages(Deploy.class);
065:
066: private static final String defaultServerUrl = "ejbd://localhost:4201";
067: private static final int BUF_SIZE = 8192;
068:
069: public static void main(String[] args) throws SystemExitException {
070:
071: CommandLineParser parser = new PosixParser();
072:
073: // create the Options
074: Options options = new Options();
075: options.addOption(option("v", "version",
076: "cmd.deploy.opt.version"));
077: options.addOption(option("h", "help", "cmd.deploy.opt.help"));
078: options.addOption(option("o", "offline",
079: "cmd.deploy.opt.offline"));
080: options.addOption(option("s", "server-url", "url",
081: "cmd.deploy.opt.server"));
082: options.addOption(option("d", "debug", "cmd.deploy.opt.debug"));
083: options.addOption(option("q", "quiet", "cmd.deploy.opt.quiet"));
084: options.addOption(option("u", "undeploy",
085: "cmd.deploy.opt.undeploy"));
086: options.addOption(option(null, "dir", "cmd.deploy.opt.dir"));
087:
088: CommandLine line;
089: try {
090: // parse the command line arguments
091: line = parser.parse(options, args);
092: } catch (ParseException exp) {
093: help(options);
094: throw new SystemExitException(-1);
095: }
096:
097: if (line.hasOption("help")) {
098: help(options);
099: return;
100: } else if (line.hasOption("version")) {
101: OpenEjbVersion.get().print(System.out);
102: return;
103: }
104:
105: if (line.getArgList().size() == 0) {
106: System.out.println("Must specify an archive to deploy.");
107: help(options);
108: return;
109: }
110:
111: // make sure that the modules given on the command line are accessible
112: List<?> modules = line.getArgList();
113: for (Object module : modules) {
114: String path = (String) module;
115: File file = new File(path);
116: try {
117: checkSource(file);
118: } catch (DeploymentTerminatedException e) {
119: System.out.println(e.getMessage());
120: // TODO: What is it for?
121: throw new SystemExitException(-100);
122: }
123: }
124:
125: boolean offline = line.hasOption("offline");
126:
127: File apps;
128: try {
129: String dir = line.getOptionValue("dir", "apps");
130: apps = SystemInstance.get().getBase().getDirectory(dir);
131: } catch (IOException e) {
132: throw new SystemExitException(-1);
133: }
134:
135: if (!apps.exists()) {
136: System.out.println("Directory does not exist: "
137: + apps.getAbsolutePath());
138: }
139:
140: Deployer deployer = null;
141: if (!offline) {
142: Properties p = new Properties();
143: p
144: .put(Context.INITIAL_CONTEXT_FACTORY,
145: "org.apache.openejb.client.RemoteInitialContextFactory");
146:
147: String serverUrl = defaultServerUrl;
148: if (line.hasOption(serverUrl)) {
149: serverUrl = line.getOptionValue("serverUrl");
150: }
151: p.put(Context.PROVIDER_URL, serverUrl);
152:
153: try {
154: InitialContext ctx = new InitialContext(p);
155: deployer = (Deployer) ctx
156: .lookup("openejb/DeployerBusinessRemote");
157: } catch (javax.naming.ServiceUnavailableException e) {
158: System.out.println(e.getCause().getMessage());
159: System.out.println(messages
160: .format("cmd.deploy.serverOffline"));
161: throw new SystemExitException(-1);
162: } catch (javax.naming.NamingException e) {
163: System.out
164: .println("openejb/DeployerBusinessRemote does not exist in server '"
165: + serverUrl
166: + "', check the server logs to ensure it exists and has not been removed.");
167: throw new SystemExitException(-2);
168: }
169: }
170:
171: boolean undeploy = line.hasOption("undeploy");
172:
173: // We increment the exit code once for every failed deploy
174: int exitCode = 0;
175: for (Object obj : line.getArgList()) {
176: String path = (String) obj;
177:
178: File file = new File(path);
179:
180: File destFile = new File(apps, file.getName());
181:
182: try {
183: if (shouldUnpack(file)) {
184: File unpacked = unpackedLocation(file, apps);
185: if (undeploy) {
186: undeploy(offline, unpacked, path, deployer);
187: }
188: destFile = unpack(file, unpacked);
189: } else {
190: if (undeploy) {
191: undeploy(offline, destFile, path, deployer);
192: }
193: checkDest(destFile, file);
194: copyFile(file, destFile);
195: }
196:
197: if (offline) {
198: System.out.println(messages.format(
199: "cmd.deploy.offline", path, apps
200: .getAbsolutePath()));
201: continue;
202: }
203:
204: String location;
205: try {
206: location = destFile.getCanonicalPath();
207: } catch (IOException e) {
208: throw new OpenEJBException(messages.format(
209: "cmd.deploy.fileNotFound", path));
210: }
211: AppInfo appInfo = deployer.deploy(location);
212:
213: System.out
214: .println(messages.format(
215: "cmd.deploy.successful", path,
216: appInfo.jarPath));
217:
218: if (line.hasOption("quiet")) {
219: continue;
220: }
221:
222: print(appInfo);
223:
224: } catch (UndeployException e) {
225: System.out.println(messages.format(
226: "cmd.undeploy.failed", path));
227: e.printStackTrace(System.out);
228: exitCode++;
229: } catch (DeploymentTerminatedException e) {
230: System.out.println(e.getMessage());
231: exitCode++;
232: } catch (ValidationFailedException e) {
233: System.out.println(messages.format(
234: "cmd.deploy.validationFailed", path));
235: int level = 2;
236: if (line.hasOption("debug")) {
237: level = 3;
238: }
239: AppValidator appValidator = new AppValidator(level,
240: false, true, false);
241: appValidator.printResults(e);
242: exitCode++;
243: if (!delete(destFile)) {
244: System.out.println(messages.format(
245: "cmd.deploy.cantDelete.deploy", destFile
246: .getAbsolutePath()));
247: }
248: } catch (OpenEJBException e) {
249: System.out.println(messages.format("cmd.deploy.failed",
250: path));
251: e.printStackTrace(System.out);
252: exitCode++;
253: if (!delete(destFile)) {
254: System.out.println(messages.format(
255: "cmd.deploy.cantDelete.deploy", destFile
256: .getAbsolutePath()));
257: }
258: }
259: }
260:
261: if (exitCode != 0) {
262: throw new SystemExitException(exitCode);
263: }
264: }
265:
266: private static void undeploy(boolean offline, File dest,
267: String path, Deployer deployer) throws UndeployException,
268: DeploymentTerminatedException {
269: if (offline) {
270: if (dest.exists()) {
271: if (!delete(dest)) {
272: throw new DeploymentTerminatedException(messages
273: .format("cmd.deploy.cantDelete.undeploy",
274: dest.getAbsolutePath()));
275: }
276: }
277: } else {
278: try {
279: Undeploy.undeploy(path, dest, deployer);
280: } catch (NoSuchApplicationException nothingToUndeploy) {
281: }
282: }
283: }
284:
285: private static void print(AppInfo appInfo) {
286: System.out.println("App(id=" + appInfo.jarPath + ")");
287:
288: for (EjbJarInfo info : appInfo.ejbJars) {
289: System.out.println(" EjbJar(id=" + info.moduleId
290: + ", path=" + info.jarPath + ")");
291: for (EnterpriseBeanInfo beanInfo : info.enterpriseBeans) {
292: System.out.println(" Ejb(ejb-name="
293: + beanInfo.ejbName + ", id="
294: + beanInfo.ejbDeploymentId + ")");
295: for (String name : beanInfo.jndiNames) {
296: System.out.println(" Jndi(name=" + name
297: + ")");
298: }
299: System.out.println("");
300: }
301: for (InterceptorInfo interceptorInfo : info.interceptors) {
302: System.out.println(" Interceptor(class="
303: + interceptorInfo.clazz + ")");
304: }
305: System.out.println("");
306: }
307: for (ClientInfo clientInfo : appInfo.clients) {
308: System.out.println(" Client(main-class="
309: + clientInfo.mainClass + ", id="
310: + clientInfo.moduleId + ", path="
311: + clientInfo.codebase + ")");
312: System.out.println("");
313: }
314: for (ConnectorInfo connectorInfo : appInfo.connectors) {
315: System.out.println(" Connector(id="
316: + connectorInfo.moduleId + ", path="
317: + connectorInfo.codebase + ")");
318: System.out.println("");
319: }
320: for (WebAppInfo webAppInfo : appInfo.webApps) {
321: System.out.println(" WebApp(context-root="
322: + webAppInfo.contextRoot + ", id="
323: + webAppInfo.moduleId + ", path="
324: + webAppInfo.codebase + ")");
325: System.out.println("");
326: }
327: for (PersistenceUnitInfo persistenceUnitInfo : appInfo.persistenceUnits) {
328: System.out.println(" PersistenceUnit(name="
329: + persistenceUnitInfo.name + ", provider="
330: + persistenceUnitInfo.provider + ")");
331: System.out.println("");
332: }
333: }
334:
335: private static void checkSource(File file)
336: throws DeploymentTerminatedException {
337: if (!file.exists()) {
338: throw new DeploymentTerminatedException(messages.format(
339: "cmd.deploy.fileNotFound", file.getAbsolutePath()));
340: }
341: }
342:
343: private static void checkDest(File destFile, File file)
344: throws DeploymentTerminatedException {
345: if (destFile.exists()) {
346: throw new DeploymentTerminatedException(messages.format(
347: "cmd.deploy.destExists", file.getAbsolutePath(),
348: destFile.getAbsolutePath()));
349: }
350: }
351:
352: private static void copyFile(File file, File destFile)
353: throws DeploymentTerminatedException {
354: InputStream in = null;
355: OutputStream out = null;
356: try {
357: in = new FileInputStream(file);
358: out = new FileOutputStream(destFile);
359:
360: byte[] buffer = new byte[BUF_SIZE];
361: int count = 0;
362: do {
363: out.write(buffer, 0, count);
364: count = in.read(buffer, 0, buffer.length);
365: } while (count != -1);
366: } catch (Exception e) {
367: throw new DeploymentTerminatedException(messages.format(
368: "cmd.deploy.cantCopy", file.getAbsolutePath(),
369: destFile.getAbsolutePath()));
370: } finally {
371: close(in);
372: close(out);
373: }
374: }
375:
376: private static boolean shouldUnpack(File file) {
377: String name = file.getName();
378: if (name.endsWith(".ear") || name.endsWith(".rar")
379: || name.endsWith(".rar")) {
380: return true;
381: }
382:
383: JarFile jarFile = null;
384: try {
385: jarFile = new JarFile(file);
386:
387: if (jarFile.getEntry("META-INF/application.xml") != null) {
388: return true;
389: }
390: if (jarFile.getEntry("META-INF/ra.xml") != null) {
391: return true;
392: }
393: if (jarFile.getEntry("WEB-INF/web.xml") != null) {
394: return true;
395: }
396: } catch (IOException e) {
397: } finally {
398: if (jarFile != null) {
399: try {
400: jarFile.close();
401: } catch (IOException ignored) {
402: }
403: }
404: }
405:
406: return false;
407: }
408:
409: private static File unpack(File jarFile, File destinationDir)
410: throws OpenEJBException, DeploymentTerminatedException {
411:
412: try {
413: checkDest(destinationDir, jarFile);
414: JarExtractor.extract(jarFile, destinationDir);
415: return destinationDir;
416: } catch (IOException e) {
417: throw new OpenEJBException("Unable to extract jar. "
418: + e.getMessage(), e);
419: }
420: }
421:
422: private static File unpackedLocation(File jarFile, File destDir) {
423: if (jarFile.isDirectory()) {
424: return jarFile;
425: }
426:
427: String name = jarFile.getName();
428: if (name.endsWith(".jar") || name.endsWith(".ear")
429: || name.endsWith(".zip") || name.endsWith(".war")
430: || name.endsWith(".rar")) {
431: name = name.replaceFirst("....$", "");
432: } else {
433: name += ".unpacked";
434: }
435:
436: File destinationDir = new File(destDir, name);
437: return destinationDir;
438: }
439:
440: private static void close(Closeable in) {
441: if (in != null) {
442: try {
443: in.close();
444: } catch (IOException e) {
445: }
446: }
447: }
448:
449: private static void help(Options options) {
450: HelpFormatter formatter = new HelpFormatter();
451: formatter.printHelp("deploy [options] <file> [<file>...]", "\n"
452: + i18n("cmd.deploy.description"), options, "\n");
453: }
454:
455: private static Option option(String shortOpt, String longOpt,
456: String description) {
457: return OptionBuilder.withLongOpt(longOpt).withDescription(
458: i18n(description)).create(shortOpt);
459: }
460:
461: private static Option option(String shortOpt, String longOpt,
462: String argName, String description) {
463: return OptionBuilder.withLongOpt(longOpt).withArgName(argName)
464: .hasArg().withDescription(i18n(description)).create(
465: shortOpt);
466: }
467:
468: private static String i18n(String key) {
469: return messages.format(key);
470: }
471:
472: public static class DeploymentTerminatedException extends Exception {
473: public DeploymentTerminatedException(String message) {
474: super (message);
475: }
476:
477: public DeploymentTerminatedException(String message,
478: Throwable cause) {
479: super(message, cause);
480: }
481: }
482: }
|