/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.aries.application.modelling.internal; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; import org.apache.aries.util.manifest.BundleManifest; import org.apache.aries.util.manifest.ManifestHeaderProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.aries.application.utils.AppConstants.*; /** * A bundle may contain a Bundle-Blueprint: header as per p649 of the v4 spec. If present, * this denotes where to look for blueprint xml files. We could use Bundle.findEntries() * to deal with the wildcards that the last entry in the list may contain, but our caller * is introspecting .jar files within an EBA and does not have access to Bundle objects, * so we need this extra support. Our caller needs to iterate over the files * within a jar in each case asking this class, 'is this a blueprint file'? * */ public class BundleBlueprintParser { public static final String DEFAULT_HEADER = "OSGI-INF/blueprint/*.xml"; private static final Logger logger = LoggerFactory.getLogger(BundleBlueprintParser.class); String _mfHeader = null; List<Path> _paths; static class Path { String directory; String filename; // This will either be a simple filename or 'null', in which case filenamePattern will be set Pattern filenamePattern; public Path (String d, String f) { directory = d; if (f.contains("*")) { filename = null; String pattern = f.replace(".", "\\."); pattern = pattern.replace("*", ".*"); filenamePattern = Pattern.compile(pattern); } else { filename = f; filenamePattern = null; } } /** * Match this Path object against a specific directory, file pair. Case sensitive. * @param dir Directory * @param fil Filename - may not contain a wildcard * @return true these match */ public boolean matches (String dir, String fil) { boolean match = false; if (!directory.equals(dir)) { match = false; } else if (filename != null) { match = (filename.equals(fil)); } else { match = filenamePattern.matcher(fil).matches(); } return match; } } /** * BundleBlueprintParser constructor * @param bundleMf BundleManifest to construct the parser from */ public BundleBlueprintParser (BundleManifest bundleMf) { String bundleBPHeader = bundleMf.getRawAttributes().getValue("Bundle-Blueprint"); setup (bundleBPHeader); } /** * BundleBlueprintParser alternative constructor * @param bundleBPHeader Bundle-Blueprint header to construct the parser from */ public BundleBlueprintParser (String bundleBPHeader) { setup (bundleBPHeader); } /** * Default constructor */ public BundleBlueprintParser () { setup(null); } static final boolean _blueprintHeaderMandatory; static { String blueprintHeaderMandatory = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("org.apache.aries.blueprint.header.mandatory", "false"); } }); _blueprintHeaderMandatory = blueprintHeaderMandatory.toLowerCase().equals("true"); } /** * @return true if this bundle might contain blueprint files */ public boolean mightContainBlueprint() { return _mfHeader != null && _mfHeader.trim().length() > 0; } private void setup (String bundleBPHeader) { _paths = new LinkedList <Path>(); if (bundleBPHeader == null) { if (_blueprintHeaderMandatory) { _mfHeader = null; } else { _mfHeader = DEFAULT_HEADER; } } else { _mfHeader = bundleBPHeader; } logger.debug("Bundle-Blueprint header: {}", _mfHeader); // Break this comma separated list up List<String> files = ManifestHeaderProcessor.split(_mfHeader, ","); clauses: for (String fileClause : files) { // we could be doing directives, so we split again, the clause can // have multiple paths with directives at the end. List<String> yetMoreFiles = ManifestHeaderProcessor.split(fileClause, ";"); for (String f : yetMoreFiles) { // if f has an = in it then we have hit the directive, which must // be at the end, we do not have any directives so we just continue // onto the next clause. if (f.contains("=")) continue clauses; // we need to make sure we have zero spaces here, otherwise stuff may // not be found. f = f.trim(); if (f.startsWith("\"") && f.endsWith("\"")) { f = f.substring(1,f.length()-1); } int index = f.lastIndexOf('/'); String path = ""; String file = f; if (index != -1) { path = f.substring(0, index); file = f.substring(index + 1); } _paths.add(new Path(path, file)); } } } /** * Iterate through the list of valid file patterns. Return true if this matches against * the header provided to the constructor. We're going to have to be case sensitive. * @param directory Directory name * @param filename File name * @return true if this is a blueprint file according to the Bundle-Blueprint header */ public boolean isBPFile (String directory, String filename) { logger.debug(LOG_ENTRY, "isBPFile", new Object[] {directory, filename}); boolean result=false; for (Path path: _paths) { if (path.matches(directory, filename)) { result = true; break; } } logger.debug(LOG_EXIT, "isBPFile", result); return result; } }