001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.util;
018:
019: import java.util.StringTokenizer;
020:
021: /**
022: * Utility class that represents either an available "Optional Package"
023: * (formerly known as "Standard Extension") as described in the manifest
024: * of a JAR file, or the requirement for such an optional package. It is
025: * used to support the requirements of the Servlet Specification, version
026: * 2.3, related to providing shared extensions to all webapps.
027: * <p>
028: * In addition, static utility methods are available to scan a manifest
029: * and return an array of either available or required optional modules
030: * documented in that manifest.
031: * <p>
032: * For more information about optional packages, see the document
033: * <em>Optional Package Versioning</em> in the documentation bundle for your
034: * Java2 Standard Edition package, in file
035: * <code>guide/extensions/versioning.html</code>.
036: *
037: * @author Craig McClanahan
038: * @author Justyna Horwat
039: * @author Greg Murray
040: * @version $Revision: 1.3 $ $Date: 2004/02/27 14:58:50 $
041: */
042:
043: public final class Extension {
044:
045: // ------------------------------------------------------------- Properties
046:
047: /**
048: * The name of the optional package being made available, or required.
049: */
050: private String extensionName = null;
051:
052: public String getExtensionName() {
053: return (this .extensionName);
054: }
055:
056: public void setExtensionName(String extensionName) {
057: this .extensionName = extensionName;
058: }
059:
060: /**
061: * UniqueId created by combining the extension name and implementation
062: * version.
063: */
064: public String getUniqueId() {
065: return this .extensionName + this .implementationVersion;
066: }
067:
068: /**
069: * The URL from which the most recent version of this optional package
070: * can be obtained if it is not already installed.
071: */
072: private String implementationURL = null;
073:
074: public String getImplementationURL() {
075: return (this .implementationURL);
076: }
077:
078: public void setImplementationURL(String implementationURL) {
079: this .implementationURL = implementationURL;
080: }
081:
082: /**
083: * The name of the company or organization that produced this
084: * implementation of this optional package.
085: */
086: private String implementationVendor = null;
087:
088: public String getImplementationVendor() {
089: return (this .implementationVendor);
090: }
091:
092: public void setImplementationVendor(String implementationVendor) {
093: this .implementationVendor = implementationVendor;
094: }
095:
096: /**
097: * The unique identifier of the company that produced the optional
098: * package contained in this JAR file.
099: */
100: private String implementationVendorId = null;
101:
102: public String getImplementationVendorId() {
103: return (this .implementationVendorId);
104: }
105:
106: public void setImplementationVendorId(String implementationVendorId) {
107: this .implementationVendorId = implementationVendorId;
108: }
109:
110: /**
111: * The version number (dotted decimal notation) for this implementation
112: * of the optional package.
113: */
114: private String implementationVersion = null;
115:
116: public String getImplementationVersion() {
117: return (this .implementationVersion);
118: }
119:
120: public void setImplementationVersion(String implementationVersion) {
121: this .implementationVersion = implementationVersion;
122: }
123:
124: /**
125: * The name of the company or organization that originated the
126: * specification to which this optional package conforms.
127: */
128: private String specificationVendor = null;
129:
130: public String getSpecificationVendor() {
131: return (this .specificationVendor);
132: }
133:
134: public void setSpecificationVendor(String specificationVendor) {
135: this .specificationVendor = specificationVendor;
136: }
137:
138: /**
139: * The version number (dotted decimal notation) of the specification
140: * to which this optional package conforms.
141: */
142: private String specificationVersion = null;
143:
144: public String getSpecificationVersion() {
145: return (this .specificationVersion);
146: }
147:
148: public void setSpecificationVersion(String specificationVersion) {
149: this .specificationVersion = specificationVersion;
150: }
151:
152: /**
153: * fulfilled is true if all the required extension dependencies have been
154: * satisfied
155: */
156: private boolean fulfilled = false;
157:
158: public void setFulfilled(boolean fulfilled) {
159: this .fulfilled = fulfilled;
160: }
161:
162: public boolean isFulfilled() {
163: return fulfilled;
164: }
165:
166: // --------------------------------------------------------- Public Methods
167:
168: /**
169: * Return <code>true</code> if the specified <code>Extension</code>
170: * (which represents an optional package required by this application)
171: * is satisfied by this <code>Extension</code> (which represents an
172: * optional package that is already installed. Otherwise, return
173: * <code>false</code>.
174: *
175: * @param required Extension of the required optional package
176: */
177: public boolean isCompatibleWith(Extension required) {
178:
179: // Extension Name must match
180: if (extensionName == null)
181: return (false);
182: if (!extensionName.equals(required.getExtensionName()))
183: return (false);
184:
185: // Available specification version must be >= required
186: if (!isNewer(specificationVersion, required
187: .getSpecificationVersion()))
188: return (false);
189:
190: // Implementation Vendor ID must match
191: if (implementationVendorId == null)
192: return (false);
193: if (!implementationVendorId.equals(required
194: .getImplementationVendorId()))
195: return (false);
196:
197: // Implementation version must be >= required
198: if (!isNewer(implementationVersion, required
199: .getImplementationVersion()))
200: return (false);
201:
202: // This available optional package satisfies the requirements
203: return (true);
204:
205: }
206:
207: /**
208: * Return a String representation of this object.
209: */
210: public String toString() {
211:
212: StringBuffer sb = new StringBuffer("Extension[");
213: sb.append(extensionName);
214: if (implementationURL != null) {
215: sb.append(", implementationURL=");
216: sb.append(implementationURL);
217: }
218: if (implementationVendor != null) {
219: sb.append(", implementationVendor=");
220: sb.append(implementationVendor);
221: }
222: if (implementationVendorId != null) {
223: sb.append(", implementationVendorId=");
224: sb.append(implementationVendorId);
225: }
226: if (implementationVersion != null) {
227: sb.append(", implementationVersion=");
228: sb.append(implementationVersion);
229: }
230: if (specificationVendor != null) {
231: sb.append(", specificationVendor=");
232: sb.append(specificationVendor);
233: }
234: if (specificationVersion != null) {
235: sb.append(", specificationVersion=");
236: sb.append(specificationVersion);
237: }
238: sb.append("]");
239: return (sb.toString());
240:
241: }
242:
243: // -------------------------------------------------------- Private Methods
244:
245: /**
246: * Return <code>true</code> if the first version number is greater than
247: * or equal to the second; otherwise return <code>false</code>.
248: *
249: * @param first First version number (dotted decimal)
250: * @param second Second version number (dotted decimal)
251: *
252: * @exception NumberFormatException on a malformed version number
253: */
254: private boolean isNewer(String first, String second)
255: throws NumberFormatException {
256:
257: if ((first == null) || (second == null))
258: return (false);
259: if (first.equals(second))
260: return (true);
261:
262: StringTokenizer fTok = new StringTokenizer(first, ".", true);
263: StringTokenizer sTok = new StringTokenizer(second, ".", true);
264: int fVersion = 0;
265: int sVersion = 0;
266: while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) {
267: if (fTok.hasMoreTokens())
268: fVersion = Integer.parseInt(fTok.nextToken());
269: else
270: fVersion = 0;
271: if (sTok.hasMoreTokens())
272: sVersion = Integer.parseInt(sTok.nextToken());
273: else
274: sVersion = 0;
275: if (fVersion < sVersion)
276: return (false);
277: else if (fVersion > sVersion)
278: return (true);
279: if (fTok.hasMoreTokens()) // Swallow the periods
280: fTok.nextToken();
281: if (sTok.hasMoreTokens())
282: sTok.nextToken();
283: }
284:
285: return (true); // Exact match
286:
287: }
288:
289: }
|