/* * Copyright (c) OSGi Alliance (2005, 2012). All Rights Reserved. * * Licensed 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 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.osgi.service.condpermadmin; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Dictionary; import java.util.Hashtable; import org.osgi.framework.Bundle; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; /** * Condition to test if the location of a bundle matches or does not match a * pattern. Since the bundle's location cannot be changed, this condition is * immutable. * * <p> * Pattern matching is done according to the filter string matching rules. * * @ThreadSafe * @version $Id: 43b6af515f7f92b5fe8fde94cc0b03dc7044807b $ */ public class BundleLocationCondition { private static final String CONDITION_TYPE = "org.osgi.service.condpermadmin.BundleLocationCondition"; /** * Constructs a condition that tries to match the passed Bundle's location * to the location pattern. * * @param bundle The Bundle being evaluated. * @param info The ConditionInfo from which to construct the condition. The * ConditionInfo must specify one or two arguments. The first * argument of the ConditionInfo specifies the location pattern * against which to match the bundle location. Matching is done * according to the filter string matching rules. Any '*' characters * in the first argument are used as wildcards when matching bundle * locations unless they are escaped with a '\' character. The * Condition is satisfied if the bundle location matches the pattern. * The second argument of the ConditionInfo is optional. If a second * argument is present and equal to "!", then the satisfaction of the * Condition is negated. That is, the Condition is satisfied if the * bundle location does NOT match the pattern. If the second argument * is present but does not equal "!", then the second argument is * ignored. * @return Condition object for the requested condition. */ static public Condition getCondition(final Bundle bundle, final ConditionInfo info) { if (!CONDITION_TYPE.equals(info.getType())) throw new IllegalArgumentException("ConditionInfo must be of type \"" + CONDITION_TYPE + "\""); String[] args = info.getArgs(); if (args.length != 1 && args.length != 2) throw new IllegalArgumentException("Illegal number of args: " + args.length); String bundleLocation = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return bundle.getLocation(); } }); Filter filter = null; try { filter = FrameworkUtil.createFilter("(location=" + escapeLocation(args[0]) + ")"); } catch (InvalidSyntaxException e) { // this should never happen, but just in case throw new RuntimeException("Invalid filter: " + e.getFilter(), e); } Dictionary<String, String> matchProps = new Hashtable<String, String>(2); matchProps.put("location", bundleLocation); boolean negate = (args.length == 2) ? "!".equals(args[1]) : false; return (negate ^ filter.match(matchProps)) ? Condition.TRUE : Condition.FALSE; } private BundleLocationCondition() { // private constructor to prevent objects of this type } /** * Escape the value string such that '(', ')' and '\' are escaped. The '\' * char is only escaped if it is not followed by a '*'. * * @param value unescaped value string. * @return escaped value string. */ private static String escapeLocation(final String value) { boolean escaped = false; int inlen = value.length(); int outlen = inlen << 1; /* inlen * 2 */ char[] output = new char[outlen]; value.getChars(0, inlen, output, inlen); int cursor = 0; for (int i = inlen; i < outlen; i++) { char c = output[i]; switch (c) { case '\\' : if (i + 1 < outlen && output[i + 1] == '*') break; case '(' : case ')' : output[cursor] = '\\'; cursor++; escaped = true; break; } output[cursor] = c; cursor++; } return escaped ? new String(output, 0, cursor) : value; } }