001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2007 Bull S.A.S.
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: * Initial developer(s): Florent BENOIT & Ludovic BERT
022: * --------------------------------------------------------------------------
023: * $Id: EarClassPathManager.java 10037 2007-03-01 10:34:44Z benoitf $
024: * --------------------------------------------------------------------------
025: */package org.objectweb.jonas.ear.lib;
026:
027: import java.io.File;
028: import java.io.FileInputStream;
029: import java.io.IOException;
030: import java.net.MalformedURLException;
031: import java.net.URL;
032: import java.util.StringTokenizer;
033: import java.util.jar.Attributes;
034: import java.util.jar.JarFile;
035: import java.util.jar.Manifest;
036:
037: /**
038: * JOnAS Ear class path manager class. This class provides a way for managing
039: * the class-path dependency libraries.
040: * @author Florent Benoit
041: * @author Ludovic Bert
042: * @author Nicolas Van Caneghem <nicolas.vancaneghem@openpricer.com>Allow the
043: * deployment of an exploded ear
044: */
045: public class EarClassPathManager {
046:
047: /**
048: * Urls of the class path manager.
049: */
050: private URL[] urls = null;
051:
052: /**
053: * List of jars that must be parsed.
054: */
055: private JarList toParse = null;
056:
057: /**
058: * List of jars that have been parsed.
059: */
060: private JarList parsed = null;
061:
062: /**
063: * List of jars which are libraries.
064: */
065: private JarList libraries = null;
066:
067: /**
068: * List of the ejb jars.
069: */
070: private JarList ejbs = null;
071:
072: /**
073: * List of the war files.
074: */
075: private JarList wars = null;
076:
077: /**
078: * List of the client jars.
079: */
080: private JarList clients = null;
081:
082: /**
083: * Directory of the ear
084: */
085: private URL directory = null;
086:
087: /**
088: * Construct an instance of a EarClassPathManager
089: * @param ejbs JarList of ejb-jar
090: * @param wars JarList of war
091: * @param directory URL of the directory
092: * @throws EarClassPathManagerException if we can't create the manager
093: */
094: public EarClassPathManager(JarList ejbs, JarList wars, URL directory)
095: throws EarClassPathManagerException {
096:
097: if ((ejbs == null) || (wars == null) || (directory == null)) {
098: throw new EarClassPathManagerException(
099: "The constructor EarClassPathManager can't accept null parameters");
100: }
101:
102: //check protocol
103: if (!directory.getProtocol().equalsIgnoreCase("file")) {
104: throw new EarClassPathManagerException(
105: "Only the file:/ URL can be used");
106: }
107: this .ejbs = ejbs;
108: this .wars = wars;
109: this .clients = new JarList();
110: this .directory = directory;
111: }
112:
113: /**
114: * Construct an instance of a EarClassPathManager
115: * @param clients JarList of the clients
116: * @param directory URL of the directory
117: * @throws EarClassPathManagerException if we can't create the manager
118: */
119: public EarClassPathManager(JarList clients, URL directory)
120: throws EarClassPathManagerException {
121:
122: if ((clients == null) || (directory == null)) {
123: throw new EarClassPathManagerException(
124: "The constructor EarClassPathManager can't accept null parameters");
125: }
126:
127: //check protocol
128: if (!directory.getProtocol().equalsIgnoreCase("file")) {
129: throw new EarClassPathManagerException(
130: "Only the file:/ URL can be used");
131: }
132: this .ejbs = new JarList();
133: this .wars = new JarList();
134: this .clients = clients;
135: this .directory = directory;
136: }
137:
138: /**
139: * Get the class-path from the MANIFEST.MF file of the specified archive.
140: * @param url the URL of the JAR file which contains the MANIFEST file.
141: * @return the class-path from the MANIFEST.MF file of the specified
142: * archive.
143: * @throws IOException if creation of a file based upon the url failed
144: * @throws EarClassPathManagerException if it failed
145: */
146: private JarList getManifestClassPath(URL url)
147: throws EarClassPathManagerException, IOException {
148:
149: if (url == null) {
150: throw new EarClassPathManagerException(
151: "JarList.getManifestClassPath : The url parameter can't be null");
152: }
153:
154: Manifest manifest = null;
155:
156: if (new File(url.getFile()).isDirectory()) {
157: File manifestFile = new File(url.getFile() + File.separator
158: + JarFile.MANIFEST_NAME);
159: if (manifestFile.exists()) {
160: manifest = new Manifest(new FileInputStream(
161: manifestFile));
162: }
163:
164: } else {
165: //Construct a JarFile in order to access to the manifest
166: // IOException it if failed
167: JarFile jarFile = new JarFile(url.getFile());
168:
169: //get manifest from the jarFile
170: manifest = jarFile.getManifest();
171: }
172:
173: //classpath
174: String classPath = null;
175:
176: //Only if a manifest is found
177: if (manifest != null) {
178: //get attributes (classpath)
179: Attributes attributes = manifest.getMainAttributes();
180: classPath = attributes.getValue(Attributes.Name.CLASS_PATH);
181: }
182:
183: //New JarList
184: JarList jarList = null;
185:
186: //The jarList will be Empty if classpath is null or populate with
187: // classpath entries
188: if (classPath != null) {
189: jarList = new JarList(new StringTokenizer(classPath));
190: } else {
191: jarList = new JarList();
192: }
193:
194: //Return the list
195: return jarList;
196: }
197:
198: /**
199: * Get the list of the URLs.
200: * @return the list of the URLs.
201: * @throws EarClassPathManagerException if we can't resolve the path
202: */
203: public URL[] getResolvedClassPath()
204: throws EarClassPathManagerException {
205:
206: //If we don't have already compute
207: if (urls == null) {
208: resolveClassPath();
209: }
210:
211: //return the cache
212: return urls;
213: }
214:
215: /**
216: * Resolve the class-path dependencies of WAR and JAR files.
217: * @throws EarClassPathManagerException if it failed
218: */
219: private void resolveClassPath() throws EarClassPathManagerException {
220:
221: //Set the list to parsed
222: toParse = new JarList();
223:
224: //Set the list already parsed
225: parsed = new JarList();
226:
227: //Set the list of libraries
228: libraries = new JarList();
229:
230: //add the ejbs, wars and clients to this list
231: toParse.merge(ejbs);
232: toParse.merge(wars);
233: toParse.merge(clients);
234:
235: //dependencies list
236: JarList lstOfFilesDep = new JarList();
237:
238: //Url of the current filename
239: URL depUrl = null;
240:
241: //While there are elements to analyse
242: while (toParse.size() > 0) {
243:
244: //File to look for Manifest
245: String fileName = (String) toParse.firstElement();
246:
247: if (fileName.endsWith("/")) {
248: throw new EarClassPathManagerException(
249: "In j2ee application, Class-Path with directory is forbidden. '"
250: + fileName + "' is not authorized.");
251: }
252: try {
253: //Get dependency entries
254: depUrl = new URL(directory.toExternalForm() + "/"
255: + fileName);
256: lstOfFilesDep = getManifestClassPath(depUrl);
257: } catch (MalformedURLException mue) {
258: lstOfFilesDep.removeAllElements();
259: throw new EarClassPathManagerException(
260: "Error while trying to get the url for "
261: + directory.toExternalForm()
262: + File.separator + fileName + " : "
263: + mue.getMessage());
264: } catch (IOException ioe) {
265: lstOfFilesDep.removeAllElements();
266: throw new EarClassPathManagerException(
267: "Error while reading manifest file from the file "
268: + fileName + " : " + ioe.getMessage());
269: }
270:
271: String parentDir = new File(fileName).getParent();
272: //subDirectory (the parent dir or "")
273: String subDir = null;
274: if (parentDir != null) {
275: subDir = parentDir;
276: } else {
277: subDir = "";
278: }
279:
280: //Set the relative path of EAR / file
281: lstOfFilesDep.setRelativePath(subDir);
282:
283: //Merge the list
284: toParse.merge(lstOfFilesDep);
285:
286: //Add the parsed file
287: parsed.add(fileName);
288:
289: //Add to the libraries if it's not an EJB or a WEB application
290: if (isALibrary(fileName)) {
291: libraries.add(fileName);
292: }
293:
294: //Remove all the parsed files
295: toParse.remove(parsed);
296:
297: }
298:
299: //We've got the list of files, its the JarList : parsed
300: try {
301: urls = libraries.getURLs(directory.toExternalForm());
302: } catch (JarListException e) {
303: throw new EarClassPathManagerException(
304: "Error while geting the URLs of the jars files which must be loaded at the EAR level");
305:
306: }
307:
308: }
309:
310: /**
311: * Check if the file is a library , ie : - It's not an EJB Jar. - It's not a
312: * War.
313: * @param fileName name of the file to check
314: * @return true if it's not either an ejbjar either a war file. (a library).
315: */
316: private boolean isALibrary(String fileName) {
317: return (!ejbs.contains(fileName) && !wars.contains(fileName));
318: }
319:
320: }
|