package org.osgi.service.indexer.impl; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.osgi.service.indexer.Builder; import org.osgi.service.indexer.Resource; import org.osgi.service.indexer.impl.types.ScalarType; import org.osgi.service.indexer.impl.types.SymbolicName; import org.osgi.service.indexer.impl.types.VersionKey; import org.osgi.service.indexer.impl.types.VersionRange; import org.osgi.service.indexer.impl.util.OSGiHeader; import org.osgi.service.indexer.impl.util.QuotedTokenizer; public class Util { public static SymbolicName getSymbolicName(Resource resource) throws IOException { Manifest manifest = resource.getManifest(); if (manifest == null) throw new IllegalArgumentException(String.format( "Cannot identify symbolic name for resource %s: manifest unavailable", resource.getLocation())); String header = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); if (header == null) throw new IllegalArgumentException( "Not an OSGi R4+ bundle: missing 'Bundle-SymbolicName' entry from manifest."); Map<String,Map<String,String>> map = OSGiHeader.parseHeader(header); if (map.size() != 1) throw new IllegalArgumentException("Invalid format for Bundle-SymbolicName header."); Entry<String,Map<String,String>> entry = map.entrySet().iterator().next(); return new SymbolicName(entry.getKey(), entry.getValue()); } public static Version getVersion(Resource resource) throws IOException { Manifest manifest = resource.getManifest(); if (manifest == null) throw new IllegalArgumentException(String .format("Cannot identify version for resource %s: manifest unavailable", resource.getLocation())); String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); Version version = (versionStr != null) ? new Version(versionStr) : Version.emptyVersion; return version; } public static MimeType getMimeType(Resource resource) throws IOException { Manifest manifest = resource.getManifest(); if (manifest == null) return MimeType.Jar; String bsn = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); if (bsn == null) return MimeType.Jar; String fragmentHost = manifest.getMainAttributes().getValue(Constants.FRAGMENT_HOST); if (fragmentHost != null) return MimeType.Fragment; return MimeType.Bundle; } public static void addVersionFilter(StringBuilder filter, VersionRange version, VersionKey key) { if (version.isRange()) { if (version.includeLow()) { filter.append("(").append(key.getKey()); filter.append(">="); filter.append(version.getLow()); filter.append(")"); } else { filter.append("(!(").append(key.getKey()); filter.append("<="); filter.append(version.getLow()); filter.append("))"); } if (version.includeHigh()) { filter.append("(").append(key.getKey()); filter.append("<="); filter.append(version.getHigh()); filter.append(")"); } else { filter.append("(!(").append(key.getKey()); filter.append(">="); filter.append(version.getHigh()); filter.append("))"); } } else { filter.append("(").append(key.getKey()).append(">="); filter.append(version); filter.append(")"); } } public static Object parseValue(String value, String typeStr) { Object result; if (typeStr.startsWith("List<")) { typeStr = typeStr.substring("List<".length(), typeStr.length() - 1); result = parseListValue(value, typeStr); } else { result = parseScalarValue(value, typeStr); } return result; } private static List< ? > parseListValue(String value, String typeStr) throws IllegalArgumentException { QuotedTokenizer tokenizer = new QuotedTokenizer(value, ","); String[] tokens = tokenizer.getTokens(); List<Object> result = new ArrayList<Object>(tokens.length); for (String token : tokens) result.add(parseScalarValue(token, typeStr)); return result; } private static Object parseScalarValue(String value, String typeStr) throws IllegalArgumentException { ScalarType type = Enum.valueOf(ScalarType.class, typeStr); switch (type) { case String : return value; case Long : return Long.valueOf(value); case Double : return Double.valueOf(value); case Version : return new Version(value); default : throw new IllegalArgumentException(typeStr); } } public static void copyAttribsToBuilder(Builder builder, Map<String,String> attribs) { for (Entry<String,String> attrib : attribs.entrySet()) { String key = attrib.getKey(); if (key.endsWith(":")) { String directiveName = key.substring(0, key.length() - 1); builder.addDirective(directiveName, attrib.getValue()); } else { int colonIndex = key.lastIndexOf(":"); String name; String typeStr; if (colonIndex > -1) { name = key.substring(0, colonIndex); typeStr = key.substring(colonIndex + 1); } else { name = key; typeStr = ScalarType.String.name(); } Object value = Util.parseValue(attrib.getValue(), typeStr); builder.addAttribute(name, value); } } } private static final Pattern MACRO_PATTERN = Pattern.compile("\\$\\{([^\\{\\}]*)\\}"); public static String readProcessedProperty(String propName, Properties... propsList) { String value = null; for (Properties props : propsList) { value = props.getProperty(propName); if (value != null) break; } if (value == null) return null; StringBuilder builder = new StringBuilder(value); Matcher matcher = MACRO_PATTERN.matcher(builder); while (matcher.find()) { int start = matcher.start(); int end = matcher.end(); String varName = matcher.group(1); String processed = readProcessedProperty(varName, propsList); if (processed != null) { builder.replace(start, end, processed); matcher.reset(builder); } } return builder.toString(); } /** * Returns a list of resource paths matching the glob pattern, e.g. {@code * OSGI-INF/blueprint/*.xml}. Wildcards only permitted in the final path * segment. * * @throws IOException */ public static final List<String> findMatchingPaths(Resource resource, String globPattern) throws IOException { String prefix; String suffix; int index = globPattern.lastIndexOf('/'); if (index == -1) { prefix = ""; suffix = globPattern; } else { int next = index + 1; prefix = globPattern.substring(0, next); if (globPattern.length() <= next) suffix = ""; else suffix = globPattern.substring(next); } String regexp = suffix.replaceAll("\\*", ".*"); Pattern pattern = Pattern.compile(regexp); List<String> children = resource.listChildren(prefix); if (children == null) return Collections.emptyList(); List<String> result = new ArrayList<String>(children.size()); for (String child : children) { if (pattern.matcher(child).matches()) result.add(prefix + child); } return result; } }