001: /*
002: * CoadunationLib: The coaduntion implementation library.
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * XMLConfigurationException.java
020: *
021: * DeploymentLoader.java
022: *
023: * This class is reponsible for loading the Coaduncation jar files so that they
024: * can be deployed within Coadunation.
025: */
026:
027: // package
028: package com.rift.coad.lib.deployment;
029:
030: // class imports
031: import java.lang.ClassLoader;
032: import java.io.*;
033: import java.io.File;
034: import java.io.InputStream;
035: import java.io.OutputStream;
036: import java.io.FileInputStream;
037: import java.io.FileOutputStream;
038: import java.net.URL;
039: import java.net.URLClassLoader;
040: import java.util.HashMap;
041: import java.util.Iterator;
042: import java.util.Map;
043:
044: // logging import
045: import org.apache.log4j.Logger;
046:
047: // coadunation imports
048: import com.rift.coad.lib.common.ClassUtil;
049: import com.rift.coad.lib.common.FileUtil;
050: import com.rift.coad.lib.common.JarUtil;
051: import com.rift.coad.lib.common.RandomGuid;
052: import com.rift.coad.lib.common.ResourceReader;
053: import com.rift.coad.lib.configuration.Configuration;
054: import com.rift.coad.lib.configuration.ConfigurationFactory;
055: import com.rift.coad.lib.deployment.rmi.TieGenerator;
056: import com.rift.coad.lib.loader.MasterClassLoader;
057: import com.rift.coad.lib.thirdparty.ant.CopyFile;
058: import com.rift.coad.lib.thirdparty.ant.JAR;
059: import com.rift.coad.lib.thirdparty.ant.JavaC;
060: import com.rift.coad.lib.thirdparty.ant.RMIC;
061:
062: /**
063: *
064: * @author Brett Chaldecott
065: */
066: public class DeploymentLoader {
067:
068: /**
069: * This class is responsible for supplying a lookup mechanism for stub code
070: * files based on the class loader that loaded them.
071: */
072: public static class ClassLoaderLookup {
073: // the class singleton
074: private static ClassLoaderLookup singleton = null;
075:
076: // private member variables
077: private Map lookupMap = new HashMap();
078:
079: /**
080: * The constructor of the class loader lookup
081: */
082: private ClassLoaderLookup() {
083:
084: }
085:
086: /**
087: * This method returns a singleton reference and creates one if it does
088: * not exist.
089: *
090: * @return a reference to the class loader lookup singleton.
091: */
092: public static synchronized ClassLoaderLookup getInstance() {
093: if (singleton == null) {
094: singleton = new ClassLoaderLookup();
095: }
096: return singleton;
097: }
098:
099: /**
100: * This method adds a class loader to the list.
101: *
102: * @param loader The reference to the loader to add.
103: */
104: protected void addClassLoader(DeploymentLoader loader) {
105: lookupMap.put(loader.getClassLoader(), loader
106: .getClientStubCodeName());
107: }
108:
109: /**
110: * This method removes an entry from the class loader map.
111: *
112: * @param loader The loader to remove.
113: */
114: protected void removeClassLoader(DeploymentLoader loader) {
115: lookupMap.remove(loader.getClassLoader());
116: }
117:
118: /**
119: * This method returns the stub code name for the supplied loader.
120: *
121: * @return The name of stub code file for the supplied loader.
122: * @param loader The name of the loader.
123: */
124: public String getStubCodeForLoader(ClassLoader loader) {
125: return (String) lookupMap.get(loader);
126: }
127:
128: }
129:
130: // the class constants
131: public static final String META_FILE = "META-INF/coadunation.xml";
132: public static final String TEMP_DIRECTORY = "temp_dir";
133: private static final String PREFIX = "tmp";
134: private static final String SUFFIX = ".jar";
135: private static final String CLIENT_STUB = "Client_Stub";
136: private static final String SUB_SUFFIX = "_Stub" + SUFFIX;
137:
138: // the class log variable
139: protected Logger log = Logger.getLogger(DeploymentLoader.class
140: .getName());
141:
142: // The classes member variabable
143: private Configuration config = null;
144: private File file = null;
145: private File tmpDir = null;
146: private URLClassLoader classLoader = null;
147: private DeploymentInfo deploymentInfo = null;
148: private long lastModified = 0;
149: private boolean successful = false;
150: private String clientStubCodeName = null;
151:
152: /**
153: * Creates a new instance of DeploymentLoader
154: *
155: * @param file The file to load.
156: * @exception DeploymentException
157: */
158: public DeploymentLoader(File file) throws DeploymentException {
159: try {
160: // instanciate the URLClass loader
161: this .file = file;
162: lastModified = file.lastModified();
163:
164: // retrieve the configuration
165: config = ConfigurationFactory.getInstance().getConfig(
166: this .getClass());
167:
168: // create the temporary file
169: tmpDir = createTmpDir(file);
170:
171: // create stubs
172: createStubs(tmpDir);
173:
174: // list the contents of the directory
175: File[] jars = FileUtil.filter(tmpDir.listFiles(), ".jar");
176:
177: // url load list
178: URL[] urlList = new URL[jars.length + 1];
179: urlList[0] = tmpDir.toURL();
180: log.debug("Load url :" + tmpDir.toURL());
181: for (int index = 0; index < jars.length; index++) {
182: log
183: .debug("Load url :"
184: + jars[index].toURL().toString());
185: urlList[index + 1] = jars[index].toURL();
186: }
187:
188: // load the temporary file
189: classLoader = new URLClassLoader(urlList, MasterClassLoader
190: .getInstance().getLoader());
191:
192: // retrieve the coadunation.xml file from the meta base directory
193: String xmlSource = new ResourceReader(META_FILE,
194: classLoader).getDocument();
195:
196: // parse the coadunation file
197: CoadunationParser xmlParser = new CoadunationParser(
198: xmlSource);
199: deploymentInfo = xmlParser.getDeploymentInfo();
200:
201: // set the successful flag appropriatly
202: successful = true;
203:
204: // add a reference to the class loader lookup
205: ClassLoaderLookup.getInstance().addClassLoader(this );
206: } catch (Exception ex) {
207: log.error("Failed to load the file [" + file.toString()
208: + "] :" + ex.getMessage(), ex);
209: }
210: }
211:
212: /**
213: * The getter method for the file object.
214: *
215: * @return The file of the deployment loader.
216: */
217: public File getFile() {
218: return file;
219: }
220:
221: /**
222: * This method returns the temporary directory loaded by this object.
223: *
224: * @return The temporary file object loaded by this object.
225: */
226: public File getTmpDir() {
227: return tmpDir;
228: }
229:
230: /**
231: * This method will retrieve the stored last modified time.
232: *
233: * @return The long containing the last modified time of the file when it
234: * was loaded into memory.
235: */
236: public long getLastModified() {
237: return lastModified;
238: }
239:
240: /**
241: * Retrieve the deployment information for this bean.
242: *
243: * @return The reference to the deployment information for this jar.
244: */
245: public DeploymentInfo getDeploymentInfo() {
246: return deploymentInfo;
247: }
248:
249: /**
250: * This method will return a reference to the requested class.
251: *
252: * @return The reference to the loaded class.
253: * @param className The name of the class to load into memory.
254: * @exception DeploymentException
255: */
256: public Class getClass(String className) throws DeploymentException {
257: try {
258: return classLoader.loadClass(className);
259: } catch (Exception ex) {
260: throw new DeploymentException("Failed to load the class : "
261: + className, ex);
262: }
263: }
264:
265: /**
266: * The method to retrieve the class loader.
267: *
268: * @return The reference to the class loader.
269: */
270: public ClassLoader getClassLoader() {
271: return classLoader;
272: }
273:
274: /**
275: * This method returns true if this object has been sucessfully loaded.
276: *
277: * @return TRUE if successfully loaded FALSE if not.
278: */
279: public boolean getSuccessful() {
280: return successful;
281: }
282:
283: /**
284: * This method returns the name of the client stub code file.
285: *
286: * @return The string containing the name of the client stub code file.
287: */
288: public String getClientStubCodeName() {
289: return clientStubCodeName;
290: }
291:
292: /**
293: * This method returns the hash code for this object which is based on the
294: * file path.
295: *
296: * @return The hash code for this object based on the file path.
297: */
298: public int hashCode() {
299: return file.getPath().hashCode();
300: }
301:
302: /**
303: * This method determines if the deployment loader contains the same values.
304: *
305: * @return TRUE if they point at the same file, FALSE if not.
306: * @param obj The object to perform the comparison on.
307: */
308: public boolean equals(Object obj) {
309: if (!(obj instanceof DeploymentLoader)) {
310: return false;
311: }
312: DeploymentLoader loader = (DeploymentLoader) obj;
313: if (null == loader) {
314: return false;
315: }
316: if (loader.getFile().getPath().equals(file.getPath())) {
317: return true;
318: }
319: return false;
320: }
321:
322: /**
323: * This method will generate a temporary file using the source file.
324: *
325: * @return The path to the newly created temporary file.
326: */
327: private File createTmpDir(File source) throws DeploymentException {
328: try {
329: File tmpDir = new File(config.getString(TEMP_DIRECTORY),
330: RandomGuid.getInstance().getGuid());
331: if (tmpDir.mkdirs() == false) {
332: throw new DeploymentException(
333: "Failed to create the director ["
334: + tmpDir.getAbsolutePath() + "]");
335: }
336: JarUtil.extract(source, tmpDir);
337: return tmpDir;
338: } catch (DeploymentException ex) {
339: throw ex;
340: } catch (Exception ex) {
341: log.error("Failed to create the temporary directory : "
342: + ex.getMessage(), ex);
343: throw new DeploymentException(
344: "Failed to create the temporary directory : "
345: + ex.getMessage(), ex);
346: }
347: }
348:
349: /**
350: * This method creates the stub code for the deployment loader.
351: *
352: * @param tmpDir The directory in which all the class from which the stub
353: * code is required can be found
354: * @exception DeploymentException
355: */
356: private void createStubs(File tmpDir) throws DeploymentException {
357: try {
358: File stubDir = new File(tmpDir, RandomGuid.getInstance()
359: .getGuid());
360: if (stubDir.mkdirs() == false) {
361: throw new DeploymentException(
362: "Failed to create the stub " + "directory ["
363: + stubDir.getAbsolutePath() + "]");
364: }
365:
366: // jars
367: File[] jars = FileUtil.filter(tmpDir.listFiles(), ".jar");
368:
369: // url load list
370: File[] classPath = new File[jars.length + 2];
371: classPath[0] = tmpDir;
372: for (int index = 0; index < jars.length; index++) {
373: classPath[index + 1] = jars[index];
374: }
375: classPath[classPath.length - 1] = stubDir;
376:
377: createTies(tmpDir, tmpDir, stubDir);
378:
379: /*
380: This is not required as the RMI class loader will take car of it.
381: // list the contents of the directory
382: for (int index = 0; index < jars.length; index++) {
383: createTies(tmpDir,jars[index],stubDir);
384: }*/
385:
386: // compile the ties
387: JavaC javaC = new JavaC(classPath, stubDir, stubDir);
388: javaC.compileClasses();
389:
390: // create the RMI stubs
391: RMIC rmic = new RMIC(classPath, stubDir, "**/*.class",
392: stubDir);
393: rmic.parse();
394:
395: // create the jar
396: String clientFileName = file.getName();
397: clientFileName = clientFileName.substring(0, clientFileName
398: .indexOf('.'))
399: + SUB_SUFFIX;
400: File stubJar = new File(tmpDir.getPath() + File.separator
401: + clientFileName);
402: JAR jar = new JAR(stubDir, stubJar);
403: jar.archive();
404:
405: File clientStubJar = new File(config.getString(CLIENT_STUB)
406: + File.separator + clientFileName);
407: CopyFile copyFile = new CopyFile(stubJar, clientStubJar);
408: copyFile.copy();
409: clientStubCodeName = clientFileName;
410: } catch (Exception ex) {
411: log.error("Failed to create the stub : " + ex.getMessage(),
412: ex);
413: throw new DeploymentException(
414: "Failed to create the stub : " + ex.getMessage(),
415: ex);
416: }
417: }
418:
419: /**
420: * This method creates stub for the given path in a the supplied stub dir.
421: *
422: * @param tmpDir The temporary directory.
423: * @param path The path to use to create the entry from.
424: * @param stubDir The stub directory to use.
425: * @exception DeploymentException
426: */
427: private void createTies(File tmpDir, File path, File stubDir)
428: throws DeploymentException {
429: try {
430: // load the temporary file
431: URLClassLoader classLoader = new URLClassLoader(
432: new URL[] { path.toURL() }, MasterClassLoader
433: .getInstance().getLoader());
434:
435: // perform the check
436: if (classLoader.getResource(META_FILE) == null) {
437: // this is not a coadunation entry ignore
438: return;
439: }
440:
441: // retrieve the coadunation.xml file from the meta base directory
442: String xmlSource = new ResourceReader(META_FILE,
443: classLoader).getDocument();
444:
445: // parse the coadunation file
446: CoadunationParser xmlParser = new CoadunationParser(
447: xmlSource);
448: DeploymentInfo deploymentInfo = xmlParser
449: .getDeploymentInfo();
450:
451: // loop through the entry set
452: Map beans = deploymentInfo.getBeans();
453: Iterator iter = beans.keySet().iterator();
454: while (iter.hasNext()) {
455: BeanInfo beanInfo = (BeanInfo) beans.get(iter.next());
456: TieGenerator tieGenerator = new TieGenerator(tmpDir,
457: stubDir, beanInfo);
458: tieGenerator.generate();
459: }
460:
461: beans = deploymentInfo.getJmxBeans();
462: iter = beans.keySet().iterator();
463: while (iter.hasNext()) {
464: JMXBeanInfo beanInfo = (JMXBeanInfo) beans.get(iter
465: .next());
466: TieGenerator tieGenerator = new TieGenerator(tmpDir,
467: stubDir, beanInfo);
468: tieGenerator.generate();
469: }
470:
471: } catch (Exception ex) {
472: log.error(
473: "Failed to create the ties for [" + path.getPath()
474: + "] because : " + ex.getMessage(), ex);
475: throw new DeploymentException(
476: "Failed to create the ties for [" + path.getPath()
477: + "] because : " + ex.getMessage(), ex);
478: }
479: }
480:
481: }
|