001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: WsGenChecker.java 7616 2005-10-26 11:15:14Z sauthieg $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_lib.files;
025:
026: import java.io.File;
027: import java.io.FileInputStream;
028: import java.io.FileNotFoundException;
029: import java.io.IOException;
030: import java.util.jar.Attributes;
031: import java.util.jar.JarFile;
032: import java.util.jar.Manifest;
033:
034: import javax.management.InstanceNotFoundException;
035: import javax.management.MBeanException;
036: import javax.management.MBeanServer;
037: import javax.management.ObjectName;
038: import javax.management.ReflectionException;
039:
040: import org.objectweb.jonas_lib.version.Version;
041:
042: import org.objectweb.jonas.common.JProp;
043: import org.objectweb.jonas.common.Log;
044: import org.objectweb.jonas.jmx.JonasObjectName;
045:
046: import org.objectweb.util.monolog.api.BasicLevel;
047: import org.objectweb.util.monolog.api.Logger;
048:
049: /**
050: * Check if a file has been WsGen-ized.
051: * If not, apply WsGen on it and return the new archive name.
052: *
053: * @author Guillaume Sauthier
054: */
055: public class WsGenChecker {
056:
057: /**
058: * Property name for WsGen engagement or not
059: */
060: private static final String AUTO_WSGEN_ENGAGED = "jonas.service.ws.auto-wsgen.engaged";
061:
062: /**
063: * logger
064: */
065: private static Logger logger = Log.getLogger(Log.JONAS_WS_PREFIX);
066:
067: /**
068: * name of the file to be checked
069: */
070: private String filename = null;
071:
072: /**
073: * MbeanServer used to execute MBean's operations
074: */
075: private MBeanServer mbeanServer;
076:
077: /**
078: * J2EEServer ObjectName
079: */
080: private ObjectName j2eeServerON;
081:
082: /**
083: * 'true' if the Auto WsGen mode is engaged
084: */
085: private boolean engaged = true;
086:
087: /**
088: * Creates a new Chceker for WsGen
089: * @param ms MBeanServer to use
090: * @param filename file to be checked
091: * @param j2eeServerON J2EEServer ObjectName
092: */
093: public WsGenChecker(MBeanServer ms, String filename,
094: ObjectName j2eeServerON) {
095: this .mbeanServer = ms;
096: this .filename = filename;
097: this .j2eeServerON = j2eeServerON;
098: try {
099: // is 'ws' service deployed ?
100: String[] services = JProp.getInstance().getValueAsArray(
101: "jonas.services");
102: boolean wsEnabled = false;
103: for (int i = 0; i < services.length; i++) {
104: if ("ws".equals(services[i])) {
105: wsEnabled = true;
106: }
107: }
108:
109: // engage only if ws service is deployed
110: this .engaged = wsEnabled
111: && JProp.getInstance().getValue(AUTO_WSGEN_ENGAGED,
112: "true").trim().equalsIgnoreCase("true");
113:
114: } catch (Exception e) {
115: this .engaged = true;
116: }
117: }
118:
119: /**
120: * Check that WsGen have been applied on the given file
121: * If it was not done, it run WsGen against the file.
122: * @return Returns the path to the modified archive
123: * @throws CheckerException FIXME
124: */
125: public String checkWsGen() throws CheckerException {
126: if (!engaged) {
127: // user don't want Automatic WsGen
128: // just Quit
129: return filename;
130: }
131:
132: String jonasVersionWsGen = getAttributeInManifest(filename,
133: "WsGen-JOnAS-Version");
134:
135: if ((jonasVersionWsGen == null)
136: || (!Version.NUMBER.equals(jonasVersionWsGen))) {
137: // The archive need WsGen
138:
139: // Print a little explaination before calling WsGen
140: if (jonasVersionWsGen == null) {
141: logger
142: .log(
143: BasicLevel.DEBUG,
144: "JOnAS version not found into '"
145: + filename
146: + "' manifest file. Trying to generate WebServices classes...");
147: } else if (!Version.NUMBER.equals(jonasVersionWsGen)) {
148: logger
149: .log(
150: BasicLevel.DEBUG,
151: "Different JOnAS version found for '"
152: + filename
153: + "' (archive version : '"
154: + jonasVersionWsGen
155: + "' / JOnAS version : '"
156: + Version.NUMBER
157: + "'). Trying to re-generate WebServices classes...");
158: }
159:
160: File module = new File(filename);
161: Boolean unpacked = Boolean.FALSE;
162: if (module.isDirectory()) {
163: unpacked = Boolean.TRUE;
164: }
165: Object[] param = { filename, unpacked };
166: String[] signature = { "java.lang.String",
167: "java.lang.Boolean" };
168:
169: // Invoke wsgenLocalFile
170: String path = null;
171: try {
172: path = (String) mbeanServer.invoke(j2eeServerON,
173: "wsgenLocalFile", param, signature);
174: } catch (InstanceNotFoundException e) {
175: // no J2EEserver MBean !?
176: // Should not occurs
177: logger.log(BasicLevel.WARN,
178: "Cannot find J2EEServer MBean", e);
179: } catch (MBeanException e) {
180: // wsgenLocalFile thrown an Exception
181: logger.log(BasicLevel.WARN,
182: "WsGen throw an Exception.", e
183: .getTargetException());
184: } catch (ReflectionException e) {
185: // cannot invoke mbean operation
186: logger.log(BasicLevel.WARN,
187: "Cannot invoke operation on J2EEServer MBean",
188: e);
189: }
190:
191: if (path != null) {
192: // archive has been changed
193: // if it was an EjbJar before, and an ear was produced
194: if ((path.endsWith(".ear"))
195: && (filename.endsWith(".jar"))) {
196: // WsGen produced an Ear from the EjbJar
197: logger.log(BasicLevel.DEBUG,
198: "WsGen produced an EAR '" + path + "'");
199:
200: // Copy it from the work directory to apps directory
201: File source = new File(path);
202: File destination = new File(JProp.getJonasBase(),
203: "apps" + File.separator + source.getName());
204: try {
205: FileUtils.copyFile(source, destination);
206: } catch (FileUtilsException e) {
207: // can't copy the file
208: throw new CheckerException(
209: "Cannot copy the file from '" + path
210: + "' to '" + filename + "'", e);
211: }
212: logger.log(BasicLevel.DEBUG, "Deploying '" + path
213: + "' (copied from '" + source.getPath()
214: + "') ...");
215:
216: // invoke method on the MBeanServer
217: try {
218: ObjectName earServiceON = JonasObjectName
219: .earService();
220: // deploy the resulting, copied ear
221: param[0] = path;
222: mbeanServer.invoke(earServiceON,
223: "deployEarMBean", param, signature);
224: } catch (InstanceNotFoundException e) {
225: // no ear service in this instance
226: throw new CheckerException(
227: "Ear Service not available in this JOnAS instance. Cannot deploy the produced Application : "
228: + path, e);
229: } catch (MBeanException e) {
230: // deployEarMBean thrown an Exception
231: throw new CheckerException(
232: "Cannot deploy the produced Application : "
233: + path, e.getTargetException());
234: } catch (ReflectionException e) {
235: // cannot invoke mbean operation
236: throw new CheckerException(
237: "Cannot invoke deploy operation on Ear Service MBean for application : "
238: + path, e);
239: }
240: return path;
241: } else {
242: // WsGen did not change the archive type
243: // but produced another (updated) jar
244: logger.log(BasicLevel.DEBUG,
245: "Archive updated, continuing deployment : "
246: + path);
247: // replace old file with the new one...
248: try {
249: // clean existing lock on files (close IO Streams is not sufficent ...)
250: // and wait for a given amount of time :(
251: // Even the GC is not sufficent :(
252: // It is required, but it seems that windows need some time
253: // to remove file locks.
254: System.gc();
255: // TODO Not very nice ! If there is other workaround...
256: Thread.sleep(Long.getLong("jonas.wsgen.sleep",
257: 100).longValue());
258:
259: // delete old file
260: if (!FileUtils.delete(filename)) {
261: throw new CheckerException(
262: "Cannot delete old application : "
263: + filename);
264: }
265: if (unpacked.booleanValue()) {
266: FileUtils.copyDirectory(new File(path),
267: module);
268: } else {
269: FileUtils.copyFile(path, filename);
270: }
271: // remove temp file
272: FileUtils.delete(path);
273: } catch (FileUtilsException e) {
274: // can't copy the file
275: throw new CheckerException(
276: "Cannot copy the ear from '" + path
277: + "' to '" + filename + "'", e);
278: } catch (InterruptedException e) {
279: // Required by the Thread.sleep() :(
280: throw new CheckerException(
281: "Cannot sleep for the given time period",
282: e);
283: }
284: return filename;
285: }
286: } else {
287: // no changes, just continue the normal deployment process
288: logger.log(BasicLevel.DEBUG,
289: "Archive has not been changed, continuing deployment : "
290: + filename);
291: return filename;
292: }
293: }
294:
295: // the archive don't need WsGen
296: logger.log(BasicLevel.DEBUG,
297: "Archive up to date, continuing deployment : "
298: + filename);
299: return filename;
300: }
301:
302: /**
303: * get the attibut value in manifest file
304: * @param name : the file containing a manifest
305: * @param attributeName : the attribut name
306: * @return the value corresponding to the attributName if it's exist null otherwise
307: */
308: private static String getAttributeInManifest(String name,
309: String attributeName) {
310:
311: File file = new File(name);
312: if (file.isFile()) {
313: // file mode
314: JarFile jar = null;
315: try {
316: // open and read the jar Manifest values
317: jar = new JarFile(file);
318: Manifest man = jar.getManifest();
319: if (man == null) {
320: // no manifest, just return null
321: // avoid a bad looking NPE ;)
322: return null;
323: }
324: Attributes atts = man.getMainAttributes();
325: return atts.getValue(attributeName);
326: } catch (IOException ioe) {
327: // if a problem occurs, return null
328: return null;
329: } finally {
330: // close the jar
331: if (jar != null) {
332: try {
333: jar.close();
334: } catch (IOException e) {
335: // nothing to do
336: logger.log(BasicLevel.DEBUG,
337: "Cannot close archive : " + name);
338: }
339: }
340: }
341: } else {
342: // directory mode
343: try {
344: Manifest mf = new Manifest(new FileInputStream(
345: new File(file, "META-INF" + File.separator
346: + "MANIFEST.MF")));
347: Attributes atts = mf.getMainAttributes();
348: return atts.getValue(attributeName);
349: } catch (FileNotFoundException e) {
350: // no Manifest
351: // act as the manifest attribute was not found
352: return null;
353: } catch (IOException e) {
354: // act as the manifest attribute was not found
355: return null;
356: }
357: }
358: }
359: }
|