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.util.L10N;
033: import com.caucho.vfs.JarPath;
034: import com.caucho.vfs.Path;
035:
036: import java.io.IOException;
037: import java.net.URL;
038: import java.security.CodeSource;
039: import java.security.cert.Certificate;
040: import java.util.ArrayList;
041: import java.util.Iterator;
042: import java.util.Map;
043: import java.util.jar.Attributes;
044: import java.util.jar.Manifest;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047: import java.util.regex.Pattern;
048:
049: /**
050: * JarEntry.
051: */
052: class JarEntry {
053: private static final L10N L = new L10N(JarEntry.class);
054: private static final Logger log = Logger.getLogger(JarEntry.class
055: .getName());
056:
057: private Manifest _manifest;
058: private JarPath _jarPath;
059: private ArrayList<ClassPackage> _packages = new ArrayList<ClassPackage>();
060:
061: private CodeSource _codeSource;
062:
063: /**
064: * Creates a JarEntry.
065: */
066: JarEntry(JarPath jarPath) {
067: _jarPath = jarPath;
068:
069: try {
070: _codeSource = new CodeSource(new URL(jarPath.getURL()),
071: (Certificate[]) jarPath.getCertificates());
072: } catch (Exception e) {
073: log.log(Level.WARNING, e.toString(), e);
074: }
075:
076: readManifest();
077: }
078:
079: /**
080: * Reads the jar's manifest.
081: */
082: private void readManifest() {
083: try {
084: _manifest = _jarPath.getManifest();
085: if (_manifest == null)
086: return;
087:
088: Attributes attr = _manifest.getMainAttributes();
089: if (attr != null)
090: addManifestPackage("", attr);
091:
092: Map entries = _manifest.getEntries();
093:
094: Iterator iter = entries.keySet().iterator();
095: while (iter.hasNext()) {
096: String pkg = (String) iter.next();
097:
098: attr = _manifest.getAttributes(pkg);
099: if (attr == null)
100: continue;
101:
102: addManifestPackage(pkg, attr);
103: }
104: } catch (IOException e) {
105: log.log(Level.WARNING, e.toString(), e);
106: }
107: }
108:
109: /**
110: * Adds package information from the manifest.
111: */
112: private void addManifestPackage(String name, Attributes attr) {
113: // only add packages
114: if (!name.endsWith("/") && !name.equals(""))
115: return;
116:
117: String specTitle = attr.getValue("Specification-Title");
118: String specVersion = attr.getValue("Specification-Version");
119: String specVendor = attr.getValue("Specification-Vendor");
120: String implTitle = attr.getValue("Implementation-Title");
121: String implVersion = attr.getValue("Implementation-Version");
122: String implVendor = attr.getValue("Implementation-Vendor");
123:
124: // If all none, then it isn't a package entry
125: if (specTitle == null && specVersion == null
126: && specVendor != null && implTitle == null
127: && implVersion == null && implVendor != null)
128: return;
129:
130: ClassPackage pkg = new ClassPackage(name);
131: pkg.setSpecificationTitle(specTitle);
132: pkg.setSpecificationVersion(specVersion);
133: pkg.setSpecificationVendor(specVendor);
134: pkg.setImplementationTitle(implTitle);
135: pkg.setImplementationVersion(implVersion);
136: pkg.setImplementationVendor(implVendor);
137:
138: _packages.add(pkg);
139: }
140:
141: /**
142: * Validates the jar.
143: */
144: public void validate() throws ConfigException {
145: if (_manifest != null)
146: validateManifest(_jarPath.getContainer().getURL(),
147: _manifest);
148: }
149:
150: /**
151: * Validates the manifest.
152: */
153: public static void validateManifest(String manifestName,
154: Manifest manifest) throws ConfigException {
155: Attributes attr = manifest.getMainAttributes();
156: if (attr == null)
157: return;
158:
159: String extList = attr.getValue("Extension-List");
160: if (extList == null)
161: return;
162:
163: Pattern pattern = Pattern.compile("[, \t]+");
164: String[] split = pattern.split(extList);
165:
166: for (int i = 0; i < split.length; i++) {
167: String ext = split[i];
168:
169: String name = attr.getValue(ext + "-Extension-Name");
170: if (name == null)
171: continue;
172:
173: Package pkg = Package.getPackage(name);
174:
175: if (pkg == null) {
176: log
177: .warning(L
178: .l(
179: "package {0} is missing. {1} requires package {0}.",
180: name, manifestName));
181: continue;
182: }
183:
184: String version = attr.getValue(ext
185: + "-Specification-Version");
186:
187: if (version == null)
188: continue;
189:
190: if (pkg.getSpecificationVersion() == null
191: || pkg.getSpecificationVersion().equals("")) {
192: log
193: .warning(L
194: .l(
195: "installed {0} is not compatible with version `{1}'. {2} requires version {1}.",
196: name, version, manifestName));
197: } else if (!pkg.isCompatibleWith(version)) {
198: log
199: .warning(L
200: .l(
201: "installed {0} is not compatible with version `{1}'. {2} requires version {1}.",
202: name, version, manifestName));
203: }
204: }
205: }
206:
207: public ClassPackage getPackage(String name) {
208: ClassPackage bestPackage = null;
209: int bestLength = -1;
210:
211: for (int i = 0; i < _packages.size(); i++) {
212: ClassPackage pkg = _packages.get(i);
213:
214: String prefix = pkg.getPrefix();
215:
216: if (name.startsWith(prefix) && bestLength < prefix.length()) {
217: bestPackage = pkg;
218: bestLength = prefix.length();
219: }
220: }
221:
222: return bestPackage;
223: }
224:
225: public JarPath getJarPath() {
226: return _jarPath;
227: }
228:
229: /**
230: * Returns the code source.
231: */
232: public CodeSource getCodeSource(String path) {
233: try {
234: Path jarPath = _jarPath.lookup(path);
235:
236: Certificate[] certificates = jarPath.getCertificates();
237:
238: return new CodeSource(new URL(jarPath.getURL()),
239: certificates);
240: } catch (Exception e) {
241: log.log(Level.WARNING, e.toString(), e);
242:
243: return null;
244: }
245: }
246:
247: /**
248: * Tests for equality.
249: */
250: public boolean equals(Object o) {
251: if (!(o instanceof JarEntry))
252: return false;
253:
254: JarEntry entry = (JarEntry) o;
255:
256: return _jarPath.equals(entry._jarPath);
257: }
258:
259: public String toString() {
260: return getClass().getSimpleName() + "[" + _jarPath + "]";
261: }
262: }
|