View | Details | Raw Unified | Return to bug 52952
Collapse All | Expand All

(-)java/org/apache/catalina/core/StandardContext.java (-1 / +12 lines)
Lines 84-89 Link Here
84
import org.apache.catalina.ContainerListener;
84
import org.apache.catalina.ContainerListener;
85
import org.apache.catalina.Context;
85
import org.apache.catalina.Context;
86
import org.apache.catalina.CredentialHandler;
86
import org.apache.catalina.CredentialHandler;
87
import org.apache.catalina.Engine;
87
import org.apache.catalina.Globals;
88
import org.apache.catalina.Globals;
88
import org.apache.catalina.Lifecycle;
89
import org.apache.catalina.Lifecycle;
89
import org.apache.catalina.LifecycleException;
90
import org.apache.catalina.LifecycleException;
Lines 2479-2484 Link Here
2479
        this.threadBindingListener = threadBindingListener;
2480
        this.threadBindingListener = threadBindingListener;
2480
    }
2481
    }
2481
2482
2483
    public ExtensionValidator getExtensionValidator() {
2484
        try {
2485
            // Walking back through the Tomcat hierarchy.
2486
            // Host -> Engine -> Service -> Server.
2487
            return ((Engine)getParent().getParent()).getService().getServer().getExtensionValidator();
2488
        } catch (Exception e) {
2489
            // Return default ExtensionValidator if any cast exception occurred.
2490
            return ExtensionValidator.DEFAULT;
2491
        }
2492
    }
2482
2493
2483
    // ------------------------------------------------------ Public Properties
2494
    // ------------------------------------------------------ Public Properties
2484
2495
Lines 5019-5025 Link Here
5019
        // Validate required extensions
5030
        // Validate required extensions
5020
        boolean dependencyCheck = true;
5031
        boolean dependencyCheck = true;
5021
        try {
5032
        try {
5022
            dependencyCheck = ExtensionValidator.validateApplication
5033
            dependencyCheck = getExtensionValidator().validateApplication
5023
                (getResources(), this);
5034
                (getResources(), this);
5024
        } catch (IOException ioe) {
5035
        } catch (IOException ioe) {
5025
            log.error(sm.getString("standardContext.extensionValidationError"), ioe);
5036
            log.error(sm.getString("standardContext.extensionValidationError"), ioe);
(-)java/org/apache/catalina/core/StandardServer.java (-1 / +10 lines)
Lines 173-178 Link Here
173
173
174
    private final Object namingToken = new Object();
174
    private final Object namingToken = new Object();
175
175
176
    /**
177
     * Extension validator that is used to ensure that extensions is fulfilled.
178
     */
179
    private ExtensionValidator extensionValidator = new ExtensionValidator();
176
180
177
    // ------------------------------------------------------------- Properties
181
    // ------------------------------------------------------------- Properties
178
182
Lines 352-357 Link Here
352
        this.catalina = catalina;
356
        this.catalina = catalina;
353
    }
357
    }
354
358
359
    @Override
360
    public ExtensionValidator getExtensionValidator(){
361
        return extensionValidator;
362
    }
363
355
    // --------------------------------------------------------- Server Methods
364
    // --------------------------------------------------------- Server Methods
356
365
357
366
Lines 855-861 Link Here
855
                                File f = new File (url.toURI());
864
                                File f = new File (url.toURI());
856
                                if (f.isFile() &&
865
                                if (f.isFile() &&
857
                                        f.getName().endsWith(".jar")) {
866
                                        f.getName().endsWith(".jar")) {
858
                                    ExtensionValidator.addSystemResource(f);
867
                                    extensionValidator.addSystemResource(f);
859
                                }
868
                                }
860
                            } catch (URISyntaxException e) {
869
                            } catch (URISyntaxException e) {
861
                                // Ignore
870
                                // Ignore
(-)java/org/apache/catalina/Server.java (+3 lines)
Lines 22-27 Link Here
22
22
23
import org.apache.catalina.deploy.NamingResourcesImpl;
23
import org.apache.catalina.deploy.NamingResourcesImpl;
24
import org.apache.catalina.startup.Catalina;
24
import org.apache.catalina.startup.Catalina;
25
import org.apache.catalina.util.ExtensionValidator;
25
26
26
/**
27
/**
27
 * A <code>Server</code> element represents the entire Catalina
28
 * A <code>Server</code> element represents the entire Catalina
Lines 219-222 Link Here
219
     * context.
220
     * context.
220
     */
221
     */
221
    public Object getNamingToken();
222
    public Object getNamingToken();
223
224
    public ExtensionValidator getExtensionValidator();
222
}
225
}
(-)java/org/apache/catalina/util/Extension.java (-1 / +41 lines)
Lines 248-258 Link Here
248
248
249
    }
249
    }
250
250
251
    @Override
252
    public boolean equals(Object o) {
253
        if (this == o) return true;
254
        if (!(o instanceof Extension)) return false;
251
255
252
    // -------------------------------------------------------- Private Methods
256
        Extension extension = (Extension) o;
253
257
258
        if (extensionName != null ? !extensionName.equals(extension.extensionName)
259
                : extension.extensionName != null)
260
            return false;
261
        if (implementationURL != null ? !implementationURL.equals(extension.implementationURL)
262
                : extension.implementationURL != null)
263
            return false;
264
        if (implementationVendor != null ? !implementationVendor.equals(extension.implementationVendor)
265
                : extension.implementationVendor != null)
266
            return false;
267
        if (implementationVendorId != null ? !implementationVendorId.equals(extension.implementationVendorId)
268
                : extension.implementationVendorId != null)
269
            return false;
270
        if (implementationVersion != null ? !implementationVersion.equals(extension.implementationVersion)
271
                : extension.implementationVersion != null)
272
            return false;
273
        if (specificationVendor != null ? !specificationVendor.equals(extension.specificationVendor)
274
                : extension.specificationVendor != null)
275
            return false;
276
        return specificationVersion != null ? specificationVersion.equals(extension.specificationVersion)
277
                : extension.specificationVersion == null;
278
    }
254
279
280
    @Override
281
    public int hashCode() {
282
        int result = extensionName != null ? extensionName.hashCode() : 0;
283
        result = 31 * result + (implementationURL != null ? implementationURL.hashCode() : 0);
284
        result = 31 * result + (implementationVendor != null ? implementationVendor.hashCode() : 0);
285
        result = 31 * result + (implementationVendorId != null ? implementationVendorId.hashCode() : 0);
286
        result = 31 * result + (implementationVersion != null ? implementationVersion.hashCode() : 0);
287
        result = 31 * result + (specificationVendor != null ? specificationVendor.hashCode() : 0);
288
        result = 31 * result + (specificationVersion != null ? specificationVersion.hashCode() : 0);
289
        return result;
290
    }
255
291
292
// -------------------------------------------------------- Private Methods
293
294
295
256
    /**
296
    /**
257
     * Return <code>true</code> if the first version number is greater than
297
     * Return <code>true</code> if the first version number is greater than
258
     * or equal to the second; otherwise return <code>false</code>.
298
     * or equal to the second; otherwise return <code>false</code>.
(-)java/org/apache/catalina/util/ExtensionValidator.java (-33 / +48 lines)
Lines 20-28 Link Here
20
import java.io.FileInputStream;
20
import java.io.FileInputStream;
21
import java.io.IOException;
21
import java.io.IOException;
22
import java.io.InputStream;
22
import java.io.InputStream;
23
import java.util.ArrayList;
23
import java.util.HashSet;
24
import java.util.Iterator;
24
import java.util.Iterator;
25
import java.util.Locale;
25
import java.util.Locale;
26
import java.util.Set;
26
import java.util.StringTokenizer;
27
import java.util.StringTokenizer;
27
import java.util.jar.JarInputStream;
28
import java.util.jar.JarInputStream;
28
import java.util.jar.Manifest;
29
import java.util.jar.Manifest;
Lines 46-55 Link Here
46
 * @author Greg Murray
47
 * @author Greg Murray
47
 * @author Justyna Horwat
48
 * @author Justyna Horwat
48
 */
49
 */
49
public final class ExtensionValidator {
50
public class ExtensionValidator {
50
51
51
    private static final Log log = LogFactory.getLog(ExtensionValidator.class);
52
    private static final Log log = LogFactory.getLog(ExtensionValidator.class);
52
53
54
    public static final ExtensionValidator DEFAULT = new ExtensionValidator(){
55
        @Override
56
        public void addSystemResource(File jarFile) throws IOException {
57
            throw new UnsupportedOperationException("this is a read-only ExtensionValidator");
58
        }
59
    };
60
53
    /**
61
    /**
54
     * The string resources for this package.
62
     * The string resources for this package.
55
     */
63
     */
Lines 56-72 Link Here
56
    private static final StringManager sm =
64
    private static final StringManager sm =
57
            StringManager.getManager("org.apache.catalina.util");
65
            StringManager.getManager("org.apache.catalina.util");
58
66
59
    private static volatile ArrayList<Extension> containerAvailableExtensions =
67
    private volatile Set<Extension> containerAvailableExtensions =
60
            null;
68
            null;
61
    private static final ArrayList<ManifestResource> containerManifestResources =
69
    private final Set<ManifestResource> containerManifestResources =
62
            new ArrayList<>();
70
            new HashSet<>();
63
71
64
72
65
    // ----------------------------------------------------- Static Initializer
73
    // ----------------------------------------------------- Constructor
66
74
67
75
68
    /**
76
    /**
69
     *  This static initializer loads the container level extensions that are
77
     *  This constructor loads the container level extensions that are
70
     *  available to all web applications. This method scans all extension
78
     *  available to all web applications. This method scans all extension
71
     *  directories available via the "java.ext.dirs" System property.
79
     *  directories available via the "java.ext.dirs" System property.
72
     *
80
     *
Lines 73-79 Link Here
73
     *  The System Class-Path is also scanned for jar files that may contain
81
     *  The System Class-Path is also scanned for jar files that may contain
74
     *  available extensions.
82
     *  available extensions.
75
     */
83
     */
76
    static {
84
    public ExtensionValidator(){
77
85
78
        // check for container level optional packages
86
        // check for container level optional packages
79
        String systemClasspath = System.getProperty("java.class.path");
87
        String systemClasspath = System.getProperty("java.class.path");
Lines 88-94 Link Here
88
                File item = new File(classpathItem);
96
                File item = new File(classpathItem);
89
                if (item.isFile()) {
97
                if (item.isFile()) {
90
                    try {
98
                    try {
91
                        addSystemResource(item);
99
                        doAddSystemResource(item);
92
                    } catch (IOException e) {
100
                    } catch (IOException e) {
93
                        log.error(sm.getString
101
                        log.error(sm.getString
94
                                  ("extensionValidator.failload", item), e);
102
                                  ("extensionValidator.failload", item), e);
Lines 123-135 Link Here
123
     * @return true if all required extensions satisfied
131
     * @return true if all required extensions satisfied
124
     * @throws IOException Error reading resources needed for validation
132
     * @throws IOException Error reading resources needed for validation
125
     */
133
     */
126
    public static synchronized boolean validateApplication(
134
    public synchronized boolean validateApplication(
127
                                           WebResourceRoot resources,
135
                                           WebResourceRoot resources,
128
                                           Context context)
136
                                           Context context)
129
                    throws IOException {
137
                    throws IOException {
130
138
131
        String appName = context.getName();
139
        String appName = context.getName();
132
        ArrayList<ManifestResource> appManifestResources = new ArrayList<>();
140
        Set<ManifestResource> appManifestResources = new HashSet<>();
133
141
134
        // Web application manifest
142
        // Web application manifest
135
        WebResource resource = resources.getResource("/META-INF/MANIFEST.MF");
143
        WebResource resource = resources.getResource("/META-INF/MANIFEST.MF");
Lines 171-185 Link Here
171
     * @param jarFile The system JAR whose manifest to add
179
     * @param jarFile The system JAR whose manifest to add
172
     * @throws IOException Error reading JAR file
180
     * @throws IOException Error reading JAR file
173
     */
181
     */
174
    public static void addSystemResource(File jarFile) throws IOException {
182
    public void addSystemResource(File jarFile) throws IOException {
175
        try (InputStream is = new FileInputStream(jarFile)) {
183
        doAddSystemResource(jarFile);
176
            Manifest manifest = getManifest(is);
177
            if (manifest != null) {
178
                ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest,
179
                        ManifestResource.SYSTEM);
180
                containerManifestResources.add(mre);
181
            }
182
        }
183
    }
184
    }
184
185
185
186
Lines 205-220 Link Here
205
     *
206
     *
206
     * @return true if manifest resource file requirements are met
207
     * @return true if manifest resource file requirements are met
207
     */
208
     */
208
    private static boolean validateManifestResources(String appName,
209
    private boolean validateManifestResources(String appName,
209
            ArrayList<ManifestResource> resources) {
210
            Set<ManifestResource> resources) {
210
        boolean passes = true;
211
        boolean passes = true;
211
        int failureCount = 0;
212
        int failureCount = 0;
212
        ArrayList<Extension> availableExtensions = null;
213
        Set<Extension> availableExtensions = null;
213
214
214
        Iterator<ManifestResource> it = resources.iterator();
215
        Iterator<ManifestResource> it = resources.iterator();
215
        while (it.hasNext()) {
216
        while (it.hasNext()) {
216
            ManifestResource mre = it.next();
217
            ManifestResource mre = it.next();
217
            ArrayList<Extension> requiredList = mre.getRequiredExtensions();
218
            Set<Extension> requiredList = mre.getRequiredExtensions();
218
            if (requiredList == null) {
219
            if (requiredList == null) {
219
                continue;
220
                continue;
220
            }
221
            }
Lines 299-319 Link Here
299
    *
300
    *
300
    * @return HashMap Map of available extensions
301
    * @return HashMap Map of available extensions
301
    */
302
    */
302
    private static ArrayList<Extension> buildAvailableExtensionsList(
303
    private Set<Extension> buildAvailableExtensionsList(
303
            ArrayList<ManifestResource> resources) {
304
            Set<ManifestResource> resources) {
304
305
305
        ArrayList<Extension> availableList = null;
306
        Set<Extension> availableList = null;
306
307
307
        Iterator<ManifestResource> it = resources.iterator();
308
        Iterator<ManifestResource> it = resources.iterator();
308
        while (it.hasNext()) {
309
        while (it.hasNext()) {
309
            ManifestResource mre = it.next();
310
            ManifestResource mre = it.next();
310
            ArrayList<Extension> list = mre.getAvailableExtensions();
311
            Set<Extension> list = mre.getAvailableExtensions();
311
            if (list != null) {
312
            if (list != null) {
312
                Iterator<Extension> values = list.iterator();
313
                Iterator<Extension> values = list.iterator();
313
                while (values.hasNext()) {
314
                while (values.hasNext()) {
314
                    Extension ext = values.next();
315
                    Extension ext = values.next();
315
                    if (availableList == null) {
316
                    if (availableList == null) {
316
                        availableList = new ArrayList<>();
317
                        availableList = new HashSet<>();
317
                        availableList.add(ext);
318
                        availableList.add(ext);
318
                    } else {
319
                    } else {
319
                        availableList.add(ext);
320
                        availableList.add(ext);
Lines 331-337 Link Here
331
     * @param inStream Input stream to a WAR or JAR file
332
     * @param inStream Input stream to a WAR or JAR file
332
     * @return The WAR's or JAR's manifest
333
     * @return The WAR's or JAR's manifest
333
     */
334
     */
334
    private static Manifest getManifest(InputStream inStream) throws IOException {
335
    private Manifest getManifest(InputStream inStream) throws IOException {
335
        Manifest manifest = null;
336
        Manifest manifest = null;
336
        try (JarInputStream jin = new JarInputStream(inStream)) {
337
        try (JarInputStream jin = new JarInputStream(inStream)) {
337
            manifest = jin.getManifest();
338
            manifest = jin.getManifest();
Lines 343-349 Link Here
343
    /**
344
    /**
344
     * Add the JARs specified to the extension list.
345
     * Add the JARs specified to the extension list.
345
     */
346
     */
346
    private static void addFolderList(String property) {
347
    private void addFolderList(String property) {
347
348
348
        // get the files in the extensions directory
349
        // get the files in the extensions directory
349
        String extensionsDir = System.getProperty(property);
350
        String extensionsDir = System.getProperty(property);
Lines 363-369 Link Here
363
                    if (files[i].getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") &&
364
                    if (files[i].getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") &&
364
                            files[i].isFile()) {
365
                            files[i].isFile()) {
365
                        try {
366
                        try {
366
                            addSystemResource(files[i]);
367
                            doAddSystemResource(files[i]);
367
                        } catch (IOException e) {
368
                        } catch (IOException e) {
368
                            log.error
369
                            log.error
369
                                (sm.getString
370
                                (sm.getString
Lines 376-380 Link Here
376
377
377
    }
378
    }
378
379
379
380
    /**
381
     *
382
     * @param jarFile
383
     * @throws IOException
384
     */
385
    private void doAddSystemResource(File jarFile) throws IOException {
386
        try (InputStream is = new FileInputStream(jarFile)) {
387
            Manifest manifest = getManifest(is);
388
            if (manifest != null) {
389
                ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest,
390
                        ManifestResource.SYSTEM);
391
                containerManifestResources.add(mre);
392
            }
393
        }
394
    }
380
}
395
}
(-)java/org/apache/catalina/util/ManifestResource.java (-10 / +38 lines)
Lines 16-23 Link Here
16
 */
16
 */
17
package org.apache.catalina.util;
17
package org.apache.catalina.util;
18
18
19
import java.util.ArrayList;
19
import java.util.HashSet;
20
import java.util.Iterator;
20
import java.util.Iterator;
21
import java.util.Set;
21
import java.util.jar.Attributes;
22
import java.util.jar.Attributes;
22
import java.util.jar.Manifest;
23
import java.util.jar.Manifest;
23
24
Lines 37-44 Link Here
37
    public static final int WAR = 2;
38
    public static final int WAR = 2;
38
    public static final int APPLICATION = 3;
39
    public static final int APPLICATION = 3;
39
40
40
    private ArrayList<Extension> availableExtensions = null;
41
    private Set<Extension> availableExtensions = null;
41
    private ArrayList<Extension> requiredExtensions = null;
42
    private Set<Extension> requiredExtensions = null;
42
43
43
    private final String resourceName;
44
    private final String resourceName;
44
    private final int resourceType;
45
    private final int resourceType;
Lines 64-70 Link Here
64
     *
65
     *
65
     * @return List of available extensions
66
     * @return List of available extensions
66
     */
67
     */
67
    public ArrayList<Extension> getAvailableExtensions() {
68
    public Set<Extension> getAvailableExtensions() {
68
        return availableExtensions;
69
        return availableExtensions;
69
    }
70
    }
70
71
Lines 73-79 Link Here
73
     *
74
     *
74
     * @return List of required extensions
75
     * @return List of required extensions
75
     */
76
     */
76
    public ArrayList<Extension> getRequiredExtensions() {
77
    public Set<Extension> getRequiredExtensions() {
77
        return requiredExtensions;
78
        return requiredExtensions;
78
    }
79
    }
79
80
Lines 136-144 Link Here
136
        return (sb.toString());
137
        return (sb.toString());
137
    }
138
    }
138
139
140
    @Override
141
    public boolean equals(Object o) {
142
        if (this == o) return true;
143
        if (!(o instanceof ManifestResource)) return false;
139
144
140
    // -------------------------------------------------------- Private Methods
145
        ManifestResource that = (ManifestResource) o;
141
146
147
        if (resourceType != that.resourceType) return false;
148
        if (availableExtensions != null ? !availableExtensions.equals(that.availableExtensions)
149
                : that.availableExtensions != null)
150
            return false;
151
        if (requiredExtensions != null ? !requiredExtensions.equals(that.requiredExtensions)
152
                : that.requiredExtensions != null)
153
            return false;
154
155
        return resourceName != null ? resourceName.equals(that.resourceName)
156
                : that.resourceName == null;
157
    }
158
159
    @Override
160
    public int hashCode() {
161
        int result = availableExtensions != null ? availableExtensions.hashCode() : 0;
162
        result = 31 * result + (requiredExtensions != null ? requiredExtensions.hashCode() : 0);
163
        result = 31 * result + (resourceName != null ? resourceName.hashCode() : 0);
164
        result = 31 * result + resourceType;
165
        return result;
166
    }
167
168
// -------------------------------------------------------- Private Methods
169
142
    private void processManifest(Manifest manifest) {
170
    private void processManifest(Manifest manifest) {
143
        availableExtensions = getAvailableExtensions(manifest);
171
        availableExtensions = getAvailableExtensions(manifest);
144
        requiredExtensions = getRequiredExtensions(manifest);
172
        requiredExtensions = getRequiredExtensions(manifest);
Lines 154-160 Link Here
154
     * @return List of required extensions, or null if the application
182
     * @return List of required extensions, or null if the application
155
     * does not require any extensions
183
     * does not require any extensions
156
     */
184
     */
157
    private ArrayList<Extension> getRequiredExtensions(Manifest manifest) {
185
    private Set<Extension> getRequiredExtensions(Manifest manifest) {
158
186
159
        Attributes attributes = manifest.getMainAttributes();
187
        Attributes attributes = manifest.getMainAttributes();
160
        String names = attributes.getValue("Extension-List");
188
        String names = attributes.getValue("Extension-List");
Lines 161-167 Link Here
161
        if (names == null)
189
        if (names == null)
162
            return null;
190
            return null;
163
191
164
        ArrayList<Extension> extensionList = new ArrayList<>();
192
        Set<Extension> extensionList = new HashSet<>();
165
        names += " ";
193
        names += " ";
166
194
167
        while (true) {
195
        while (true) {
Lines 201-207 Link Here
201
     * @return List of available extensions, or null if the web application
229
     * @return List of available extensions, or null if the web application
202
     * does not bundle any extensions
230
     * does not bundle any extensions
203
     */
231
     */
204
    private ArrayList<Extension> getAvailableExtensions(Manifest manifest) {
232
    private Set<Extension> getAvailableExtensions(Manifest manifest) {
205
233
206
        Attributes attributes = manifest.getMainAttributes();
234
        Attributes attributes = manifest.getMainAttributes();
207
        String name = attributes.getValue("Extension-Name");
235
        String name = attributes.getValue("Extension-Name");
Lines 208-214 Link Here
208
        if (name == null)
236
        if (name == null)
209
            return null;
237
            return null;
210
238
211
        ArrayList<Extension> extensionList = new ArrayList<>();
239
        Set<Extension> extensionList = new HashSet<>();
212
240
213
        Extension extension = new Extension();
241
        Extension extension = new Extension();
214
        extension.setExtensionName(name);
242
        extension.setExtensionName(name);

Return to bug 52952