1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.catalina.util;
18
19 import java.util.ArrayList;
20 import java.util.jar.Attributes;
21 import java.util.jar.Manifest;
22
23 /**
24  *  Representation of a Manifest file and its available extensions and
25  *  required extensions
26  *
27  * @author Greg Murray
28  * @author Justyna Horwat
29  */

30 public class ManifestResource {
31
32     // ------------------------------------------------------------- Properties
33
34     // These are the resource types for determining effect error messages
35     public static final int SYSTEM = 1;
36     public static final int WAR = 2;
37     public static final int APPLICATION = 3;
38
39     private ArrayList<Extension> availableExtensions = null;
40     private ArrayList<Extension> requiredExtensions = null;
41
42     private final String resourceName;
43     private final int resourceType;
44
45     public ManifestResource(String resourceName, Manifest manifest,
46                             int resourceType) {
47         this.resourceName = resourceName;
48         this.resourceType = resourceType;
49         processManifest(manifest);
50     }
51
52     /**
53      * Gets the name of the resource
54      *
55      * @return The name of the resource
56      */

57     public String getResourceName() {
58         return resourceName;
59     }
60
61     /**
62      * Gets the list of available extensions
63      *
64      * @return List of available extensions
65      */

66     public ArrayList<Extension> getAvailableExtensions() {
67         return availableExtensions;
68     }
69
70     /**
71      * Gets the list of required extensions
72      *
73      * @return List of required extensions
74      */

75     public ArrayList<Extension> getRequiredExtensions() {
76         return requiredExtensions;
77     }
78
79     // --------------------------------------------------------- Public Methods
80
81     /**
82      * Gets the number of available extensions
83      *
84      * @return The number of available extensions
85      */

86     public int getAvailableExtensionCount() {
87         return (availableExtensions != null) ? availableExtensions.size() : 0;
88     }
89
90     /**
91      * Gets the number of required extensions
92      *
93      * @return The number of required extensions
94      */

95     public int getRequiredExtensionCount() {
96         return (requiredExtensions != null) ? requiredExtensions.size() : 0;
97     }
98
99     /**
100      * Returns <code>true</code> if all required extension dependencies
101      * have been meet for this <code>ManifestResource</code> object.
102      *
103      * @return boolean true if all extension dependencies have been satisfied
104      */

105     public boolean isFulfilled() {
106         if (requiredExtensions == null) {
107             return true;
108         }
109         for (Extension ext : requiredExtensions) {
110             if (!ext.isFulfilled()) return false;
111         }
112         return true;
113     }
114
115     @Override
116     public String toString() {
117         StringBuilder sb = new StringBuilder("ManifestResource[");
118         sb.append(resourceName);
119
120         sb.append(", isFulfilled=");
121         sb.append(isFulfilled() +"");
122         sb.append(", requiredExtensionCount =");
123         sb.append(getRequiredExtensionCount());
124         sb.append(", availableExtensionCount=");
125         sb.append(getAvailableExtensionCount());
126         switch (resourceType) {
127             case SYSTEM : sb.append(", resourceType=SYSTEM"); break;
128             case WAR : sb.append(", resourceType=WAR"); break;
129             case APPLICATION : sb.append(", resourceType=APPLICATION"); break;
130         }
131         sb.append("]");
132         return sb.toString();
133     }
134
135
136     // -------------------------------------------------------- Private Methods
137
138     private void processManifest(Manifest manifest) {
139         availableExtensions = getAvailableExtensions(manifest);
140         requiredExtensions = getRequiredExtensions(manifest);
141     }
142
143     /**
144      * Return the set of <code>Extension</code> objects representing optional
145      * packages that are required by the application associated with the
146      * specified <code>Manifest</code>.
147      *
148      * @param manifest Manifest to be parsed
149      *
150      * @return List of required extensions, or null if the application
151      * does not require any extensions
152      */

153     private ArrayList<Extension> getRequiredExtensions(Manifest manifest) {
154
155         Attributes attributes = manifest.getMainAttributes();
156         String names = attributes.getValue("Extension-List");
157         if (names == null)
158             return null;
159
160         ArrayList<Extension> extensionList = new ArrayList<>();
161         names += " ";
162
163         while (true) {
164
165             int space = names.indexOf(' ');
166             if (space < 0)
167                 break;
168             String name = names.substring(0, space).trim();
169             names = names.substring(space + 1);
170
171             String value =
172                 attributes.getValue(name + "-Extension-Name");
173             if (value == null)
174                 continue;
175             Extension extension = new Extension();
176             extension.setExtensionName(value);
177             extension.setImplementationURL
178                 (attributes.getValue(name + "-Implementation-URL"));
179             extension.setImplementationVendorId
180                 (attributes.getValue(name + "-Implementation-Vendor-Id"));
181             String version = attributes.getValue(name + "-Implementation-Version");
182             extension.setImplementationVersion(version);
183             extension.setSpecificationVersion
184                 (attributes.getValue(name + "-Specification-Version"));
185             extensionList.add(extension);
186         }
187         return extensionList;
188     }
189
190     /**
191      * Return the set of <code>Extension</code> objects representing optional
192      * packages that are bundled with the application associated with the
193      * specified <code>Manifest</code>.
194      *
195      * @param manifest Manifest to be parsed
196      *
197      * @return List of available extensions, or null if the web application
198      * does not bundle any extensions
199      */

200     private ArrayList<Extension> getAvailableExtensions(Manifest manifest) {
201
202         Attributes attributes = manifest.getMainAttributes();
203         String name = attributes.getValue("Extension-Name");
204         if (name == null)
205             return null;
206
207         ArrayList<Extension> extensionList = new ArrayList<>();
208
209         Extension extension = new Extension();
210         extension.setExtensionName(name);
211         extension.setImplementationURL(
212             attributes.getValue("Implementation-URL"));
213         extension.setImplementationVendor(
214             attributes.getValue("Implementation-Vendor"));
215         extension.setImplementationVendorId(
216             attributes.getValue("Implementation-Vendor-Id"));
217         extension.setImplementationVersion(
218             attributes.getValue("Implementation-Version"));
219         extension.setSpecificationVersion(
220             attributes.getValue("Specification-Version"));
221
222         extensionList.add(extension);
223
224         return extensionList;
225     }
226
227 }
228