001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.loader;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.config.types.FileSetType;
033: import com.caucho.config.types.PathPatternType;
034: import com.caucho.make.DependencyContainer;
035: import com.caucho.server.util.CauchoSystem;
036: import com.caucho.util.CharBuffer;
037: import com.caucho.vfs.*;
038:
039: import javax.annotation.PostConstruct;
040: import java.net.URL;
041: import java.util.*;
042: import java.util.logging.Level;
043: import java.util.logging.Logger;
044: import java.io.*;
045: import java.util.zip.*;
046:
047: /**
048: * Class loader which checks for changes in class files and automatically
049: * picks up new jars.
050: */
051: abstract public class JarListLoader extends Loader implements
052: Dependency {
053: private static final Logger log = Logger
054: .getLogger(JarListLoader.class.getName());
055:
056: // list of the jars in the directory
057: protected ArrayList<JarEntry> _jarList;
058:
059: // list of dependencies
060: private DependencyContainer _dependencyList = new DependencyContainer();
061:
062: // Entry map
063: private HashMap<String, ArrayList<JarEntry>> _pathMap;
064:
065: /**
066: * Creates a new jar list loader.
067: */
068: public JarListLoader() {
069: _jarList = new ArrayList<JarEntry>();
070: _dependencyList = new DependencyContainer();
071: }
072:
073: /**
074: * Initialize
075: */
076: protected void init() {
077: }
078:
079: /**
080: * Sets the owning class loader.
081: */
082: public void setLoader(DynamicClassLoader loader) {
083: super .setLoader(loader);
084:
085: for (int i = 0; i < _jarList.size(); i++)
086: loader.addURL(_jarList.get(i).getJarPath());
087: }
088:
089: /**
090: * True if any of the loaded classes have been modified. If true, the
091: * caller should drop the classpath and create a new one.
092: */
093: public boolean isModified() {
094: return _dependencyList.isModified();
095: }
096:
097: /**
098: * True if any of the loaded classes have been modified. If true, the
099: * caller should drop the classpath and create a new one.
100: */
101: public boolean logModified(Logger log) {
102: return _dependencyList.logModified(log);
103: }
104:
105: /**
106: * Validates the loader.
107: */
108: public void validate() throws ConfigException {
109: for (int i = 0; i < _jarList.size(); i++) {
110: _jarList.get(i).validate();
111: }
112: }
113:
114: protected void addJar(Path jar) {
115: JarPath jarPath = JarPath.create(jar);
116: JarEntry jarEntry = new JarEntry(jarPath);
117: _jarList.add(jarEntry);
118:
119: _dependencyList.add(new Depend(jarPath));
120:
121: if (getLoader() != null)
122: getLoader().addURL(jarPath);
123:
124: if (_pathMap == null && DynamicClassLoader.isJarCacheEnabled())
125: _pathMap = new HashMap<String, ArrayList<JarEntry>>();
126:
127: if (_pathMap != null) {
128: ZipScanner scan = null;
129:
130: try {
131: HashMap<String, ArrayList<JarEntry>> pathMap = _pathMap;
132:
133: boolean isScan = true;
134: boolean isValidScan = false;
135:
136: try {
137: if (isScan && jar.canRead())
138: scan = new ZipScanner(jar);
139:
140: if (scan != null && scan.open()) {
141: while (scan.next()) {
142: String name = scan.getName();
143:
144: ArrayList<JarEntry> entryList = pathMap
145: .get(name);
146: if (entryList == null) {
147: entryList = new ArrayList<JarEntry>();
148:
149: // server/249b
150: /*
151: if (name.endsWith("/"))
152: name = name.substring(0, name.length() - 1);
153: */
154:
155: pathMap.put(name, entryList);
156: }
157:
158: entryList.add(jarEntry);
159: }
160:
161: isValidScan = true;
162: }
163: } catch (Exception e) {
164: log.log(Level.FINER, e.toString(), e);
165:
166: isScan = false;
167: }
168:
169: if (!isValidScan && jar.canRead()) {
170: ZipFile file = new ZipFile(jar.getNativePath());
171:
172: Enumeration<? extends ZipEntry> e = file.entries();
173: while (e.hasMoreElements()) {
174: ZipEntry entry = e.nextElement();
175: String name = entry.getName();
176:
177: ArrayList<JarEntry> entryList = pathMap
178: .get(name);
179: if (entryList == null) {
180: entryList = new ArrayList<JarEntry>();
181:
182: // server/249b
183: /*
184: if (name.endsWith("/"))
185: name = name.substring(0, name.length() - 1);
186: */
187:
188: pathMap.put(name, entryList);
189: }
190:
191: entryList.add(jarEntry);
192: }
193:
194: file.close();
195: }
196: } catch (IOException e) {
197: if (jar.canRead())
198: log.log(Level.WARNING, e.toString(), e);
199: else
200: log.log(Level.FINER, e.toString(), e);
201: } finally {
202: if (scan != null)
203: scan.close();
204: }
205: }
206: }
207:
208: /**
209: * Fill data for the class path. fillClassPath() will add all
210: * .jar and .zip files in the directory list.
211: */
212: @Override
213: protected void buildClassPath(ArrayList<String> pathList) {
214: for (int i = 0; i < _jarList.size(); i++) {
215: JarEntry jarEntry = _jarList.get(i);
216: JarPath jar = jarEntry.getJarPath();
217:
218: String path = jar.getContainer().getNativePath();
219:
220: if (!pathList.contains(path))
221: pathList.add(path);
222: }
223: }
224:
225: /**
226: * Returns the class entry.
227: *
228: * @param name name of the class
229: */
230: protected ClassEntry getClassEntry(String name, String pathName)
231: throws ClassNotFoundException {
232: if (_pathMap != null) {
233: ArrayList<JarEntry> jarEntryList = _pathMap.get(pathName);
234:
235: if (jarEntryList != null) {
236: JarEntry jarEntry = jarEntryList.get(0);
237:
238: Path filePath = jarEntry.getJarPath().lookup(pathName);
239:
240: return createEntry(name, pathName, jarEntry, filePath);
241: }
242: } else {
243: // Find the path corresponding to the class
244: for (int i = 0; i < _jarList.size(); i++) {
245: JarEntry jarEntry = _jarList.get(i);
246: Path path = jarEntry.getJarPath();
247:
248: Path filePath = path.lookup(pathName);
249:
250: if (filePath.canRead() && filePath.getLength() > 0) {
251: return createEntry(name, pathName, jarEntry,
252: filePath);
253: }
254: }
255: }
256:
257: return null;
258: }
259:
260: private ClassEntry createEntry(String name, String pathName,
261: JarEntry jarEntry, Path filePath) {
262: String pkg = "";
263: int p = pathName.lastIndexOf('/');
264: if (p > 0)
265: pkg = pathName.substring(0, p + 1);
266:
267: ClassEntry entry = new ClassEntry(getLoader(), name, filePath,
268: filePath, jarEntry.getCodeSource(pathName));
269:
270: ClassPackage classPackage = jarEntry.getPackage(pkg);
271:
272: entry.setClassPackage(classPackage);
273:
274: return entry;
275: }
276:
277: /**
278: * Adds resources to the enumeration.
279: */
280: public void getResources(Vector<URL> vector, String name) {
281: if (_pathMap != null) {
282: ArrayList<JarEntry> jarEntryList = _pathMap.get(name);
283:
284: for (int i = 0; jarEntryList != null
285: && i < jarEntryList.size(); i++) {
286: JarEntry jarEntry = jarEntryList.get(i);
287: Path path = jarEntry.getJarPath();
288:
289: path = path.lookup(name);
290:
291: try {
292: URL url = new URL(path.getURL());
293:
294: if (!vector.contains(url))
295: vector.add(url);
296: } catch (Exception e) {
297: log.log(Level.WARNING, e.toString(), e);
298: }
299: }
300: } else {
301: for (int i = 0; i < _jarList.size(); i++) {
302: JarEntry jarEntry = _jarList.get(i);
303: Path path = jarEntry.getJarPath();
304:
305: path = path.lookup(name);
306:
307: if (path.exists()) {
308: try {
309: URL url = new URL(path.getURL());
310:
311: if (!vector.contains(url))
312: vector.add(url);
313: } catch (Exception e) {
314: log.log(Level.WARNING, e.toString(), e);
315: }
316: }
317: }
318: }
319: }
320:
321: /**
322: * Find a given path somewhere in the classpath
323: *
324: * @param pathName the relative resourceName
325: *
326: * @return the matching path or null
327: */
328: public Path getPath(String pathName) {
329: if (_pathMap != null) {
330: ArrayList<JarEntry> jarEntryList = _pathMap.get(pathName);
331:
332: if (jarEntryList != null) {
333: return jarEntryList.get(0).getJarPath()
334: .lookup(pathName);
335: }
336: } else {
337: for (int i = 0; i < _jarList.size(); i++) {
338: JarEntry jarEntry = _jarList.get(i);
339: Path path = jarEntry.getJarPath();
340:
341: Path filePath = path.lookup(pathName);
342:
343: if (filePath.exists())
344: return filePath;
345: }
346: }
347:
348: return null;
349: }
350:
351: /**
352: * Closes the jars.
353: */
354: protected void clearJars() {
355: synchronized (this ) {
356: ArrayList<JarEntry> jars = new ArrayList<JarEntry>(_jarList);
357: _jarList.clear();
358:
359: if (_pathMap != null)
360: _pathMap.clear();
361:
362: for (int i = 0; i < jars.size(); i++) {
363: JarEntry jarEntry = jars.get(i);
364:
365: JarPath jarPath = jarEntry.getJarPath();
366:
367: jarPath.closeJar();
368: }
369: }
370: }
371: }
|