/*
* Copyright (c) OSGi Alliance (2005, 2015). 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.
Pattern matching is done according to the filter string matching rules.
Author: $Id: 8a79c1452911de1f8401fe88c1439fa666b004e2 $ @ThreadSafe
/**
* 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
* @author $Id: 8a79c1452911de1f8401fe88c1439fa666b004e2 $
*/
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.
Params: - bundle – The Bundle being evaluated.
- 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.
Returns: Condition object for the requested condition.
/**
* 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>() {
@Override
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 '*'.
Params: - value – unescaped value string.
Returns: escaped value string.
/**
* 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;
}
}