You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pa...@apache.org on 2020/09/07 17:06:25 UTC
[felix-dev] branch connect updated: Update to r8-core-final R8
release (passes the core ct)
This is an automated email from the ASF dual-hosted git repository.
pauls pushed a commit to branch connect
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/connect by this push:
new 29d6dd8 Update to r8-core-final R8 release (passes the core ct)
29d6dd8 is described below
commit 29d6dd86081d3836b195d7363e4646f9871120ec
Author: Karl Pauls <kp...@adobe.com>
AuthorDate: Mon Sep 7 19:06:10 2020 +0200
Update to r8-core-final R8 release (passes the core ct)
---
.../felix/framework/security/util/Permissions.java | 19 +-
framework/pom.xml | 3 +-
.../org/apache/felix/framework/DTOFactory.java | 5 +
.../java/org/apache/felix/framework/Felix.java | 7 +
.../felix/framework/ServiceRegistrationImpl.java | 10 +
.../java/org/osgi/framework/BundlePermission.java | 6 +-
.../org/osgi/framework/CapabilityPermission.java | 6 +-
.../main/java/org/osgi/framework/Constants.java | 12 +-
.../main/java/org/osgi/framework/FilterImpl.java | 1385 ++++++++++++++
.../java/org/osgi/framework/FrameworkEvent.java | 13 +-
.../java/org/osgi/framework/FrameworkUtil.java | 2024 +++++---------------
.../java/org/osgi/framework/PackagePermission.java | 6 +-
.../osgi/framework/PrototypeServiceFactory.java | 2 +-
.../java/org/osgi/framework/ServiceObjects.java | 2 +-
.../java/org/osgi/framework/ServicePermission.java | 6 +-
.../java/org/osgi/framework/ServiceReference.java | 59 +-
.../org/osgi/framework/connect/ConnectContent.java | 140 +-
.../framework/connect/ConnectFrameworkFactory.java | 7 +-
.../org/osgi/framework/connect/ConnectModule.java | 28 +-
.../framework/connect/FrameworkUtilHelper.java | 23 +-
.../osgi/framework/connect/ModuleConnector.java | 96 +-
.../org/osgi/framework/connect/package-info.java | 5 +-
.../java/org/osgi/framework/dto/BundleDTO.java | 2 +-
.../java/org/osgi/framework/dto/FrameworkDTO.java | 2 +-
.../osgi/framework/dto/ServiceReferenceDTO.java | 9 +-
.../java/org/osgi/framework/dto/package-info.java | 2 +-
.../osgi/framework/hooks/bundle/package-info.java | 2 +-
.../framework/hooks/resolver/package-info.java | 2 +-
.../osgi/framework/hooks/service/package-info.java | 2 +-
.../framework/hooks/weaving/WeavingException.java | 7 +-
.../osgi/framework/hooks/weaving/WeavingHook.java | 21 +-
.../hooks/weaving/WovenClassListener.java | 2 +-
.../osgi/framework/hooks/weaving/package-info.java | 2 +-
.../java/org/osgi/framework/launch/Framework.java | 35 +-
.../osgi/framework/launch/FrameworkFactory.java | 5 +-
.../org/osgi/framework/launch/package-info.java | 4 +-
.../osgi/framework/namespace/HostNamespace.java | 20 +-
.../framework/namespace/IdentityNamespace.java | 4 +-
.../osgi/framework/namespace/NativeNamespace.java | 8 +-
.../org/osgi/framework/namespace/package-info.java | 8 +-
.../main/java/org/osgi/framework/package-info.java | 8 +-
.../startlevel/dto/BundleStartLevelDTO.java | 2 +-
.../startlevel/dto/FrameworkStartLevelDTO.java | 2 +-
.../framework/startlevel/dto/package-info.java | 2 +-
.../osgi/framework/startlevel/package-info.java | 2 +-
.../framework/wiring/dto/BundleRevisionDTO.java | 2 +-
.../osgi/framework/wiring/dto/BundleWireDTO.java | 2 +-
.../osgi/framework/wiring/dto/BundleWiringDTO.java | 2 +-
.../osgi/framework/wiring/dto/package-info.java | 2 +-
.../org/osgi/framework/wiring/package-info.java | 2 +-
.../java/org/osgi/service/condition/Condition.java | 77 +
.../dto => service/condition}/package-info.java | 17 +-
framework/src/main/resources/default.properties | 5 +-
53 files changed, 2269 insertions(+), 1857 deletions(-)
diff --git a/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java b/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
index 4df53f2..801182e 100644
--- a/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
+++ b/framework.security/src/main/java/org/apache/felix/framework/security/util/Permissions.java
@@ -34,12 +34,16 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
+import java.util.PropertyPermission;
import org.apache.felix.framework.util.SecureAction;
import org.osgi.framework.AdminPermission;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.CapabilityPermission;
import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.PackagePermission;
+import org.osgi.framework.ServicePermission;
import org.osgi.framework.ServiceReference;
import org.osgi.service.packageadmin.ExportedPackage;
import org.osgi.service.packageadmin.PackageAdmin;
@@ -107,12 +111,15 @@ public final class Permissions
{
return new PermissionInfo[] {
IMPLICIT[0],
- new PermissionInfo(AdminPermission.class.getName(), "(id="
- + bundle.getBundleId() + ")", AdminPermission.METADATA),
- new PermissionInfo(AdminPermission.class.getName(), "(id="
- + bundle.getBundleId() + ")", AdminPermission.RESOURCE),
- new PermissionInfo(AdminPermission.class.getName(), "(id="
- + bundle.getBundleId() + ")", AdminPermission.CONTEXT) };
+ new PermissionInfo(PropertyPermission.class.getName(), "org.osgi.framework.*", "read"),
+ new PermissionInfo(
+ AdminPermission.class.getName(),
+ "(id=" + bundle.getBundleId() + ")",
+ AdminPermission.CLASS + "," + AdminPermission.METADATA + "," + AdminPermission.RESOURCE + "," + AdminPermission.CONTEXT),
+ new PermissionInfo(CapabilityPermission.class.getName(), "(|(capability.namespace=osgi.ee)(capability.namespace=osgi.native))", CapabilityPermission.REQUIRE),
+ new PermissionInfo(PackagePermission.class.getName(),"(package.name=java.*)",PackagePermission.IMPORT),
+ new PermissionInfo(ServicePermission.class.getName(),"org.osgi.service.condition.Condition", ServicePermission.GET)
+ };
}
public Permissions getPermissions(PermissionInfo[] permissionInfos)
diff --git a/framework/pom.xml b/framework/pom.xml
index e12b847..a5a6197 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -60,7 +60,8 @@
org.osgi.service.url;-split-package:=first,
org.osgi.service.resolver,
org.osgi.util.tracker;-split-package:=first,
- org.osgi.dto;-split-package:=first
+ org.osgi.dto;-split-package:=first,
+ org.osgi.service.condition;-split-package:=first
</Export-Package>
<Private-Package>org.apache.felix.framework.*, org.apache.felix.resolver.*</Private-Package>
<Import-Package>!*</Import-Package>
diff --git a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
index 0abcf9c..0a2a634 100644
--- a/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
+++ b/framework/src/main/java/org/apache/felix/framework/DTOFactory.java
@@ -61,6 +61,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.xml.ws.Service;
/**
* Creates various DTOs provided by the core framework.
@@ -120,6 +121,10 @@ public class DTOFactory
return null;
}
+ static ServiceReferenceDTO createDTO(ServiceReference ref) {
+ return createServiceReferenceDTO(ref);
+ }
+
private static BundleDTO createBundleDTO(Bundle bundle)
{
BundleDTO dto = new BundleDTO();
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index ba3263c..c3191de 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -5140,12 +5140,17 @@ public class Felix extends BundleImpl implements Framework
class SystemBundleActivator implements BundleActivator
{
+ private volatile ServiceRegistration<org.osgi.service.condition.Condition> m_reg;
@Override
public void start(BundleContext context) throws Exception
{
// Add the bundle activator for the url handler service.
m_activatorList.add(0, new URLHandlersActivator(m_configMap, Felix.this));
+
+ m_reg = context.registerService(org.osgi.service.condition.Condition.class, org.osgi.service.condition.Condition.INSTANCE,
+ FrameworkUtil.asDictionary(Collections.singletonMap(org.osgi.service.condition.Condition.CONDITION_ID, org.osgi.service.condition.Condition.CONDITION_ID_TRUE)));
+
// Start all activators.
for (Iterator<BundleActivator> iter = m_activatorList.iterator(); iter.hasNext(); )
{
@@ -5166,6 +5171,7 @@ public class Felix extends BundleImpl implements Framework
throwable);
}
}
+
}
@Override
@@ -5259,6 +5265,7 @@ public class Felix extends BundleImpl implements Framework
throwable);
}
}
+ m_reg.unregister();
m_activatorList.clear();
if (m_securityManager != null)
{
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 9169900..7a38c67 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -42,6 +42,7 @@ import org.osgi.framework.ServiceException;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.dto.ServiceReferenceDTO;
import org.osgi.framework.wiring.BundleCapability;
import org.osgi.framework.wiring.BundleRevision;
import org.osgi.framework.wiring.BundleWire;
@@ -699,6 +700,15 @@ class ServiceRegistrationImpl implements ServiceRegistration
public Dictionary<String, Object> getProperties() {
return new Hashtable<String, Object>(ServiceRegistrationImpl.this.m_propMap);
}
+
+ @Override
+ public Object adapt(Class type)
+ {
+ if (type == ServiceReferenceDTO.class) {
+ return DTOFactory.createDTO(this);
+ }
+ return null;
+ }
}
private class ServiceReferenceMap implements Map
diff --git a/framework/src/main/java/org/osgi/framework/BundlePermission.java b/framework/src/main/java/org/osgi/framework/BundlePermission.java
index 2371599..d4de480 100644
--- a/framework/src/main/java/org/osgi/framework/BundlePermission.java
+++ b/framework/src/main/java/org/osgi/framework/BundlePermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2019). 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.
@@ -58,7 +58,7 @@ import java.util.Map;
*
* @since 1.3
* @ThreadSafe
- * @author $Id: 7b0816059dc9b3e37f0375039bebbe5f0b18d998 $
+ * @author $Id: 7a45b1cb579ff9cfd1582f82436dd755ff805fba $
*/
public final class BundlePermission extends BasicPermission {
@@ -543,7 +543,7 @@ final class BundlePermissionCollection extends PermissionCollection {
// work our way up the tree...
int last;
int offset = requestedName.length() - 1;
- while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
requestedName = requestedName.substring(0, last + 1) + "*";
bp = pc.get(requestedName);
if (bp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/CapabilityPermission.java b/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
index 177ff97..60a5202 100644
--- a/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
+++ b/framework/src/main/java/org/osgi/framework/CapabilityPermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). 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.
@@ -47,7 +47,7 @@ import java.util.Set;
* </ul>
*
* @ThreadSafe
- * @author $Id: 8a38df04e56e9dcab7ea413ba69d4c4f05487c25 $
+ * @author $Id: c7bae50cab3a92ba810fcf983081c008f22a6bbd $
* @since 1.6
*/
@@ -714,7 +714,7 @@ final class CapabilityPermissionCollection extends PermissionCollection {
/* work our way up the tree... */
int last;
int offset = requestedName.length() - 1;
- while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
requestedName = requestedName.substring(0, last + 1) + "*";
cp = pc.get(requestedName);
if (cp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/Constants.java b/framework/src/main/java/org/osgi/framework/Constants.java
index 68dfb53..19c68b8 100644
--- a/framework/src/main/java/org/osgi/framework/Constants.java
+++ b/framework/src/main/java/org/osgi/framework/Constants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2000, 2018). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2020). 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.
@@ -29,7 +29,7 @@ import org.osgi.framework.launch.Framework;
* otherwise indicated.
*
* @since 1.1
- * @author $Id: 41e648afb56767a610f279a9c7effef47dfcbf2e $
+ * @author $Id: 57af8721d5f7e08f9b8a1d9f109a5ebb94bf9646 $
*/
@ProviderType
public interface Constants {
@@ -1025,7 +1025,6 @@ public interface Constants {
/**
* Framework environment property identifying whether the Framework supports
* bootclasspath extension bundles.
- *
* <p>
* If the value of this property is {@code true}, then the Framework
* supports bootclasspath extension bundles. The default value is
@@ -1035,6 +1034,7 @@ public interface Constants {
* {@code BundleContext.getProperty} method.
*
* @since 1.3
+ * @deprecated As of 1.10.
*/
String SUPPORTS_BOOTCLASSPATH_EXTENSION = "org.osgi.supports.bootclasspath.extension";
@@ -1574,7 +1574,7 @@ public interface Constants {
String SERVICE_IMPORTED_CONFIGS = "service.imported.configs";
/**
- * Service property identifying the intents that this service implement.
+ * Service property identifying the intents that this service implements.
* This property has a dual purpose:
* <ul>
* <li>A bundle can use this service property to notify the distribution
@@ -1833,8 +1833,8 @@ public interface Constants {
* Service property identifying the monotonically increasing change count of
* a service.
* <p>
- * A service may optional provide this property to indicate there has been a
- * change in some data provided by the service. The change count must be
+ * A service may provide this property to indicate there has been a change
+ * in some data provided by the service. The change count must be
* incremented with a positive value every time the data provided by the
* service is changed. The service announces the modified change count by
* updating its service properties with the new value for this service
diff --git a/framework/src/main/java/org/osgi/framework/FilterImpl.java b/framework/src/main/java/org/osgi/framework/FilterImpl.java
new file mode 100755
index 0000000..5d88a58
--- /dev/null
+++ b/framework/src/main/java/org/osgi/framework/FilterImpl.java
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (c) OSGi Alliance (2005, 2020). 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.framework;
+
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * RFC 1960-based Filter. Filter objects can be created by calling the
+ * constructor with the desired filter string. A Filter object can be called
+ * numerous times to determine if the match argument matches the filter string
+ * that was used to create the Filter object.
+ * <p>
+ * The syntax of a filter string is the string representation of LDAP search
+ * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
+ * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should be
+ * noted that RFC 2254: <i>A String Representation of LDAP Search Filters</i>
+ * (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes RFC 1960 but
+ * only adds extensible matching and is not applicable for this API.
+ * <p>
+ * The string representation of an LDAP search filter is defined by the
+ * following grammar. It uses a prefix format.
+ *
+ * <pre>
+ * <filter> ::= '(' <filtercomp> ')'
+ * <filtercomp> ::= <and> | <or> | <not> | <item>
+ * <and> ::= '&' <filterlist>
+ * <or> ::= '|' <filterlist>
+ * <not> ::= '!' <filter>
+ * <filterlist> ::= <filter> | <filter> <filterlist>
+ * <item> ::= <simple> | <present> | <substring>
+ * <simple> ::= <attr> <filtertype> <value>
+ * <filtertype> ::= <equal> | <approx> | <greater> | <less>
+ * <equal> ::= '='
+ * <approx> ::= '˜='
+ * <greater> ::= '>='
+ * <less> ::= '<='
+ * <present> ::= <attr> '=*'
+ * <substring> ::= <attr> '=' <initial> <any> <final>
+ * <initial> ::= NULL | <value>
+ * <any> ::= '*' <starval>
+ * <starval> ::= NULL | <value> '*' <starval>
+ * <final> ::= NULL | <value>
+ * </pre>
+ *
+ * {@code <attr>} is a string representing an attribute, or key, in the
+ * properties objects of the registered services. Attribute names are not case
+ * sensitive; that is cn and CN both refer to the same attribute.
+ * {@code <value>} is a string representing the value, or part of one, of
+ * a key in the properties objects of the registered services. If a
+ * {@code <value>} must contain one of the characters ' {@code *}' or
+ * '{@code (}' or '{@code )}', these characters should be escaped by preceding
+ * them with the backslash '{@code \}' character. Note that although both the
+ * {@code <substring>} and {@code <present>} productions can produce
+ * the {@code 'attr=*'} construct, this construct is used only to denote a
+ * presence filter.
+ * <p>
+ * Examples of LDAP filters are:
+ *
+ * <pre>
+ * "(cn=Babs Jensen)"
+ * "(!(cn=Tim Howes))"
+ * "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
+ * "(o=univ*of*mich*)"
+ * </pre>
+ * <p>
+ * The approximate match ({@code ~=}) is implementation specific but should at
+ * least ignore case and white space differences. Optional are codes like
+ * soundex or other smart "closeness" comparisons.
+ * <p>
+ * Comparison of values is not straightforward. Strings are compared differently
+ * than numbers and it is possible for a key to have multiple values. Note that
+ * that keys in the match argument must always be strings. The comparison is
+ * defined by the object type of the key's value. The following rules apply for
+ * comparison: <blockquote>
+ * <TABLE BORDER=0>
+ * <TR>
+ * <TD><b>Property Value Type </b></TD>
+ * <TD><b>Comparison Type</b></TD>
+ * </TR>
+ * <TR>
+ * <TD>String</TD>
+ * <TD>String comparison</TD>
+ * </TR>
+ * <TR valign=top>
+ * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
+ * <TD>numerical comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Character</TD>
+ * <TD>character comparison</TD>
+ * </TR>
+ * <TR>
+ * <TD>Boolean</TD>
+ * <TD>equality comparisons only</TD>
+ * </TR>
+ * <TR>
+ * <TD>[] (array)</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * <TR>
+ * <TD>Collection</TD>
+ * <TD>recursively applied to values</TD>
+ * </TR>
+ * </TABLE>
+ * Note: arrays of primitives are also supported. </blockquote> A filter matches
+ * a key that has multiple values if it matches at least one of those values.
+ * For example,
+ *
+ * <pre>
+ * Dictionary d = new Hashtable();
+ * d.put("cn", new String[] {
+ * "a", "b", "c"
+ * });
+ * </pre>
+ *
+ * d will match {@code (cn=a)} and also {@code (cn=b)}
+ * <p>
+ * A filter component that references a key having an unrecognizable data type
+ * will evaluate to {@code false} .
+ */
+abstract class FilterImpl implements Filter {
+ /* normalized filter string for Filter object */
+ private transient String filterString;
+
+ /**
+ * Creates a {@link FilterImpl} object. This filter object may be used to
+ * match a {@link ServiceReference} or a Dictionary.
+ * <p>
+ * If the filter cannot be parsed, an {@link InvalidSyntaxException} will be
+ * thrown with a human readable message where the filter became unparsable.
+ *
+ * @param filterString the filter string.
+ * @throws InvalidSyntaxException If the filter parameter contains an
+ * invalid filter string that cannot be parsed.
+ */
+ static FilterImpl createFilter(String filterString)
+ throws InvalidSyntaxException {
+ return new Parser(filterString).parse();
+ }
+
+ FilterImpl() {
+ // empty constructor for subclasses
+ }
+
+ /**
+ * Filter using a service's properties.
+ * <p>
+ * This {@code Filter} is executed using the keys and values of the
+ * referenced service's properties. The keys are looked up in a case
+ * insensitive manner.
+ *
+ * @param reference The reference to the service whose properties are used
+ * in the match.
+ * @return {@code true} if the service's properties match this
+ * {@code Filter}; {@code false} otherwise.
+ */
+ @Override
+ public boolean match(ServiceReference< ? > reference) {
+ return matches0((reference != null) ? new ServiceReferenceMap(reference)
+ : Collections.emptyMap());
+ }
+
+ /**
+ * Filter using a {@code Dictionary} with case insensitive key lookup. This
+ * {@code Filter} is executed using the specified {@code Dictionary}'s keys
+ * and values. The keys are looked up in a case insensitive manner.
+ *
+ * @param dictionary The {@code Dictionary} whose key/value pairs are used
+ * in the match.
+ * @return {@code true} if the {@code Dictionary}'s values match this
+ * filter; {@code false} otherwise.
+ * @throws IllegalArgumentException If {@code dictionary} contains case
+ * variants of the same key name.
+ */
+ @Override
+ public boolean match(Dictionary<String, ? > dictionary) {
+ return matches0(
+ (dictionary != null) ? new CaseInsensitiveMap(dictionary)
+ : Collections.emptyMap());
+ }
+
+ /**
+ * Filter using a {@code Dictionary}. This {@code Filter} is executed using
+ * the specified {@code Dictionary}'s keys and values. The keys are looked
+ * up in a normal manner respecting case.
+ *
+ * @param dictionary The {@code Dictionary} whose key/value pairs are used
+ * in the match.
+ * @return {@code true} if the {@code Dictionary}'s values match this
+ * filter; {@code false} otherwise.
+ * @since 1.3
+ */
+ @Override
+ public boolean matchCase(Dictionary<String, ? > dictionary) {
+ return matches0((dictionary != null) ? DictionaryMap.asMap(dictionary)
+ : Collections.emptyMap());
+ }
+
+ /**
+ * Filter using a {@code Map}. This {@code Filter} is executed using the
+ * specified {@code Map}'s keys and values. The keys are looked up in a
+ * normal manner respecting case.
+ *
+ * @param map The {@code Map} whose key/value pairs are used in the match.
+ * Maps with {@code null} key or values are not supported. A
+ * {@code null} value is considered not present to the filter.
+ * @return {@code true} if the {@code Map}'s values match this filter;
+ * {@code false} otherwise.
+ * @since 1.6
+ */
+ @Override
+ public boolean matches(Map<String, ? > map) {
+ return matches0((map != null) ? map : Collections.emptyMap());
+ }
+
+ abstract boolean matches0(Map<String, ? > map);
+
+ /**
+ * Returns this {@code Filter}'s filter string.
+ * <p>
+ * The filter string is normalized by removing whitespace which does not
+ * affect the meaning of the filter.
+ *
+ * @return This {@code Filter}'s filter string.
+ */
+ @Override
+ public String toString() {
+ String result = filterString;
+ if (result == null) {
+ filterString = result = normalize(new StringBuilder()).toString();
+ }
+ return result;
+ }
+
+ /**
+ * Returns this {@code Filter}'s normalized filter string.
+ * <p>
+ * The filter string is normalized by removing whitespace which does not
+ * affect the meaning of the filter.
+ *
+ * @return This {@code Filter}'s filter string.
+ */
+ abstract StringBuilder normalize(StringBuilder sb);
+
+ /**
+ * Compares this {@code Filter} to another {@code Filter}.
+ * <p>
+ * This implementation returns the result of calling
+ * {@code this.toString().equals(obj.toString()}.
+ *
+ * @param obj The object to compare against this {@code Filter}.
+ * @return If the other object is a {@code Filter} object, then returns the
+ * result of calling {@code this.toString().equals(obj.toString()};
+ * {@code false} otherwise.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof Filter)) {
+ return false;
+ }
+
+ return this.toString().equals(obj.toString());
+ }
+
+ /**
+ * Returns the hashCode for this {@code Filter}.
+ * <p>
+ * This implementation returns the result of calling
+ * {@code this.toString().hashCode()}.
+ *
+ * @return The hashCode of this {@code Filter}.
+ */
+ @Override
+ public int hashCode() {
+ return this.toString().hashCode();
+ }
+
+ static final class And extends FilterImpl {
+ private final FilterImpl[] operands;
+
+ And(FilterImpl[] operands) {
+ this.operands = operands;
+ }
+
+ @Override
+ boolean matches0(Map<String, ? > map) {
+ for (FilterImpl operand : operands) {
+ if (!operand.matches0(map)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append('&');
+ for (FilterImpl operand : operands) {
+ operand.normalize(sb);
+ }
+ return sb.append(')');
+ }
+ }
+
+ static final class Or extends FilterImpl {
+ private final FilterImpl[] operands;
+
+ Or(FilterImpl[] operands) {
+ this.operands = operands;
+ }
+
+ @Override
+ boolean matches0(Map<String, ? > map) {
+ for (FilterImpl operand : operands) {
+ if (operand.matches0(map)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append('|');
+ for (FilterImpl operand : operands) {
+ operand.normalize(sb);
+ }
+ return sb.append(')');
+ }
+ }
+
+ static final class Not extends FilterImpl {
+ private final FilterImpl operand;
+
+ Not(FilterImpl operand) {
+ this.operand = operand;
+ }
+
+ @Override
+ boolean matches0(Map<String, ? > map) {
+ return !operand.matches0(map);
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append('!');
+ operand.normalize(sb);
+ return sb.append(')');
+ }
+ }
+
+ static abstract class Item extends FilterImpl {
+ final String attr;
+
+ Item(String attr) {
+ this.attr = attr;
+ }
+
+ @Override
+ boolean matches0(Map<String, ? > map) {
+ return compare(map.get(attr));
+ }
+
+ private boolean compare(Object value1) {
+ if (value1 == null) {
+ return false;
+ }
+ if (value1 instanceof String) {
+ return compare_String((String) value1);
+ }
+ if (value1 instanceof Version) {
+ return compare_Version((Version) value1);
+ }
+
+ Class< ? > clazz = value1.getClass();
+ if (clazz.isArray()) {
+ Class< ? > type = clazz.getComponentType();
+ if (type.isPrimitive()) {
+ return compare_PrimitiveArray(type, value1);
+ }
+ return compare_ObjectArray((Object[]) value1);
+ }
+ if (value1 instanceof Collection< ? >) {
+ return compare_Collection((Collection< ? >) value1);
+ }
+ if (value1 instanceof Integer || value1 instanceof Long
+ || value1 instanceof Byte || value1 instanceof Short) {
+ return compare_Long(((Number) value1).longValue());
+ }
+ if (value1 instanceof Character) {
+ return compare_Character(((Character) value1).charValue());
+ }
+ if (value1 instanceof Float) {
+ return compare_Float(((Float) value1).floatValue());
+ }
+ if (value1 instanceof Double) {
+ return compare_Double(((Double) value1).doubleValue());
+ }
+ if (value1 instanceof Boolean) {
+ return compare_Boolean(((Boolean) value1).booleanValue());
+ }
+ if (value1 instanceof Comparable< ? >) {
+ @SuppressWarnings("unchecked")
+ Comparable<Object> comparable = (Comparable<Object>) value1;
+ return compare_Comparable(comparable);
+ }
+ return compare_Unknown(value1);
+ }
+
+ private boolean compare_Collection(Collection< ? > collection) {
+ for (Object value1 : collection) {
+ if (compare(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_ObjectArray(Object[] array) {
+ for (Object value1 : array) {
+ if (compare(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean compare_PrimitiveArray(Class< ? > type,
+ Object primarray) {
+ if (Integer.TYPE.isAssignableFrom(type)) {
+ int[] array = (int[]) primarray;
+ for (int value1 : array) {
+ if (compare_Long(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Long.TYPE.isAssignableFrom(type)) {
+ long[] array = (long[]) primarray;
+ for (long value1 : array) {
+ if (compare_Long(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Byte.TYPE.isAssignableFrom(type)) {
+ byte[] array = (byte[]) primarray;
+ for (byte value1 : array) {
+ if (compare_Long(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Short.TYPE.isAssignableFrom(type)) {
+ short[] array = (short[]) primarray;
+ for (short value1 : array) {
+ if (compare_Long(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Character.TYPE.isAssignableFrom(type)) {
+ char[] array = (char[]) primarray;
+ for (char value1 : array) {
+ if (compare_Character(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Float.TYPE.isAssignableFrom(type)) {
+ float[] array = (float[]) primarray;
+ for (float value1 : array) {
+ if (compare_Float(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Double.TYPE.isAssignableFrom(type)) {
+ double[] array = (double[]) primarray;
+ for (double value1 : array) {
+ if (compare_Double(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (Boolean.TYPE.isAssignableFrom(type)) {
+ boolean[] array = (boolean[]) primarray;
+ for (boolean value1 : array) {
+ if (compare_Boolean(value1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+
+ boolean compare_String(String string) {
+ return false;
+ }
+
+ boolean compare_Version(Version value1) {
+ return false;
+ }
+
+ boolean compare_Comparable(Comparable<Object> value1) {
+ return false;
+ }
+
+ boolean compare_Unknown(Object value1) {
+ return false;
+ }
+
+ boolean compare_Boolean(boolean boolval) {
+ return false;
+ }
+
+ boolean compare_Character(char charval) {
+ return false;
+ }
+
+ boolean compare_Double(double doubleval) {
+ return false;
+ }
+
+ boolean compare_Float(float floatval) {
+ return false;
+ }
+
+ boolean compare_Long(long longval) {
+ return false;
+ }
+
+ /**
+ * Encode the value string such that '(', '*', ')' and '\' are escaped.
+ *
+ * @param value unencoded value string.
+ */
+ static StringBuilder encodeValue(StringBuilder sb, String value) {
+ for (int i = 0, len = value.length(); i < len; i++) {
+ char c = value.charAt(i);
+ switch (c) {
+ case '(' :
+ case '*' :
+ case ')' :
+ case '\\' :
+ sb.append('\\');
+ // FALL-THROUGH
+ default :
+ sb.append(c);
+ break;
+ }
+ }
+ return sb;
+ }
+ }
+
+ static final class Present extends Item {
+ Present(String attr) {
+ super(attr);
+ }
+
+ @Override
+ boolean matches0(Map<String, ? > map) {
+ return map.get(attr) != null;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ return sb.append('(')
+ .append(attr)
+ .append('=')
+ .append('*')
+ .append(')');
+ }
+ }
+
+ static final class Substring extends Item {
+ final String[] substrings;
+
+ Substring(String attr, String[] substrings) {
+ super(attr);
+ this.substrings = substrings;
+ }
+
+ @Override
+ boolean compare_String(String string) {
+ int pos = 0;
+ for (int i = 0, size = substrings.length; i < size; i++) {
+ String substr = substrings[i];
+ if (i + 1 < size) /* if this is not that last substr */ {
+ if (substr == null) /* * */ {
+ String substr2 = substrings[i + 1];
+ if (substr2 == null) /* ** */
+ continue; /* ignore first star */
+ /* xxx */
+ int index = string.indexOf(substr2, pos);
+ if (index == -1) {
+ return false;
+ }
+ pos = index + substr2.length();
+ if (i + 2 < size) // if there are more
+ // substrings, increment
+ // over the string we just
+ // matched; otherwise need
+ // to do the last substr
+ // check
+ i++;
+ } else /* xxx */ {
+ int len = substr.length();
+ if (string.regionMatches(pos, substr, 0, len)) {
+ pos += len;
+ } else {
+ return false;
+ }
+ }
+ } else /* last substr */ {
+ if (substr == null) /* * */ {
+ return true;
+ }
+ /* xxx */
+ return string.endsWith(substr);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append(attr).append('=');
+ for (String substr : substrings) {
+ if (substr == null) /* * */ {
+ sb.append('*');
+ } else /* xxx */ {
+ encodeValue(sb, substr);
+ }
+ }
+ return sb.append(')');
+ }
+ }
+
+ static class Equal extends Item {
+ final String value;
+ private Object cached;
+
+ Equal(String attr, String value) {
+ super(attr);
+ this.value = value;
+ }
+
+ private <T> T convert(Class<T> type, Function<String, ? extends T> converter) {
+ @SuppressWarnings("unchecked")
+ T converted = (T) cached;
+ if ((converted != null) && type.isInstance(converted)) {
+ return converted;
+ }
+ cached = converted = converter.apply(value.trim());
+ return converted;
+ }
+
+ boolean comparison(int compare) {
+ return compare == 0;
+ }
+
+ @Override
+ boolean compare_String(String string) {
+ return comparison((string == value) ? 0 : string.compareTo(value));
+ }
+
+ @Override
+ boolean compare_Version(Version value1) {
+ try {
+ Version version2 = convert(Version.class, Version::valueOf);
+ return comparison(value1.compareTo(version2));
+ } catch (Exception e) {
+ // if the valueOf or compareTo method throws an exception
+ return false;
+ }
+ }
+
+ @Override
+ boolean compare_Boolean(boolean boolval) {
+ boolean boolval2 = convert(Boolean.class, Boolean::valueOf).booleanValue();
+ return comparison(Boolean.compare(boolval, boolval2));
+ }
+
+ @Override
+ boolean compare_Character(char charval) {
+ char charval2;
+ try {
+ charval2 = value.charAt(0);
+ } catch (IndexOutOfBoundsException e) {
+ return false;
+ }
+ return comparison(Character.compare(charval, charval2));
+ }
+
+ @Override
+ boolean compare_Double(double doubleval) {
+ double doubleval2;
+ try {
+ doubleval2 = convert(Double.class, Double::valueOf).doubleValue();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ return comparison(Double.compare(doubleval, doubleval2));
+ }
+
+ @Override
+ boolean compare_Float(float floatval) {
+ float floatval2;
+ try {
+ floatval2 = convert(Float.class, Float::valueOf).floatValue();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ return comparison(Float.compare(floatval, floatval2));
+ }
+
+ @Override
+ boolean compare_Long(long longval) {
+ long longval2;
+ try {
+ longval2 = convert(Long.class, Long::valueOf).longValue();
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ return comparison(Long.compare(longval, longval2));
+ }
+
+ @Override
+ boolean compare_Comparable(Comparable<Object> value1) {
+ Object value2 = valueOf(value1.getClass());
+ if (value2 == null) {
+ return false;
+ }
+ try {
+ return comparison(value1.compareTo(value2));
+ } catch (Exception e) {
+ // if the compareTo method throws an exception; return false
+ return false;
+ }
+ }
+
+ @Override
+ boolean compare_Unknown(Object value1) {
+ Object value2 = valueOf(value1.getClass());
+ if (value2 == null) {
+ return false;
+ }
+ try {
+ return value1.equals(value2);
+ } catch (Exception e) {
+ // if the equals method throws an exception; return false
+ return false;
+ }
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append(attr).append('=');
+ return encodeValue(sb, value).append(')');
+ }
+
+ Object valueOf(Class< ? > target) {
+ do {
+ Method method;
+ try {
+ method = target.getMethod("valueOf", String.class);
+ } catch (NoSuchMethodException e) {
+ break;
+ }
+ if (Modifier.isStatic(method.getModifiers())
+ && target.isAssignableFrom(method.getReturnType())) {
+ setAccessible(method);
+ try {
+ return method.invoke(null, value.trim());
+ } catch (Error e) {
+ throw e;
+ } catch (Throwable e) {
+ return null;
+ }
+ }
+ } while (false);
+
+ do {
+ Constructor< ? > constructor;
+ try {
+ constructor = target.getConstructor(String.class);
+ } catch (NoSuchMethodException e) {
+ break;
+ }
+ setAccessible(constructor);
+ try {
+ return constructor.newInstance(value.trim());
+ } catch (Error e) {
+ throw e;
+ } catch (Throwable e) {
+ return null;
+ }
+ } while (false);
+
+ return null;
+ }
+
+ private static void setAccessible(AccessibleObject accessible) {
+ if (!accessible.isAccessible()) {
+ AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+ accessible.setAccessible(true);
+ return null;
+ });
+ }
+ }
+ }
+
+ static final class LessEqual extends Equal {
+ LessEqual(String attr, String value) {
+ super(attr, value);
+ }
+
+ @Override
+ boolean comparison(int compare) {
+ return compare <= 0;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append(attr).append('<').append('=');
+ return encodeValue(sb, value).append(')');
+ }
+ }
+
+ static final class GreaterEqual extends Equal {
+ GreaterEqual(String attr, String value) {
+ super(attr, value);
+ }
+
+ @Override
+ boolean comparison(int compare) {
+ return compare >= 0;
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append(attr).append('>').append('=');
+ return encodeValue(sb, value).append(')');
+ }
+ }
+
+ static final class Approx extends Equal {
+ final String approx;
+
+ Approx(String attr, String value) {
+ super(attr, value);
+ this.approx = approxString(value);
+ }
+
+ @Override
+ boolean compare_String(String string) {
+ string = approxString(string);
+ return string.equalsIgnoreCase(approx);
+ }
+
+ @Override
+ boolean compare_Character(char charval) {
+ char charval2;
+ try {
+ charval2 = approx.charAt(0);
+ } catch (IndexOutOfBoundsException e) {
+ return false;
+ }
+ return (charval == charval2)
+ || (Character.toUpperCase(charval) == Character
+ .toUpperCase(charval2))
+ || (Character.toLowerCase(charval) == Character
+ .toLowerCase(charval2));
+ }
+
+ @Override
+ StringBuilder normalize(StringBuilder sb) {
+ sb.append('(').append(attr).append('~').append('=');
+ return encodeValue(sb, approx).append(')');
+ }
+
+ /**
+ * Map a string for an APPROX (~=) comparison. This implementation
+ * removes white spaces. This is the minimum implementation allowed by
+ * the OSGi spec.
+ *
+ * @param input Input string.
+ * @return String ready for APPROX comparison.
+ */
+ static String approxString(String input) {
+ boolean changed = false;
+ char[] output = input.toCharArray();
+ int cursor = 0;
+ for (char c : output) {
+ if (Character.isWhitespace(c)) {
+ changed = true;
+ continue;
+ }
+
+ output[cursor] = c;
+ cursor++;
+ }
+
+ return changed ? new String(output, 0, cursor) : input;
+ }
+ }
+
+ /**
+ * Parser class for OSGi filter strings. This class parses the complete
+ * filter string and builds a tree of FilterImpl objects rooted at the
+ * parent.
+ */
+ static private final class Parser {
+ private final String filterstring;
+ private final char[] filterChars;
+ private int pos;
+
+ Parser(String filterstring) {
+ this.filterstring = filterstring;
+ filterChars = filterstring.toCharArray();
+ pos = 0;
+ }
+
+ FilterImpl parse() throws InvalidSyntaxException {
+ FilterImpl filter;
+ try {
+ filter = parse_filter();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new InvalidSyntaxException("Filter ended abruptly",
+ filterstring, e);
+ }
+
+ if (pos != filterChars.length) {
+ throw new InvalidSyntaxException(
+ "Extraneous trailing characters: "
+ + filterstring.substring(pos),
+ filterstring);
+ }
+ return filter;
+ }
+
+ private FilterImpl parse_filter() throws InvalidSyntaxException {
+ FilterImpl filter;
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ throw new InvalidSyntaxException(
+ "Missing '(': " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ pos++;
+
+ filter = parse_filtercomp();
+
+ skipWhiteSpace();
+
+ if (filterChars[pos] != ')') {
+ throw new InvalidSyntaxException(
+ "Missing ')': " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ pos++;
+
+ skipWhiteSpace();
+
+ return filter;
+ }
+
+ private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ char c = filterChars[pos];
+
+ switch (c) {
+ case '&' : {
+ pos++;
+ return parse_and();
+ }
+ case '|' : {
+ pos++;
+ return parse_or();
+ }
+ case '!' : {
+ pos++;
+ return parse_not();
+ }
+ }
+ return parse_item();
+ }
+
+ private FilterImpl parse_and() throws InvalidSyntaxException {
+ int lookahead = pos;
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ pos = lookahead - 1;
+ return parse_item();
+ }
+
+ List<FilterImpl> operands = new ArrayList<>(10);
+
+ while (filterChars[pos] == '(') {
+ FilterImpl child = parse_filter();
+ operands.add(child);
+ }
+
+ return new FilterImpl.And(operands.toArray(new FilterImpl[0]));
+ }
+
+ private FilterImpl parse_or() throws InvalidSyntaxException {
+ int lookahead = pos;
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ pos = lookahead - 1;
+ return parse_item();
+ }
+
+ List<FilterImpl> operands = new ArrayList<>(10);
+
+ while (filterChars[pos] == '(') {
+ FilterImpl child = parse_filter();
+ operands.add(child);
+ }
+
+ return new FilterImpl.Or(operands.toArray(new FilterImpl[0]));
+ }
+
+ private FilterImpl parse_not() throws InvalidSyntaxException {
+ int lookahead = pos;
+ skipWhiteSpace();
+
+ if (filterChars[pos] != '(') {
+ pos = lookahead - 1;
+ return parse_item();
+ }
+
+ FilterImpl child = parse_filter();
+
+ return new FilterImpl.Not(child);
+ }
+
+ private FilterImpl parse_item() throws InvalidSyntaxException {
+ String attr = parse_attr();
+
+ skipWhiteSpace();
+
+ switch (filterChars[pos]) {
+ case '~' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl.Approx(attr, parse_value());
+ }
+ break;
+ }
+ case '>' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl.GreaterEqual(attr, parse_value());
+ }
+ break;
+ }
+ case '<' : {
+ if (filterChars[pos + 1] == '=') {
+ pos += 2;
+ return new FilterImpl.LessEqual(attr, parse_value());
+ }
+ break;
+ }
+ case '=' : {
+ if (filterChars[pos + 1] == '*') {
+ int oldpos = pos;
+ pos += 2;
+ skipWhiteSpace();
+ if (filterChars[pos] == ')') {
+ return new FilterImpl.Present(attr);
+ }
+ pos = oldpos;
+ }
+
+ pos++;
+ String[] substrings = parse_substring();
+
+ int length = substrings.length;
+ if (length == 0) {
+ return new FilterImpl.Equal(attr, "");
+ }
+ if (length == 1) {
+ String single = substrings[0];
+ if (single != null) {
+ return new FilterImpl.Equal(attr, single);
+ }
+ }
+ return new FilterImpl.Substring(attr, substrings);
+ }
+ }
+
+ throw new InvalidSyntaxException(
+ "Invalid operator: " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ private String parse_attr() throws InvalidSyntaxException {
+ skipWhiteSpace();
+
+ int begin = pos;
+ int end = pos;
+
+ char c = filterChars[pos];
+
+ while (c != '~' && c != '<' && c != '>' && c != '=' && c != '('
+ && c != ')') {
+ pos++;
+
+ if (!Character.isWhitespace(c)) {
+ end = pos;
+ }
+
+ c = filterChars[pos];
+ }
+
+ int length = end - begin;
+
+ if (length == 0) {
+ throw new InvalidSyntaxException(
+ "Missing attr: " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ return new String(filterChars, begin, length);
+ }
+
+ private String parse_value() throws InvalidSyntaxException {
+ StringBuilder sb = new StringBuilder(filterChars.length - pos);
+
+ parseloop: while (true) {
+ char c = filterChars[pos];
+
+ switch (c) {
+ case ')' : {
+ break parseloop;
+ }
+
+ case '(' : {
+ throw new InvalidSyntaxException(
+ "Invalid value: " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ case '\\' : {
+ pos++;
+ c = filterChars[pos];
+ /* fall through into default */
+ }
+
+ default : {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ if (sb.length() == 0) {
+ throw new InvalidSyntaxException(
+ "Missing value: " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ return sb.toString();
+ }
+
+ private String[] parse_substring() throws InvalidSyntaxException {
+ StringBuilder sb = new StringBuilder(filterChars.length - pos);
+
+ List<String> operands = new ArrayList<>(10);
+
+ parseloop: while (true) {
+ char c = filterChars[pos];
+
+ switch (c) {
+ case ')' : {
+ if (sb.length() > 0) {
+ operands.add(sb.toString());
+ }
+
+ break parseloop;
+ }
+
+ case '(' : {
+ throw new InvalidSyntaxException(
+ "Invalid value: " + filterstring.substring(pos),
+ filterstring);
+ }
+
+ case '*' : {
+ if (sb.length() > 0) {
+ operands.add(sb.toString());
+ }
+
+ sb.setLength(0);
+
+ operands.add(null);
+ pos++;
+
+ break;
+ }
+
+ case '\\' : {
+ pos++;
+ c = filterChars[pos];
+ /* fall through into default */
+ }
+
+ default : {
+ sb.append(c);
+ pos++;
+ break;
+ }
+ }
+ }
+
+ return operands.toArray(new String[0]);
+ }
+
+ private void skipWhiteSpace() {
+ for (int length = filterChars.length; (pos < length)
+ && Character.isWhitespace(filterChars[pos]);) {
+ pos++;
+ }
+ }
+ }
+
+ /**
+ * This Map is used for key lookup during filter evaluation. This Map
+ * implementation only supports the get operation using a String key as no
+ * other operations are used by the Filter implementation.
+ */
+ private static class DictionaryMap extends AbstractMap<String,Object>
+ implements Map<String,Object> {
+ static Map<String, ? > asMap(Dictionary<String, ? > dictionary) {
+ if (dictionary instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map<String, ? > coerced = (Map<String, ? >) dictionary;
+ return coerced;
+ }
+ return new DictionaryMap(dictionary);
+ }
+
+ private final Dictionary<String, ? > dictionary;
+
+ DictionaryMap(Dictionary<String, ? > dictionary) {
+ this.dictionary = requireNonNull(dictionary);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return dictionary.get(key);
+ }
+
+ @Override
+ public Set<Entry<String,Object>> entrySet() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * This Map is used for case-insensitive key lookup during filter
+ * evaluation. This Map implementation only supports the get operation using
+ * a String key as no other operations are used by the Filter
+ * implementation.
+ */
+ private static final class CaseInsensitiveMap
+ extends DictionaryMap implements Map<String,Object> {
+ private final String[] keys;
+
+ /**
+ * Create a case insensitive map from the specified dictionary.
+ *
+ * @param dictionary
+ * @throws IllegalArgumentException If {@code dictionary} contains case
+ * variants of the same key name.
+ */
+ CaseInsensitiveMap(Dictionary<String, ? > dictionary) {
+ super(dictionary);
+ List<String> keyList = new ArrayList<>(dictionary.size());
+ for (Enumeration< ? > e = dictionary.keys(); e.hasMoreElements();) {
+ Object k = e.nextElement();
+ if (k instanceof String) {
+ String key = (String) k;
+ for (String i : keyList) {
+ if (key.equalsIgnoreCase(i)) {
+ throw new IllegalArgumentException();
+ }
+ }
+ keyList.add(key);
+ }
+ }
+ this.keys = keyList.toArray(new String[0]);
+ }
+
+ @Override
+ public Object get(Object o) {
+ String k = (String) o;
+ for (String key : keys) {
+ if (key.equalsIgnoreCase(k)) {
+ return super.get(key);
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * This Map is used for key lookup from a ServiceReference during filter
+ * evaluation. This Map implementation only supports the get operation using
+ * a String key as no other operations are used by the Filter
+ * implementation.
+ */
+ private static final class ServiceReferenceMap
+ extends AbstractMap<String,Object> implements Map<String,Object> {
+ private final ServiceReference< ? > reference;
+
+ ServiceReferenceMap(ServiceReference< ? > reference) {
+ this.reference = requireNonNull(reference);
+ }
+
+ @Override
+ public Object get(Object key) {
+ return reference.getProperty((String) key);
+ }
+
+ @Override
+ public Set<Entry<String,Object>> entrySet() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkEvent.java b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
index 84c63f1..9156a79 100644
--- a/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
+++ b/framework/src/main/java/org/osgi/framework/FrameworkEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2004, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2004, 2020). 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.
@@ -34,7 +34,7 @@ import org.osgi.framework.wiring.FrameworkWiring;
*
* @Immutable
* @see FrameworkListener
- * @author $Id: b3072b2d058e70389a52e342ed5f8647b930b8f1 $
+ * @author $Id: bcff0614c20b454723977355f99486ca01ee89ea $
*/
public class FrameworkEvent extends EventObject {
@@ -148,13 +148,13 @@ public class FrameworkEvent extends EventObject {
/**
* The Framework has stopped and the boot class path has changed.
- *
* <p>
* This event is fired when the Framework has been stopped because of a stop
* operation on the system bundle and a bootclasspath extension bundle has
* been installed or updated. The source of this event is the System Bundle.
*
* @since 1.5
+ * @deprecated As of 1.10.
*/
public final static int STOPPED_BOOTCLASSPATH_MODIFIED = 0x00000100;
@@ -173,9 +173,9 @@ public class FrameworkEvent extends EventObject {
* The Framework has stopped and the framework requires a new class loader
* to restart.
* <p>
- * This event is fired when the Framework has been stopped because of a stop
- * operation on the system bundle and the framework requires a new class
- * loader to be used to restart. For example, if a framework extension
+ * This event is fired when the Framework has been stopped because of a
+ * refresh operation on the system bundle and the framework requires a new
+ * class loader to be used to restart. For example, if a framework extension
* bundle has been refreshed. The source of this event is the System Bundle.
*
* @since 1.9
@@ -244,7 +244,6 @@ public class FrameworkEvent extends EventObject {
* <li>{@link #PACKAGES_REFRESHED}</li>
* <li>{@link #STARTLEVEL_CHANGED}</li>
* <li>{@link #STOPPED}</li>
- * <li>{@link #STOPPED_BOOTCLASSPATH_MODIFIED}</li>
* <li>{@link #STOPPED_UPDATE}</li>
* <li>{@link #WAIT_TIMEDOUT}</li>
* </ul>
diff --git a/framework/src/main/java/org/osgi/framework/FrameworkUtil.java b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
index d50bea5..edc8008 100644
--- a/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
+++ b/framework/src/main/java/org/osgi/framework/FrameworkUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2005, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2005, 2020). 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.
@@ -16,22 +16,20 @@
package org.osgi.framework;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
+import static java.util.Objects.requireNonNull;
+
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.AbstractMap;
+import java.util.AbstractSet;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
@@ -49,7 +47,7 @@ import org.osgi.framework.connect.FrameworkUtilHelper;
*
* @since 1.3
* @ThreadSafe
- * @author $Id: 90d50e4d3f69b659bed23beedab6e54b31b96d76 $
+ * @author $Id: 71423feb17277b685e6d5d7864907e768da8cd0b $
*/
public class FrameworkUtil {
/**
@@ -82,7 +80,7 @@ public class FrameworkUtil {
* @see Filter
*/
public static Filter createFilter(String filter) throws InvalidSyntaxException {
- return FilterImpl.newInstance(filter);
+ return FilterImpl.createFilter(filter);
}
/**
@@ -168,1592 +166,99 @@ public class FrameworkUtil {
* US.
* </p>
*
- * <pre>
- * * ; ou=S & V, o=Tweety Inc., c=US
- * </pre>
- * <p>
- * The wildcard ('*') matches zero or one DN in the chain, however,
- * sometimes it is necessary to match a longer chain. The minus sign (
- * {@code '-'} \u002D) represents zero or more DNs, whereas the asterisk
- * only represents a single DN. For example, to match a DN where the Tweety
- * Inc. is in the DN chain, use the following expression:
- * </p>
- *
- * <pre>
- * - ; *, o=Tweety Inc., c=US
- * </pre>
- *
- * @param matchPattern The pattern against which to match the DN chain.
- * @param dnChain The DN chain to match against the specified pattern. Each
- * element of the chain must be of type {@code String} and use the
- * format defined in <a
- * href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
- * @return {@code true} If the pattern matches the DN chain; otherwise
- * {@code false} is returned.
- * @throws IllegalArgumentException If the specified match pattern or DN
- * chain is invalid.
- * @since 1.5
- */
- public static boolean matchDistinguishedNameChain(String matchPattern, List<String> dnChain) {
- return DNChainMatching.match(matchPattern, dnChain);
- }
-
- /**
- * Return a {@code Bundle} for the specified bundle class loader.
- *
- * @param bundleClassLoader A bundle class loader.
- * @return An Optional containing {@code Bundle} for the specified bundle
- * class loader or an empty Optional if the specified class loader
- * is not associated with a specific bundle.
- * @since 1.10
- */
- public static Optional<Bundle> getBundle(ClassLoader bundleClassLoader) {
- return Optional
- .ofNullable((bundleClassLoader instanceof BundleReference)
- ? ((BundleReference) bundleClassLoader).getBundle()
- : null);
- }
-
- /**
- * Return a {@code Bundle} for the specified bundle class.
- *
- * @param classFromBundle A class defined by a bundle.
- * @return A {@code Bundle} for the specified bundle class or {@code null}
- * if the specified class was not defined by a bundle.
- * @since 1.5
- */
- public static Bundle getBundle(Class< ? > classFromBundle) {
- // We use doPriv since the caller may not have permission
- // to call getClassLoader.
- Optional<ClassLoader> cl = Optional
- .ofNullable(AccessController.doPrivileged(
- (PrivilegedAction<ClassLoader>) () -> classFromBundle
- .getClassLoader()));
-
- return cl.flatMap(FrameworkUtil::getBundle)
- .orElseGet(() -> helpers.stream()
- .map(helper -> helper.getBundle(classFromBundle))
- .filter(Optional::isPresent)
- .map(Optional::get)
- .findFirst()
- .orElse(null));
- }
-
- private final static List<FrameworkUtilHelper> helpers;
- static {
- List<FrameworkUtilHelper> l = new ArrayList<>();
- try {
- ServiceLoader<FrameworkUtilHelper> helperLoader = AccessController
- .doPrivileged(
- (PrivilegedAction<ServiceLoader<FrameworkUtilHelper>>) () -> ServiceLoader
- .load(FrameworkUtilHelper.class,
- FrameworkUtilHelper.class
- .getClassLoader()));
- helperLoader.forEach(l::add);
- } catch (Throwable error) {
- // try hard not to fail static <clinit>
- try {
- Thread t = Thread.currentThread();
- t.getUncaughtExceptionHandler().uncaughtException(t, error);
- } catch (Throwable ignored) {
- // we ignore this
- }
- }
- helpers = Collections.unmodifiableList(l);
- }
-
- /**
- * RFC 1960-based Filter. Filter objects can be created by calling the
- * constructor with the desired filter string. A Filter object can be called
- * numerous times to determine if the match argument matches the filter
- * string that was used to create the Filter object.
- *
- * <p>
- * The syntax of a filter string is the string representation of LDAP search
- * filters as defined in RFC 1960: <i>A String Representation of LDAP Search
- * Filters</i> (available at http://www.ietf.org/rfc/rfc1960.txt). It should
- * be noted that RFC 2254: <i>A String Representation of LDAP Search
- * Filters</i> (available at http://www.ietf.org/rfc/rfc2254.txt) supersedes
- * RFC 1960 but only adds extensible matching and is not applicable for this
- * API.
- *
- * <p>
- * The string representation of an LDAP search filter is defined by the
- * following grammar. It uses a prefix format.
- *
- * <pre>
- * <filter> ::= '(' <filtercomp> ')'
- * <filtercomp> ::= <and> | <or> | <not> | <item>
- * <and> ::= '&' <filterlist>
- * <or> ::= '|' <filterlist>
- * <not> ::= '!' <filter>
- * <filterlist> ::= <filter> | <filter> <filterlist>
- * <item> ::= <simple> | <present> | <substring>
- * <simple> ::= <attr> <filtertype> <value>
- * <filtertype> ::= <equal> | <approx> | <greater> | <less>
- * <equal> ::= '='
- * <approx> ::= '˜='
- * <greater> ::= '>='
- * <less> ::= '<='
- * <present> ::= <attr> '=*'
- * <substring> ::= <attr> '=' <initial> <any> <final>
- * <initial> ::= NULL | <value>
- * <any> ::= '*' <starval>
- * <starval> ::= NULL | <value> '*' <starval>
- * <final> ::= NULL | <value>
- * </pre>
- *
- * {@code <attr>} is a string representing an attribute, or key, in
- * the properties objects of the registered services. Attribute names are
- * not case sensitive; that is cn and CN both refer to the same attribute.
- * {@code <value>} is a string representing the value, or part of one,
- * of a key in the properties objects of the registered services. If a
- * {@code <value>} must contain one of the characters ' {@code *}' or
- * '{@code (}' or '{@code )}', these characters should be escaped by
- * preceding them with the backslash '{@code \}' character. Note that
- * although both the {@code <substring>} and {@code <present>}
- * productions can produce the {@code 'attr=*'} construct, this construct is
- * used only to denote a presence filter.
- *
- * <p>
- * Examples of LDAP filters are:
- *
- * <pre>
- * "(cn=Babs Jensen)"
- * "(!(cn=Tim Howes))"
- * "(&(" + Constants.OBJECTCLASS + "=Person)(|(sn=Jensen)(cn=Babs J*)))"
- * "(o=univ*of*mich*)"
- * </pre>
- *
- * <p>
- * The approximate match ({@code ~=}) is implementation specific but should
- * at least ignore case and white space differences. Optional are codes like
- * soundex or other smart "closeness" comparisons.
- *
- * <p>
- * Comparison of values is not straightforward. Strings are compared
- * differently than numbers and it is possible for a key to have multiple
- * values. Note that that keys in the match argument must always be strings.
- * The comparison is defined by the object type of the key's value. The
- * following rules apply for comparison:
- *
- * <blockquote>
- * <TABLE BORDER=0>
- * <TR>
- * <TD><b>Property Value Type </b></TD>
- * <TD><b>Comparison Type</b></TD>
- * </TR>
- * <TR>
- * <TD>String</TD>
- * <TD>String comparison</TD>
- * </TR>
- * <TR valign=top>
- * <TD>Integer, Long, Float, Double, Byte, Short, BigInteger, BigDecimal</TD>
- * <TD>numerical comparison</TD>
- * </TR>
- * <TR>
- * <TD>Character</TD>
- * <TD>character comparison</TD>
- * </TR>
- * <TR>
- * <TD>Boolean</TD>
- * <TD>equality comparisons only</TD>
- * </TR>
- * <TR>
- * <TD>[] (array)</TD>
- * <TD>recursively applied to values</TD>
- * </TR>
- * <TR>
- * <TD>Collection</TD>
- * <TD>recursively applied to values</TD>
- * </TR>
- * </TABLE>
- * Note: arrays of primitives are also supported. </blockquote>
- *
- * A filter matches a key that has multiple values if it matches at least
- * one of those values. For example,
- *
- * <pre>
- * Dictionary d = new Hashtable();
- * d.put("cn", new String[] {"a", "b", "c"});
- * </pre>
- *
- * d will match {@code (cn=a)} and also {@code (cn=b)}
- *
- * <p>
- * A filter component that references a key having an unrecognizable data
- * type will evaluate to {@code false} .
- */
- static private final class FilterImpl implements Filter {
- /* filter operators */
- private static final int EQUAL = 1;
- private static final int APPROX = 2;
- private static final int GREATER = 3;
- private static final int LESS = 4;
- private static final int PRESENT = 5;
- private static final int SUBSTRING = 6;
- private static final int AND = 7;
- private static final int OR = 8;
- private static final int NOT = 9;
-
- /** filter operation */
- private final int op;
- /** filter attribute or null if operation AND, OR or NOT */
- private final String attr;
- /** filter operands */
- private final Object value;
-
- /* normalized filter string for Filter object */
- private transient String filterString;
-
- /**
- * Constructs a {@link FilterImpl} object. This filter object may be
- * used to match a {@link ServiceReference} or a Dictionary.
- *
- * <p>
- * If the filter cannot be parsed, an {@link InvalidSyntaxException}
- * will be thrown with a human readable message where the filter became
- * unparsable.
- *
- * @param filterString the filter string.
- * @throws InvalidSyntaxException If the filter parameter contains an
- * invalid filter string that cannot be parsed.
- */
- static FilterImpl newInstance(String filterString) throws InvalidSyntaxException {
- return new Parser(filterString).parse();
- }
-
- FilterImpl(int operation, String attr, Object value) {
- this.op = operation;
- this.attr = attr;
- this.value = value;
- filterString = null;
- }
-
- /**
- * Filter using a service's properties.
- * <p>
- * This {@code Filter} is executed using the keys and values of the
- * referenced service's properties. The keys are looked up in a case
- * insensitive manner.
- *
- * @param reference The reference to the service whose properties are
- * used in the match.
- * @return {@code true} if the service's properties match this
- * {@code Filter}; {@code false} otherwise.
- */
- @Override
- public boolean match(ServiceReference<?> reference) {
- return matches(new ServiceReferenceMap(reference));
- }
-
- /**
- * Filter using a {@code Dictionary} with case insensitive key lookup.
- * This {@code Filter} is executed using the specified
- * {@code Dictionary}'s keys and values. The keys are looked up in a
- * case insensitive manner.
- *
- * @param dictionary The {@code Dictionary} whose key/value pairs are
- * used in the match.
- * @return {@code true} if the {@code Dictionary}'s values match this
- * filter; {@code false} otherwise.
- * @throws IllegalArgumentException If {@code dictionary} contains case
- * variants of the same key name.
- */
- @Override
- public boolean match(Dictionary<String, ?> dictionary) {
- return matches(new CaseInsensitiveMap(dictionary));
- }
-
- /**
- * Filter using a {@code Dictionary}. This {@code Filter} is executed
- * using the specified {@code Dictionary}'s keys and values. The keys
- * are looked up in a normal manner respecting case.
- *
- * @param dictionary The {@code Dictionary} whose key/value pairs are
- * used in the match.
- * @return {@code true} if the {@code Dictionary}'s values match this
- * filter; {@code false} otherwise.
- * @since 1.3
- */
- @Override
- public boolean matchCase(Dictionary<String, ?> dictionary) {
- switch (op) {
- case AND : {
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- if (!f.matchCase(dictionary)) {
- return false;
- }
- }
- return true;
- }
-
- case OR : {
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- if (f.matchCase(dictionary)) {
- return true;
- }
- }
- return false;
- }
-
- case NOT : {
- FilterImpl filter = (FilterImpl) value;
- return !filter.matchCase(dictionary);
- }
-
- case SUBSTRING :
- case EQUAL :
- case GREATER :
- case LESS :
- case APPROX : {
- Object prop = (dictionary == null) ? null : dictionary.get(attr);
- return compare(op, prop, value);
- }
-
- case PRESENT : {
- Object prop = (dictionary == null) ? null : dictionary.get(attr);
- return prop != null;
- }
- }
-
- return false;
- }
-
- /**
- * Filter using a {@code Map}. This {@code Filter} is executed using the
- * specified {@code Map}'s keys and values. The keys are looked up in a
- * normal manner respecting case.
- *
- * @param map The {@code Map} whose key/value pairs are used in the
- * match. Maps with {@code null} key or values are not supported.
- * A {@code null} value is considered not present to the filter.
- * @return {@code true} if the {@code Map}'s values match this filter;
- * {@code false} otherwise.
- * @since 1.6
- */
- @Override
- public boolean matches(Map<String, ?> map) {
- switch (op) {
- case AND : {
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- if (!f.matches(map)) {
- return false;
- }
- }
- return true;
- }
-
- case OR : {
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- if (f.matches(map)) {
- return true;
- }
- }
- return false;
- }
-
- case NOT : {
- FilterImpl filter = (FilterImpl) value;
- return !filter.matches(map);
- }
-
- case SUBSTRING :
- case EQUAL :
- case GREATER :
- case LESS :
- case APPROX : {
- Object prop = (map == null) ? null : map.get(attr);
- return compare(op, prop, value);
- }
-
- case PRESENT : {
- Object prop = (map == null) ? null : map.get(attr);
- return prop != null;
- }
- }
-
- return false;
- }
-
- /**
- * Returns this {@code Filter}'s filter string.
- * <p>
- * The filter string is normalized by removing whitespace which does not
- * affect the meaning of the filter.
- *
- * @return This {@code Filter}'s filter string.
- */
- @Override
- public String toString() {
- String result = filterString;
- if (result == null) {
- filterString = result = normalize().toString();
- }
- return result;
- }
-
- /**
- * Returns this {@code Filter}'s normalized filter string.
- * <p>
- * The filter string is normalized by removing whitespace which does not
- * affect the meaning of the filter.
- *
- * @return This {@code Filter}'s filter string.
- */
- private StringBuilder normalize() {
- StringBuilder sb = new StringBuilder();
- sb.append('(');
-
- switch (op) {
- case AND : {
- sb.append('&');
-
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- sb.append(f.normalize());
- }
-
- break;
- }
-
- case OR : {
- sb.append('|');
-
- FilterImpl[] filters = (FilterImpl[]) value;
- for (FilterImpl f : filters) {
- sb.append(f.normalize());
- }
-
- break;
- }
-
- case NOT : {
- sb.append('!');
- FilterImpl filter = (FilterImpl) value;
- sb.append(filter.normalize());
-
- break;
- }
-
- case SUBSTRING : {
- sb.append(attr);
- sb.append('=');
-
- String[] substrings = (String[]) value;
-
- for (String substr : substrings) {
- if (substr == null) /* * */{
- sb.append('*');
- } else /* xxx */{
- sb.append(encodeValue(substr));
- }
- }
-
- break;
- }
- case EQUAL : {
- sb.append(attr);
- sb.append('=');
- sb.append(encodeValue((String) value));
-
- break;
- }
- case GREATER : {
- sb.append(attr);
- sb.append(">=");
- sb.append(encodeValue((String) value));
-
- break;
- }
- case LESS : {
- sb.append(attr);
- sb.append("<=");
- sb.append(encodeValue((String) value));
-
- break;
- }
- case APPROX : {
- sb.append(attr);
- sb.append("~=");
- sb.append(encodeValue(approxString((String) value)));
-
- break;
- }
-
- case PRESENT : {
- sb.append(attr);
- sb.append("=*");
-
- break;
- }
- }
-
- sb.append(')');
-
- return sb;
- }
-
- /**
- * Compares this {@code Filter} to another {@code Filter}.
- *
- * <p>
- * This implementation returns the result of calling
- * {@code this.toString().equals(obj.toString()}.
- *
- * @param obj The object to compare against this {@code Filter}.
- * @return If the other object is a {@code Filter} object, then returns
- * the result of calling
- * {@code this.toString().equals(obj.toString()}; {@code false}
- * otherwise.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (!(obj instanceof Filter)) {
- return false;
- }
-
- return this.toString().equals(obj.toString());
- }
-
- /**
- * Returns the hashCode for this {@code Filter}.
- *
- * <p>
- * This implementation returns the result of calling
- * {@code this.toString().hashCode()}.
- *
- * @return The hashCode of this {@code Filter}.
- */
- @Override
- public int hashCode() {
- return this.toString().hashCode();
- }
-
- /**
- * Encode the value string such that '(', '*', ')' and '\' are escaped.
- *
- * @param value unencoded value string.
- * @return encoded value string.
- */
- private static String encodeValue(String value) {
- boolean encoded = 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 '(' :
- case '*' :
- case ')' :
- case '\\' : {
- output[cursor] = '\\';
- cursor++;
- encoded = true;
-
- break;
- }
- }
-
- output[cursor] = c;
- cursor++;
- }
-
- return encoded ? new String(output, 0, cursor) : value;
- }
-
- private boolean compare(int operation, Object value1, Object value2) {
- if (value1 == null) {
- return false;
- }
- if (value1 instanceof String) {
- return compare_String(operation, (String) value1, value2);
- }
- if (value1 instanceof Version) {
- return compare_Version(operation, (Version) value1, value2);
- }
-
- Class<?> clazz = value1.getClass();
- if (clazz.isArray()) {
- Class<?> type = clazz.getComponentType();
- if (type.isPrimitive()) {
- return compare_PrimitiveArray(operation, type, value1, value2);
- }
- return compare_ObjectArray(operation, (Object[]) value1, value2);
- }
- if (value1 instanceof Collection<?>) {
- return compare_Collection(operation, (Collection<?>) value1, value2);
- }
- if (value1 instanceof Integer) {
- return compare_Integer(operation, ((Integer) value1).intValue(), value2);
- }
- if (value1 instanceof Long) {
- return compare_Long(operation, ((Long) value1).longValue(), value2);
- }
- if (value1 instanceof Byte) {
- return compare_Byte(operation, ((Byte) value1).byteValue(), value2);
- }
- if (value1 instanceof Short) {
- return compare_Short(operation, ((Short) value1).shortValue(), value2);
- }
- if (value1 instanceof Character) {
- return compare_Character(operation, ((Character) value1).charValue(), value2);
- }
- if (value1 instanceof Float) {
- return compare_Float(operation, ((Float) value1).floatValue(), value2);
- }
- if (value1 instanceof Double) {
- return compare_Double(operation, ((Double) value1).doubleValue(), value2);
- }
- if (value1 instanceof Boolean) {
- return compare_Boolean(operation, ((Boolean) value1).booleanValue(), value2);
- }
- if (value1 instanceof Comparable<?>) {
- @SuppressWarnings("unchecked")
- Comparable<Object> comparable = (Comparable<Object>) value1;
- return compare_Comparable(operation, comparable, value2);
- }
- return compare_Unknown(operation, value1, value2);
- }
-
- private boolean compare_Collection(int operation, Collection<?> collection, Object value2) {
- for (Object value1 : collection) {
- if (compare(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean compare_ObjectArray(int operation, Object[] array, Object value2) {
- for (Object value1 : array) {
- if (compare(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean compare_PrimitiveArray(int operation, Class<?> type, Object primarray, Object value2) {
- if (Integer.TYPE.isAssignableFrom(type)) {
- int[] array = (int[]) primarray;
- for (int value1 : array) {
- if (compare_Integer(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Long.TYPE.isAssignableFrom(type)) {
- long[] array = (long[]) primarray;
- for (long value1 : array) {
- if (compare_Long(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Byte.TYPE.isAssignableFrom(type)) {
- byte[] array = (byte[]) primarray;
- for (byte value1 : array) {
- if (compare_Byte(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Short.TYPE.isAssignableFrom(type)) {
- short[] array = (short[]) primarray;
- for (short value1 : array) {
- if (compare_Short(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Character.TYPE.isAssignableFrom(type)) {
- char[] array = (char[]) primarray;
- for (char value1 : array) {
- if (compare_Character(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Float.TYPE.isAssignableFrom(type)) {
- float[] array = (float[]) primarray;
- for (float value1 : array) {
- if (compare_Float(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Double.TYPE.isAssignableFrom(type)) {
- double[] array = (double[]) primarray;
- for (double value1 : array) {
- if (compare_Double(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- if (Boolean.TYPE.isAssignableFrom(type)) {
- boolean[] array = (boolean[]) primarray;
- for (boolean value1 : array) {
- if (compare_Boolean(operation, value1, value2)) {
- return true;
- }
- }
- return false;
- }
- return false;
- }
-
- private boolean compare_String(int operation, String string, Object value2) {
- switch (operation) {
- case SUBSTRING : {
- String[] substrings = (String[]) value2;
- int pos = 0;
- for (int i = 0, size = substrings.length; i < size; i++) {
- String substr = substrings[i];
-
- if (i + 1 < size) /* if this is not that last substr */{
- if (substr == null) /* * */{
- String substr2 = substrings[i + 1];
-
- if (substr2 == null) /* ** */
- continue; /* ignore first star */
- /* xxx */
- int index = string.indexOf(substr2, pos);
- if (index == -1) {
- return false;
- }
-
- pos = index + substr2.length();
- if (i + 2 < size) // if there are more
- // substrings, increment
- // over the string we just
- // matched; otherwise need
- // to do the last substr
- // check
- i++;
- } else /* xxx */{
- int len = substr.length();
- if (string.regionMatches(pos, substr, 0, len)) {
- pos += len;
- } else {
- return false;
- }
- }
- } else /* last substr */{
- if (substr == null) /* * */{
- return true;
- }
- /* xxx */
- return string.endsWith(substr);
- }
- }
-
- return true;
- }
- case EQUAL : {
- return string.equals(value2);
- }
- case APPROX : {
- string = approxString(string);
- String string2 = approxString((String) value2);
-
- return string.equalsIgnoreCase(string2);
- }
- case GREATER : {
- return string.compareTo((String) value2) >= 0;
- }
- case LESS : {
- return string.compareTo((String) value2) <= 0;
- }
- }
- return false;
- }
-
- private boolean compare_Integer(int operation, int intval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- int intval2;
- try {
- intval2 = Integer.parseInt(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return intval == intval2;
- }
- case GREATER : {
- return intval >= intval2;
- }
- case LESS : {
- return intval <= intval2;
- }
- }
- return false;
- }
-
- private boolean compare_Long(int operation, long longval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- long longval2;
- try {
- longval2 = Long.parseLong(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
-
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return longval == longval2;
- }
- case GREATER : {
- return longval >= longval2;
- }
- case LESS : {
- return longval <= longval2;
- }
- }
- return false;
- }
-
- private boolean compare_Byte(int operation, byte byteval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- byte byteval2;
- try {
- byteval2 = Byte.parseByte(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
-
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return byteval == byteval2;
- }
- case GREATER : {
- return byteval >= byteval2;
- }
- case LESS : {
- return byteval <= byteval2;
- }
- }
- return false;
- }
-
- private boolean compare_Short(int operation, short shortval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- short shortval2;
- try {
- shortval2 = Short.parseShort(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
-
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return shortval == shortval2;
- }
- case GREATER : {
- return shortval >= shortval2;
- }
- case LESS : {
- return shortval <= shortval2;
- }
- }
- return false;
- }
-
- private boolean compare_Character(int operation, char charval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- char charval2;
- try {
- charval2 = ((String) value2).charAt(0);
- } catch (IndexOutOfBoundsException e) {
- return false;
- }
-
- switch (operation) {
- case EQUAL : {
- return charval == charval2;
- }
- case APPROX : {
- return (charval == charval2) || (Character.toUpperCase(charval) == Character.toUpperCase(charval2)) || (Character.toLowerCase(charval) == Character.toLowerCase(charval2));
- }
- case GREATER : {
- return charval >= charval2;
- }
- case LESS : {
- return charval <= charval2;
- }
- }
- return false;
- }
-
- private boolean compare_Boolean(int operation, boolean boolval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- boolean boolval2 = Boolean.valueOf(((String) value2).trim()).booleanValue();
- switch (operation) {
- case APPROX :
- case EQUAL :
- case GREATER :
- case LESS : {
- return boolval == boolval2;
- }
- }
- return false;
- }
-
- private boolean compare_Float(int operation, float floatval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- float floatval2;
- try {
- floatval2 = Float.parseFloat(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
-
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return Float.compare(floatval, floatval2) == 0;
- }
- case GREATER : {
- return Float.compare(floatval, floatval2) >= 0;
- }
- case LESS : {
- return Float.compare(floatval, floatval2) <= 0;
- }
- }
- return false;
- }
-
- private boolean compare_Double(int operation, double doubleval, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- double doubleval2;
- try {
- doubleval2 = Double.parseDouble(((String) value2).trim());
- } catch (IllegalArgumentException e) {
- return false;
- }
-
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return Double.compare(doubleval, doubleval2) == 0;
- }
- case GREATER : {
- return Double.compare(doubleval, doubleval2) >= 0;
- }
- case LESS : {
- return Double.compare(doubleval, doubleval2) <= 0;
- }
- }
- return false;
- }
-
- private static Object valueOf(Class<?> target, String value2) {
- do {
- Method method;
- try {
- method = target.getMethod("valueOf", String.class);
- } catch (NoSuchMethodException e) {
- break;
- }
- if (Modifier.isStatic(method.getModifiers()) && target.isAssignableFrom(method.getReturnType())) {
- setAccessible(method);
- try {
- return method.invoke(null, value2.trim());
- } catch (IllegalAccessException e) {
- return null;
- } catch (InvocationTargetException e) {
- return null;
- }
- }
- } while (false);
-
- do {
- Constructor<?> constructor;
- try {
- constructor = target.getConstructor(String.class);
- } catch (NoSuchMethodException e) {
- break;
- }
- setAccessible(constructor);
- try {
- return constructor.newInstance(value2.trim());
- } catch (IllegalAccessException e) {
- return null;
- } catch (InvocationTargetException e) {
- return null;
- } catch (InstantiationException e) {
- return null;
- }
- } while (false);
-
- return null;
- }
-
- private static void setAccessible(AccessibleObject accessible) {
- if (!accessible.isAccessible()) {
- AccessController.doPrivileged(new SetAccessibleAction(accessible));
- }
- }
-
- private boolean compare_Comparable(int operation, Comparable<Object> value1, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- value2 = valueOf(value1.getClass(), (String) value2);
- if (value2 == null) {
- return false;
- }
- try {
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return value1.compareTo(value2) == 0;
- }
- case GREATER : {
- return value1.compareTo(value2) >= 0;
- }
- case LESS : {
- return value1.compareTo(value2) <= 0;
- }
- }
- } catch (Exception e) {
- // if the compareTo method throws an exception; return false
- return false;
- }
- return false;
- }
-
- private boolean compare_Version(int operation, Version value1, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- try {
- Version version2 = Version.valueOf((String) value2);
- switch (operation) {
- case APPROX :
- case EQUAL : {
- return value1.compareTo(version2) == 0;
- }
- case GREATER : {
- return value1.compareTo(version2) >= 0;
- }
- case LESS : {
- return value1.compareTo(version2) <= 0;
- }
- }
- } catch (Exception e) {
- // if the valueOf or compareTo method throws an exception
- return false;
- }
- return false;
- }
-
- private boolean compare_Unknown(int operation, Object value1, Object value2) {
- if (operation == SUBSTRING) {
- return false;
- }
- value2 = valueOf(value1.getClass(), (String) value2);
- if (value2 == null) {
- return false;
- }
- try {
- switch (operation) {
- case APPROX :
- case EQUAL :
- case GREATER :
- case LESS : {
- return value1.equals(value2);
- }
- }
- } catch (Exception e) {
- // if the equals method throws an exception; return false
- return false;
- }
- return false;
- }
-
- /**
- * Map a string for an APPROX (~=) comparison.
- *
- * This implementation removes white spaces. This is the minimum
- * implementation allowed by the OSGi spec.
- *
- * @param input Input string.
- * @return String ready for APPROX comparison.
- */
- private static String approxString(String input) {
- boolean changed = false;
- char[] output = input.toCharArray();
- int cursor = 0;
- for (char c : output) {
- if (Character.isWhitespace(c)) {
- changed = true;
- continue;
- }
-
- output[cursor] = c;
- cursor++;
- }
-
- return changed ? new String(output, 0, cursor) : input;
- }
-
- /**
- * Parser class for OSGi filter strings. This class parses the complete
- * filter string and builds a tree of Filter objects rooted at the
- * parent.
- */
- static private final class Parser {
- private final String filterstring;
- private final char[] filterChars;
- private int pos;
-
- Parser(String filterstring) {
- this.filterstring = filterstring;
- filterChars = filterstring.toCharArray();
- pos = 0;
- }
-
- FilterImpl parse() throws InvalidSyntaxException {
- FilterImpl filter;
- try {
- filter = parse_filter();
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new InvalidSyntaxException("Filter ended abruptly", filterstring, e);
- }
-
- if (pos != filterChars.length) {
- throw new InvalidSyntaxException("Extraneous trailing characters: " + filterstring.substring(pos), filterstring);
- }
- return filter;
- }
-
- private FilterImpl parse_filter() throws InvalidSyntaxException {
- FilterImpl filter;
- skipWhiteSpace();
-
- if (filterChars[pos] != '(') {
- throw new InvalidSyntaxException("Missing '(': " + filterstring.substring(pos), filterstring);
- }
-
- pos++;
-
- filter = parse_filtercomp();
-
- skipWhiteSpace();
-
- if (filterChars[pos] != ')') {
- throw new InvalidSyntaxException("Missing ')': " + filterstring.substring(pos), filterstring);
- }
-
- pos++;
-
- skipWhiteSpace();
-
- return filter;
- }
-
- private FilterImpl parse_filtercomp() throws InvalidSyntaxException {
- skipWhiteSpace();
-
- char c = filterChars[pos];
-
- switch (c) {
- case '&' : {
- pos++;
- return parse_and();
- }
- case '|' : {
- pos++;
- return parse_or();
- }
- case '!' : {
- pos++;
- return parse_not();
- }
- }
- return parse_item();
- }
-
- private FilterImpl parse_and() throws InvalidSyntaxException {
- int lookahead = pos;
- skipWhiteSpace();
-
- if (filterChars[pos] != '(') {
- pos = lookahead - 1;
- return parse_item();
- }
-
- List<FilterImpl> operands = new ArrayList<FilterImpl>(10);
-
- while (filterChars[pos] == '(') {
- FilterImpl child = parse_filter();
- operands.add(child);
- }
-
- return new FilterImpl(FilterImpl.AND, null,
- operands.toArray(new FilterImpl[0]));
- }
-
- private FilterImpl parse_or() throws InvalidSyntaxException {
- int lookahead = pos;
- skipWhiteSpace();
-
- if (filterChars[pos] != '(') {
- pos = lookahead - 1;
- return parse_item();
- }
-
- List<FilterImpl> operands = new ArrayList<FilterImpl>(10);
-
- while (filterChars[pos] == '(') {
- FilterImpl child = parse_filter();
- operands.add(child);
- }
-
- return new FilterImpl(FilterImpl.OR, null,
- operands.toArray(new FilterImpl[0]));
- }
-
- private FilterImpl parse_not() throws InvalidSyntaxException {
- int lookahead = pos;
- skipWhiteSpace();
-
- if (filterChars[pos] != '(') {
- pos = lookahead - 1;
- return parse_item();
- }
-
- FilterImpl child = parse_filter();
-
- return new FilterImpl(FilterImpl.NOT, null, child);
- }
-
- private FilterImpl parse_item() throws InvalidSyntaxException {
- String attr = parse_attr();
-
- skipWhiteSpace();
-
- switch (filterChars[pos]) {
- case '~' : {
- if (filterChars[pos + 1] == '=') {
- pos += 2;
- return new FilterImpl(FilterImpl.APPROX, attr, parse_value());
- }
- break;
- }
- case '>' : {
- if (filterChars[pos + 1] == '=') {
- pos += 2;
- return new FilterImpl(FilterImpl.GREATER, attr, parse_value());
- }
- break;
- }
- case '<' : {
- if (filterChars[pos + 1] == '=') {
- pos += 2;
- return new FilterImpl(FilterImpl.LESS, attr, parse_value());
- }
- break;
- }
- case '=' : {
- if (filterChars[pos + 1] == '*') {
- int oldpos = pos;
- pos += 2;
- skipWhiteSpace();
- if (filterChars[pos] == ')') {
- return new FilterImpl(FilterImpl.PRESENT, attr, null);
- }
- pos = oldpos;
- }
-
- pos++;
- Object string = parse_substring();
-
- if (string instanceof String) {
- return new FilterImpl(FilterImpl.EQUAL, attr, string);
- }
- return new FilterImpl(FilterImpl.SUBSTRING, attr, string);
- }
- }
-
- throw new InvalidSyntaxException("Invalid operator: " + filterstring.substring(pos), filterstring);
- }
-
- private String parse_attr() throws InvalidSyntaxException {
- skipWhiteSpace();
-
- int begin = pos;
- int end = pos;
-
- char c = filterChars[pos];
-
- while (c != '~' && c != '<' && c != '>' && c != '=' && c != '(' && c != ')') {
- pos++;
-
- if (!Character.isWhitespace(c)) {
- end = pos;
- }
-
- c = filterChars[pos];
- }
-
- int length = end - begin;
-
- if (length == 0) {
- throw new InvalidSyntaxException("Missing attr: " + filterstring.substring(pos), filterstring);
- }
-
- return new String(filterChars, begin, length);
- }
-
- private String parse_value() throws InvalidSyntaxException {
- StringBuilder sb = new StringBuilder(filterChars.length - pos);
-
- parseloop: while (true) {
- char c = filterChars[pos];
-
- switch (c) {
- case ')' : {
- break parseloop;
- }
-
- case '(' : {
- throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring);
- }
-
- case '\\' : {
- pos++;
- c = filterChars[pos];
- /* fall through into default */
- }
-
- default : {
- sb.append(c);
- pos++;
- break;
- }
- }
- }
-
- if (sb.length() == 0) {
- throw new InvalidSyntaxException("Missing value: " + filterstring.substring(pos), filterstring);
- }
-
- return sb.toString();
- }
-
- private Object parse_substring() throws InvalidSyntaxException {
- StringBuilder sb = new StringBuilder(filterChars.length - pos);
-
- List<String> operands = new ArrayList<String>(10);
-
- parseloop: while (true) {
- char c = filterChars[pos];
-
- switch (c) {
- case ')' : {
- if (sb.length() > 0) {
- operands.add(sb.toString());
- }
-
- break parseloop;
- }
-
- case '(' : {
- throw new InvalidSyntaxException("Invalid value: " + filterstring.substring(pos), filterstring);
- }
-
- case '*' : {
- if (sb.length() > 0) {
- operands.add(sb.toString());
- }
-
- sb.setLength(0);
-
- operands.add(null);
- pos++;
-
- break;
- }
-
- case '\\' : {
- pos++;
- c = filterChars[pos];
- /* fall through into default */
- }
-
- default : {
- sb.append(c);
- pos++;
- break;
- }
- }
- }
-
- int size = operands.size();
-
- if (size == 0) {
- return "";
- }
-
- if (size == 1) {
- Object single = operands.get(0);
-
- if (single != null) {
- return single;
- }
- }
-
- return operands.toArray(new String[0]);
- }
-
- private void skipWhiteSpace() {
- for (int length = filterChars.length; (pos < length) && Character.isWhitespace(filterChars[pos]);) {
- pos++;
- }
- }
- }
+ * <pre>
+ * * ; ou=S & V, o=Tweety Inc., c=US
+ * </pre>
+ * <p>
+ * The wildcard ('*') matches zero or one DN in the chain, however,
+ * sometimes it is necessary to match a longer chain. The minus sign (
+ * {@code '-'} \u002D) represents zero or more DNs, whereas the asterisk
+ * only represents a single DN. For example, to match a DN where the Tweety
+ * Inc. is in the DN chain, use the following expression:
+ * </p>
+ *
+ * <pre>
+ * - ; *, o=Tweety Inc., c=US
+ * </pre>
+ *
+ * @param matchPattern The pattern against which to match the DN chain.
+ * @param dnChain The DN chain to match against the specified pattern. Each
+ * element of the chain must be of type {@code String} and use the
+ * format defined in <a
+ * href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>.
+ * @return {@code true} If the pattern matches the DN chain; otherwise
+ * {@code false} is returned.
+ * @throws IllegalArgumentException If the specified match pattern or DN
+ * chain is invalid.
+ * @since 1.5
+ */
+ public static boolean matchDistinguishedNameChain(String matchPattern, List<String> dnChain) {
+ return DNChainMatching.match(matchPattern, dnChain);
}
/**
- * This Map is used for case-insensitive key lookup during filter
- * evaluation. This Map implementation only supports the get operation using
- * a String key as no other operations are used by the Filter
- * implementation.
+ * Return a {@code Bundle} for the specified bundle class loader.
+ *
+ * @param bundleClassLoader A bundle class loader.
+ * @return An Optional containing {@code Bundle} for the specified bundle
+ * class loader or an empty Optional if the specified class loader
+ * is not associated with a specific bundle.
+ * @since 1.10
*/
- static private final class CaseInsensitiveMap extends AbstractMap<String, Object> implements Map<String, Object> {
- private final Dictionary<String, ?> dictionary;
- private final String[] keys;
-
- /**
- * Create a case insensitive map from the specified dictionary.
- *
- * @param dictionary
- * @throws IllegalArgumentException If {@code dictionary} contains case
- * variants of the same key name.
- */
- CaseInsensitiveMap(Dictionary<String, ?> dictionary) {
- if (dictionary == null) {
- this.dictionary = null;
- this.keys = new String[0];
- return;
- }
- this.dictionary = dictionary;
- List<String> keyList = new ArrayList<String>(dictionary.size());
- for (Enumeration<?> e = dictionary.keys(); e.hasMoreElements();) {
- Object k = e.nextElement();
- if (k instanceof String) {
- String key = (String) k;
- for (String i : keyList) {
- if (key.equalsIgnoreCase(i)) {
- throw new IllegalArgumentException();
- }
- }
- keyList.add(key);
- }
- }
- this.keys = keyList.toArray(new String[0]);
- }
-
- @Override
- public Object get(Object o) {
- String k = (String) o;
- for (String key : keys) {
- if (key.equalsIgnoreCase(k)) {
- return dictionary.get(key);
- }
- }
- return null;
- }
-
- @Override
- public Set<java.util.Map.Entry<String, Object>> entrySet() {
- throw new UnsupportedOperationException();
- }
+ public static Optional<Bundle> getBundle(ClassLoader bundleClassLoader) {
+ requireNonNull(bundleClassLoader);
+ return Optional
+ .ofNullable((bundleClassLoader instanceof BundleReference)
+ ? ((BundleReference) bundleClassLoader).getBundle()
+ : null);
}
/**
- * This Map is used for key lookup from a ServiceReference during filter
- * evaluation. This Map implementation only supports the get operation using
- * a String key as no other operations are used by the Filter
- * implementation.
+ * Return a {@code Bundle} for the specified bundle class.
+ *
+ * @param classFromBundle A class defined by a bundle.
+ * @return A {@code Bundle} for the specified bundle class or {@code null}
+ * if the specified class was not defined by a bundle.
+ * @since 1.5
*/
- static private final class ServiceReferenceMap extends AbstractMap<String, Object> implements Map<String, Object> {
- private final ServiceReference<?> reference;
-
- ServiceReferenceMap(ServiceReference<?> reference) {
- this.reference = reference;
- }
-
- @Override
- public Object get(Object key) {
- if (reference == null) {
- return null;
- }
- return reference.getProperty((String) key);
- }
+ public static Bundle getBundle(Class< ? > classFromBundle) {
+ // We use doPriv since the caller may not have permission
+ // to call getClassLoader.
+ Optional<ClassLoader> cl = Optional
+ .ofNullable(AccessController.doPrivileged(
+ (PrivilegedAction<ClassLoader>) () -> classFromBundle
+ .getClassLoader()));
- @Override
- public Set<java.util.Map.Entry<String, Object>> entrySet() {
- throw new UnsupportedOperationException();
- }
+ return cl.flatMap(FrameworkUtil::getBundle)
+ .orElseGet(() -> helpers.stream()
+ .map(helper -> helper.getBundle(classFromBundle))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .findFirst()
+ .orElse(null));
}
- static private final class SetAccessibleAction implements PrivilegedAction<Void> {
- private final AccessibleObject accessible;
-
- SetAccessibleAction(AccessibleObject accessible) {
- this.accessible = accessible;
- }
-
- @Override
- public Void run() {
- accessible.setAccessible(true);
- return null;
+ private final static List<FrameworkUtilHelper> helpers;
+ static {
+ List<FrameworkUtilHelper> l = new ArrayList<>();
+ try {
+ ServiceLoader<FrameworkUtilHelper> helperLoader = AccessController
+ .doPrivileged(
+ (PrivilegedAction<ServiceLoader<FrameworkUtilHelper>>) () -> ServiceLoader
+ .load(FrameworkUtilHelper.class,
+ FrameworkUtilHelper.class
+ .getClassLoader()));
+ helperLoader.forEach(l::add);
+ } catch (Throwable error) {
+ // try hard not to fail static <clinit>
+ try {
+ Thread t = Thread.currentThread();
+ t.getUncaughtExceptionHandler().uncaughtException(t, error);
+ } catch (Throwable ignored) {
+ // we ignore this
+ }
}
+ helpers = Collections.unmodifiableList(l);
}
/**
@@ -2198,4 +703,357 @@ public class FrameworkUtil {
return sb.toString();
}
}
+
+ /**
+ * Return a Map wrapper around a Dictionary.
+ *
+ * @param <K> The type of the key.
+ * @param <V> The type of the value.
+ * @param dictionary The dictionary to wrap.
+ * @return A Map object which wraps the specified dictionary. If the
+ * specified dictionary can be cast to a Map, then the specified
+ * dictionary is returned.
+ * @since 1.10
+ */
+ public static <K, V> Map<K,V> asMap(
+ Dictionary< ? extends K, ? extends V> dictionary) {
+ if (dictionary instanceof Map) {
+ @SuppressWarnings("unchecked")
+ Map<K,V> coerced = (Map<K,V>) dictionary;
+ return coerced;
+ }
+ return new DictionaryAsMap<>(dictionary);
+ }
+
+ private static class DictionaryAsMap<K, V> extends AbstractMap<K,V> {
+ private final Dictionary<K,V> dict;
+
+ @SuppressWarnings("unchecked")
+ DictionaryAsMap(Dictionary< ? extends K, ? extends V> dict) {
+ this.dict = (Dictionary<K,V>) requireNonNull(dict);
+ }
+
+ Iterator<K> keys() {
+ List<K> keys = new ArrayList<>(dict.size());
+ for (Enumeration<K> e = dict.keys(); e.hasMoreElements();) {
+ keys.add(e.nextElement());
+ }
+ return keys.iterator();
+ }
+
+ @Override
+ public int size() {
+ return dict.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return dict.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ if (key == null) {
+ return false;
+ }
+ return dict.get(key) != null;
+ }
+
+ @Override
+ public V get(Object key) {
+ if (key == null) {
+ return null;
+ }
+ return dict.get(key);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ return dict.put(
+ requireNonNull(key,
+ "a Dictionary cannot contain a null key"),
+ requireNonNull(value,
+ "a Dictionary cannot contain a null value"));
+ }
+
+ @Override
+ public V remove(Object key) {
+ if (key == null) {
+ return null;
+ }
+ return dict.remove(key);
+ }
+
+ @Override
+ public void clear() {
+ for (Iterator<K> iter = keys(); iter.hasNext();) {
+ dict.remove(iter.next());
+ }
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return new KeySet();
+ }
+
+ @Override
+ public Set<Map.Entry<K,V>> entrySet() {
+ return new EntrySet();
+ }
+
+ @Override
+ public String toString() {
+ return dict.toString();
+ }
+
+ final class KeySet extends AbstractSet<K> {
+ @Override
+ public Iterator<K> iterator() {
+ return new KeyIterator();
+ }
+
+ @Override
+ public int size() {
+ return DictionaryAsMap.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return DictionaryAsMap.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object key) {
+ return DictionaryAsMap.this.containsKey(key);
+ }
+
+ @Override
+ public boolean remove(Object key) {
+ return DictionaryAsMap.this.remove(key) != null;
+ }
+
+ @Override
+ public void clear() {
+ DictionaryAsMap.this.clear();
+ }
+ }
+
+ final class KeyIterator implements Iterator<K> {
+ private final Iterator<K> keys = DictionaryAsMap.this.keys();
+ private K key = null;
+
+ @Override
+ public boolean hasNext() {
+ return keys.hasNext();
+ }
+
+ @Override
+ public K next() {
+ return key = keys.next();
+ }
+
+ @Override
+ public void remove() {
+ if (key == null) {
+ throw new IllegalStateException();
+ }
+ DictionaryAsMap.this.remove(key);
+ key = null;
+ }
+ }
+
+ final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+ @Override
+ public Iterator<Map.Entry<K,V>> iterator() {
+ return new EntryIterator();
+ }
+
+ @Override
+ public int size() {
+ return DictionaryAsMap.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return DictionaryAsMap.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) o;
+ return containsEntry(e);
+ }
+ return false;
+ }
+
+ private boolean containsEntry(Map.Entry< ? , ? > e) {
+ Object key = e.getKey();
+ if (key == null) {
+ return false;
+ }
+ Object value = e.getValue();
+ if (value == null) {
+ return false;
+ }
+ return Objects.equals(DictionaryAsMap.this.get(key), value);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) o;
+ if (containsEntry(e)) {
+ DictionaryAsMap.this.remove(e.getKey());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ DictionaryAsMap.this.clear();
+ }
+ }
+
+ final class EntryIterator implements Iterator<Map.Entry<K,V>> {
+ private final Iterator<K> keys = DictionaryAsMap.this.keys();
+ private K key = null;
+
+ @Override
+ public boolean hasNext() {
+ return keys.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K,V> next() {
+ return new Entry(key = keys.next());
+ }
+
+ @Override
+ public void remove() {
+ if (key == null) {
+ throw new IllegalStateException();
+ }
+ DictionaryAsMap.this.remove(key);
+ key = null;
+ }
+ }
+
+ final class Entry extends SimpleEntry<K,V> {
+ private static final long serialVersionUID = 1L;
+
+ Entry(K key) {
+ super(key, DictionaryAsMap.this.get(key));
+ }
+
+ @Override
+ public V setValue(V value) {
+ DictionaryAsMap.this.put(getKey(), value);
+ return super.setValue(value);
+ }
+ }
+ }
+
+ /**
+ * Return a Dictionary wrapper around a Map.
+ *
+ * @param <K> The type of the key.
+ * @param <V> The type of the value.
+ * @param map The map to wrap.
+ * @return A Dictionary object which wraps the specified map. If the
+ * specified map can be cast to a Dictionary, then the specified map
+ * is returned.
+ * @since 1.10
+ */
+ public static <K, V> Dictionary<K,V> asDictionary(
+ Map< ? extends K, ? extends V> map) {
+ if (map instanceof Dictionary) {
+ @SuppressWarnings("unchecked")
+ Dictionary<K,V> coerced = (Dictionary<K,V>) map;
+ return coerced;
+ }
+ return new MapAsDictionary<>(map);
+ }
+
+ private static class MapAsDictionary<K, V> extends Dictionary<K,V> {
+ private final Map<K,V> map;
+
+ @SuppressWarnings("unchecked")
+ MapAsDictionary(Map< ? extends K, ? extends V> map) {
+ this.map = (Map<K,V>) requireNonNull(map);
+ boolean nullKey;
+ try {
+ nullKey = map.containsKey(null);
+ } catch (NullPointerException e) {
+ nullKey = false; // map does not allow null key
+ }
+ if (nullKey) {
+ throw new NullPointerException(
+ "a Dictionary cannot contain a null key");
+ }
+ boolean nullValue;
+ try {
+ nullValue = map.containsValue(null);
+ } catch (NullPointerException e) {
+ nullValue = false; // map does not allow null value
+ }
+ if (nullValue) {
+ throw new NullPointerException(
+ "a Dictionary cannot contain a null value");
+ }
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public Enumeration<K> keys() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ @Override
+ public Enumeration<V> elements() {
+ return Collections.enumeration(map.values());
+ }
+
+ @Override
+ public V get(Object key) {
+ if (key == null) {
+ return null;
+ }
+ return map.get(key);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ return map.put(
+ requireNonNull(key,
+ "a Dictionary cannot contain a null key"),
+ requireNonNull(value,
+ "a Dictionary cannot contain a null value"));
+ }
+
+ @Override
+ public V remove(Object key) {
+ if (key == null) {
+ return null;
+ }
+ return map.remove(key);
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+ }
+
}
diff --git a/framework/src/main/java/org/osgi/framework/PackagePermission.java b/framework/src/main/java/org/osgi/framework/PackagePermission.java
index 1338daa..c10c211 100644
--- a/framework/src/main/java/org/osgi/framework/PackagePermission.java
+++ b/framework/src/main/java/org/osgi/framework/PackagePermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). 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.
@@ -54,7 +54,7 @@ import java.util.Map;
* deprecated, implies the {@code import} action.
*
* @ThreadSafe
- * @author $Id: 264ccd683465cbe22d571b0cb7d0b19352d582f7 $
+ * @author $Id: cc8cd627f5ca1e77bd3420d6e64d07b1a9ba4684 $
*/
public final class PackagePermission extends BasicPermission {
@@ -713,7 +713,7 @@ final class PackagePermissionCollection extends PermissionCollection {
/* work our way up the tree... */
int last;
int offset = requestedName.length() - 1;
- while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
requestedName = requestedName.substring(0, last + 1) + "*";
pp = pc.get(requestedName);
if (pp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java b/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
index dbb9243..9a3a3c8 100644
--- a/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
+++ b/framework/src/main/java/org/osgi/framework/PrototypeServiceFactory.java
@@ -65,7 +65,7 @@ import org.osgi.annotation.versioning.ConsumerType;
* @see ServiceObjects
* @ThreadSafe
* @since 1.8
- * @author $Id: PrototypeServiceFactory.java 1825132 2018-02-23 15:11:00Z pauls $
+ * @author $Id: 864506fa15679676e52eee91982a6fd5c1e9768f $
*/
@ConsumerType
public interface PrototypeServiceFactory<S> extends ServiceFactory<S> {
diff --git a/framework/src/main/java/org/osgi/framework/ServiceObjects.java b/framework/src/main/java/org/osgi/framework/ServiceObjects.java
index 145ed77..9b8ca46 100644
--- a/framework/src/main/java/org/osgi/framework/ServiceObjects.java
+++ b/framework/src/main/java/org/osgi/framework/ServiceObjects.java
@@ -41,7 +41,7 @@ import org.osgi.annotation.versioning.ProviderType;
* @see PrototypeServiceFactory
* @ThreadSafe
* @since 1.8
- * @author $Id: ServiceObjects.java 1825132 2018-02-23 15:11:00Z pauls $
+ * @author $Id: 84901895b763946d9f0e3819e47ecbf0ffa60f04 $
*/
@ProviderType
public interface ServiceObjects<S> {
diff --git a/framework/src/main/java/org/osgi/framework/ServicePermission.java b/framework/src/main/java/org/osgi/framework/ServicePermission.java
index e7d6c6f..693a787 100644
--- a/framework/src/main/java/org/osgi/framework/ServicePermission.java
+++ b/framework/src/main/java/org/osgi/framework/ServicePermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). 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.
@@ -51,7 +51,7 @@ import java.util.Set;
* to get the specific service.
*
* @ThreadSafe
- * @author $Id: 8db61d0b1cadd57ab173cba677b6bfb353680800 $
+ * @author $Id: a6b52521c8ba68698c1e167d4596f3ac56aab8ca $
*/
public final class ServicePermission extends BasicPermission {
@@ -866,7 +866,7 @@ final class ServicePermissionCollection extends PermissionCollection {
// work our way up the tree...
int last;
int offset = requestedName.length() - 1;
- while ((last = requestedName.lastIndexOf(".", offset)) != -1) {
+ while ((last = requestedName.lastIndexOf('.', offset)) != -1) {
requestedName = requestedName.substring(0, last + 1) + "*";
sp = pc.get(requestedName);
if (sp != null) {
diff --git a/framework/src/main/java/org/osgi/framework/ServiceReference.java b/framework/src/main/java/org/osgi/framework/ServiceReference.java
index 5d1b175..c512a44 100644
--- a/framework/src/main/java/org/osgi/framework/ServiceReference.java
+++ b/framework/src/main/java/org/osgi/framework/ServiceReference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2000, 2017). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2000, 2019). 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.
@@ -50,10 +50,11 @@ import org.osgi.annotation.versioning.ProviderType;
* @see BundleContext#getService(ServiceReference)
* @see BundleContext#getServiceObjects(ServiceReference)
* @ThreadSafe
- * @author $Id: 1454244c30992b7a52ac3838b03bc584c3495816 $
+ * @author $Id: adb91d7f0922417180e901dc6ec447f467b34921 $
*/
@ProviderType
-public interface ServiceReference<S> extends Comparable<Object> {
+public interface ServiceReference<S>
+ extends Comparable<Object>, BundleReference {
/**
* Returns the property value to which the specified property key is mapped
* in the properties {@code Dictionary} object of the service referenced by
@@ -109,6 +110,7 @@ public interface ServiceReference<S> extends Comparable<Object> {
* already been unregistered.
* @see BundleContext#registerService(String[],Object,Dictionary)
*/
+ @Override
public Bundle getBundle();
/**
@@ -131,14 +133,24 @@ public interface ServiceReference<S> extends Comparable<Object> {
* <p>
* This method performs the following checks:
* <ol>
+ * <li>If the specified bundle is equal to the bundle that registered the
+ * service referenced by this {@code ServiceReference} (registrant bundle)
+ * return {@code true}.</li>
* <li>Get the package name from the specified class name.</li>
- * <li>For the bundle that registered the service referenced by this
- * {@code ServiceReference} (registrant bundle); find the source for the
- * package. If no source is found then return {@code true} if the registrant
- * bundle is equal to the specified bundle; otherwise return {@code false}.</li>
- * <li>If the package source of the registrant bundle is equal to the
- * package source of the specified bundle then return {@code true};
- * otherwise return {@code false}.</li>
+ * <li>For the specified bundle; find the source for the package. If no
+ * source is found then return {@code true} (use of reflection is assumed by
+ * the specified bundle).</li>
+ * <li>For the registrant bundle; find the source for the package. If the
+ * package source is found then return {@code true} if the package source
+ * equals the package source of the specified bundle; otherwise return
+ * {@code false}.</li>
+ * <li>If no package source is found for the registrant bundle then
+ * determine the package source based on the service object. If the service
+ * object is a {@code ServiceFactory} and the factory implementation is not
+ * from the registrant bundle return {@code true}; otherwise attempt to find
+ * the package source based on the service object class. If the package
+ * source is found and is equal to package source of the specified bundle
+ * return {@code true}; otherwise return {@code false}.</li>
* </ol>
*
* @param bundle The {@code Bundle} object to check.
@@ -148,8 +160,8 @@ public interface ServiceReference<S> extends Comparable<Object> {
* bundle use the same source for the package of the specified class
* name. Otherwise {@code false} is returned.
* @throws IllegalArgumentException If the specified {@code Bundle} was not
- * created by the same framework instance as this
- * {@code ServiceReference}.
+ * created by the same framework instance as this
+ * {@code ServiceReference}.
* @since 1.3
*/
public boolean isAssignableTo(Bundle bundle, String className);
@@ -212,4 +224,27 @@ public interface ServiceReference<S> extends Comparable<Object> {
* @since 1.9
*/
public Dictionary<String,Object> getProperties();
+
+ /**
+ * Adapt this {@code ServiceReference} object to the specified type.
+ * <p>
+ * Adapting this {@code ServiceReference} object to the specified type may
+ * require certain checks, including security checks, to succeed. If a check
+ * does not succeed, then this {@code ServiceReference} object cannot be
+ * adapted and {@code null} is returned.
+ *
+ * @param <A> The type to which this {@code ServiceReference} object is to
+ * be adapted.
+ * @param type Class object for the type to which this
+ * {@code ServiceReference} object is to be adapted.
+ * @return The object, of the specified type, to which this
+ * {@code ServiceReference} object has been adapted or {@code null}
+ * if this {@code ServiceReference} object cannot be adapted to the
+ * specified type.
+ * @throws SecurityException If the caller does not have the appropriate
+ * {@code AdaptPermission[type,this,ADAPT]}, and the Java
+ * Runtime Environment supports permissions.
+ * @since 1.10
+ */
+ <A> A adapt(Class<A> type);
}
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java b/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java
index eb80ae6..3a90329 100644
--- a/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectContent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -21,138 +21,156 @@ import java.io.InputStream;
import java.util.Map;
import java.util.Optional;
+import org.osgi.annotation.versioning.ConsumerType;
import org.osgi.framework.Bundle;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.namespace.IdentityNamespace;
import org.osgi.framework.wiring.BundleRevisions;
/**
- * A connect content provides a {@link Framework framework} access to the
- * content of a connect {@link ConnectModule module}. A framework may
- * {@link #open() open} and {@link #close() close} the content for a connect
- * module multiple times while the connect content is in use by the framework
- * instance. The framework must close the connect content once the connect
- * content is no longer used as the content of a current bundle revision or an
- * in use bundle revision.
+ * A {@code ConnectContent} provides a {@link Framework} instance access to the
+ * content of a {@link ConnectModule}.
* <p>
- * An entry in a connect content is identified by a path name that is a
- * '{@code /}'-separated path. A connect content may treat directories as
- * entries. A directory entry path name will end with a slash ('/'). A directory
- * entry may be located using a path name that drops the trailing slash.
+ * A framework may {@link #open() open} and {@link #close() close} the content
+ * for a {@link ConnectModule} multiple times while the {@code ConnectContent}
+ * is in use by the framework. The framework must close the
+ * {@code ConnectContent} once the {@code ConnectContent} is no longer used as
+ * the content of a current bundle revision or an in use bundle revision.
+ * <p>
+ * An entry in a {@code ConnectContent} is identified by a path name that is a
+ * solidus (<code>'/' \u002F</code>) separated path. A {@code ConnectContent}
+ * may treat directories as entries. A directory entry path name will end with a
+ * solidus. A directory entry may be located using a path name that omits the
+ * trailing solidus.
*
* @see BundleRevisions
* @ThreadSafe
- * @author $Id: 44ec66031f9460c48453c7113e4871472a7c475c $
+ * @author $Id: 9e455f9d467f0e38daea0ea52a59a5ccb8c81257 $
*/
+@ConsumerType
public interface ConnectContent {
/**
* The {@code osgi.identity}
* {@link IdentityNamespace#CAPABILITY_TAGS_ATTRIBUTE tags} attribute value
* used by the framework to tag connect bundle revisions.
*/
- public static final String TAG_OSGI_CONNECT = "osgi.connect";
+ String TAG_OSGI_CONNECT = "osgi.connect";
/**
- * Returns this connect content Manifest headers and values. The
- * {@link Optional#empty() empty} value is returned if the framework should
- * handle parsing the Manifest of the content itself.
+ * Returns the Manifest headers and values of this {@code ConnectContent}.
*
- * @return This connect content Manifest headers and values.
- * @throws IllegalStateException if the connect content has been closed
+ * @return An {@code Optional} containing the Manifest headers and values
+ * for this {@code ConnectContent}, or an empty {@code Optional} if
+ * the framework should handle parsing the Manifest of the content
+ * itself.
+ * @throws IllegalStateException If this {@code ConnectContent} has been
+ * closed.
*/
Optional<Map<String,String>> getHeaders();
/**
- * Returns an iterable with all the entry names available in this
- * ConnectContent
+ * Returns the entry names available in this {@code ConnectContent}.
*
- * @return the entry names
- * @throws IOException if an error occurs reading the ConnectContent
- * @throws IllegalStateException if the connect content has been closed
+ * @return An {@code Iterable} which can supply the available entry names.
+ * @throws IOException If an error occurs reading this
+ * {@code ConnectContent}.
+ * @throws IllegalStateException If this {@code ConnectContent} has been
+ * closed.
*/
Iterable<String> getEntries() throws IOException;
/**
- * Returns the connect entry for the specified path name in this content.
+ * Returns the {@link ConnectEntry} for the specified path name in this
+ * content.
+ * <p>
* The {@link Optional#empty() empty} value is returned if an entry with the
* specified path name does not exist. The path must not start with a
* "/" and is relative to the root of this content. A connect
* entry for a directory will have a path name that ends with a slash ('/').
*
- * @param path the path name of the entry
- * @return the connect entry, or {@link Optional#empty() empty} if not
- * found.
- * @throws IllegalStateException if the connect content has been closed
+ * @param path The path name of the entry.
+ * @return An {@code Optional} containing the {@link ConnectEntry} for the
+ * specified path, or an empty {@code Optional} if no entry for
+ * specified path can be found.
+ * @throws IllegalStateException If this {@code ConnectContent} has been
+ * closed.
*/
Optional<ConnectEntry> getEntry(String path);
/**
- * Returns a class loader for this connect content. The
- * {@link Optional#empty() empty} value is returned if the framework should
- * handle creating a class loader for the bundle revision associated with
- * this connect content.
+ * Returns a class loader for this {@code ConnectContent}.
* <p>
* This method is called by the framework for {@link Bundle#RESOLVED
* resolved} bundles only and will be called at most once while a bundle is
- * resolved. If a bundle associated with a connect module is refreshed and
- * resolved again the framework will ask the content for the class loader
- * again. This allows for a connect content to reuse or create a new class
- * loader each time the bundle revision is resolved.
+ * resolved. If a bundle associated with a {@link ConnectModule} is
+ * refreshed and resolved again, the framework will ask the
+ * {@code ConnectContent} for the class loader again. This allows for a
+ * {@code ConnectContent} to reuse or create a new class loader each time
+ * the bundle revision is resolved.
*
- * @return a class loader for the module.
+ * @return An {@code Optional} containing the class loader for this
+ * {@code ConnectContent}, or an empty {@code Optional} if framework
+ * should handle creating a class loader for the bundle revision
+ * associated with this {@code ConnectContent}.
+ * @throws IllegalStateException If this {@code ConnectContent} has been
+ * closed.
*/
Optional<ClassLoader> getClassLoader();
/**
- * Opens this connect content. The framework will open the content when it
- * needs to access the content for a bundle revision associated with the
- * connect content. The framework may lazily postpone to open the content
- * until right before requests to access the bundle revision content are
- * made.
+ * Opens this {@code ConnectContent}.
+ * <p>
+ * The framework will open the content when it needs to access the content
+ * for a bundle revision associated with this {@code ConnectContent}. The
+ * framework may defer calling this method until requests to access the
+ * bundle revision content are made.
*
- * @throws IOException if an error occurred opening the content
+ * @throws IOException If an error occurred opening this
+ * {@code ConnectContent}.
*/
void open() throws IOException;
/**
- * Closes this connect content.
+ * Closes this {@code ConnectContent}.
*
- * @throws IOException if an error occurred closing the connect content
+ * @throws IOException If an error occurred closing this
+ * {@code ConnectContent}.
*/
void close() throws IOException;
/**
- * Represents the entry of a connect module
+ * Represents the entry of a {@code ConnectContent}.
*/
+ @ConsumerType
public interface ConnectEntry {
/**
- * Returns the path name of the entry
+ * Returns the path name of this entry.
*
- * @return the path name of the entry
+ * @return The path name of this entry.
*/
String getName();
/**
- * Returns the size of the entry. The value {@code -1} is returned if
- * the content length is not known.
+ * Returns the content length of this entry.
*
- * @return the size of the entry, or {@code -1} if the content length is
- * not known.
+ * @return The content length of the entry, or {@code -1} if the content
+ * length is not known.
*/
public long getContentLength();
/**
- * Returns the last modification time of the entry
+ * Returns the last modification time of this entry.
*
- * @return the last modification time of the entry
+ * @return The last modification time of this entry measured in
+ * milliseconds since the epoch (00:00:00 GMT, January 1, 1970).
*/
public long getLastModified();
/**
- * Returns the content of the entry as a byte array.
+ * Returns the content of this entry.
*
- * @return the content bytes
- * @throws IOException if an error occurs reading the content
+ * @return The content of this entry.
+ * @throws IOException If an error occurs reading the content.
*/
default byte[] getBytes() throws IOException {
long longLength = getContentLength();
@@ -190,10 +208,10 @@ public interface ConnectContent {
}
/**
- * Returns the content of the entry as an input stream.
+ * Returns an input stream for the content of this entry.
*
- * @return the content input stream
- * @throws IOException if an error occurs reading the content
+ * @return An input stream for the content of this entry.
+ * @throws IOException If an error occurs reading the content.
*/
InputStream getInputStream() throws IOException;
}
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java b/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java
index fe0a641..307f419 100644
--- a/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectFrameworkFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -24,7 +24,7 @@ import org.osgi.framework.launch.Framework;
/**
* A factory for creating {@link Framework} instances.
* <p>
- * If a framework supports {@link ModuleConnector} then the implementation jar
+ * If a framework supports {@link ModuleConnector}, then the implementation jar
* must contain the following resource:
*
* <pre>
@@ -45,7 +45,7 @@ import org.osgi.framework.launch.Framework;
* ConnectFrameworkFactory instance from the resource.
*
* @ThreadSafe
- * @author $Id: c1193dbc989c5cc0840f0b6a66a229b95d6fbc4e $
+ * @author $Id: fee4e88754bbaa4a88bcee0c0eaefa54893df6a1 $
*/
@ProviderType
public interface ConnectFrameworkFactory {
@@ -73,7 +73,6 @@ public interface ConnectFrameworkFactory {
* {@code AllPermission}, and the Java Runtime Environment
* supports permissions.
* @see ModuleConnector
- * @since 1.3
*/
Framework newFramework(Map<String,String> configuration,
ModuleConnector moduleConnector);
diff --git a/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java b/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java
index 6f48a00..d3b8376 100644
--- a/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java
+++ b/framework/src/main/java/org/osgi/framework/connect/ConnectModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -17,28 +17,30 @@ package org.osgi.framework.connect;
import java.io.IOException;
+import org.osgi.annotation.versioning.ConsumerType;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.wiring.BundleRevision;
/**
- * A connect module instance is used by a {@link Framework framework} when a
- * bundle location is connected to connect module. The connected bundle must use
- * the connect module to load content for the bundle revisions installed in the
- * framework for the connected bundle.
+ * A {@code ConnectModule} is used by a {@link Framework} instance to access the
+ * content of the connected bundle.
*
* @ThreadSafe
- * @author $Id: 421e5c4762caa3798def32c52c3c1347648a5606 $
+ * @author $Id: d81245bffb9c6de8e3d2e9515f1443b0f6b47189 $
*/
+@ConsumerType
public interface ConnectModule {
/**
- * Returns the current content of this connect module. The framework will
- * call this method when it needs to access the content for the current
- * {@link BundleRevision bundle revision} that is connected to this connect
- * module. The framework may lazily postpone to open the content until right
- * before requests to access the bundle revision content are made.
+ * Returns the current content of this connect module.
+ * <p>
+ * The framework must call this method when it needs to access the content
+ * for the current {@link BundleRevision bundle revision} of this
+ * {@code ConnectModule}. The framework may defer opening the returned
+ * {@link ConnectContent} until requests to access the bundle revision
+ * content are made.
*
- * @return the current content of this connect module
- * @throws IOException if an error occurred getting the content
+ * @return The current {@link ConnectContent} of this {@code ConnectModule}.
+ * @throws IOException If an error occurred getting the content.
* @see ModuleConnector#connect(String)
*/
ConnectContent getContent() throws IOException;
diff --git a/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java b/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java
index d418a6b..f7b54ab 100644
--- a/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java
+++ b/framework/src/main/java/org/osgi/framework/connect/FrameworkUtilHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -18,24 +18,29 @@ package org.osgi.framework.connect;
import java.util.Optional;
+import org.osgi.annotation.versioning.ConsumerType;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
/**
- * A helper for the {@link FrameworkUtil} class. This helper provides
- * alternative implementations for methods on {@link FrameworkUtil}.
+ * A helper for the {@link FrameworkUtil} class.
+ * <p>
+ * This helper provides alternative implementations for methods on
+ * {@link FrameworkUtil}.
*/
+@ConsumerType
public interface FrameworkUtilHelper {
/**
- * Return a {@code Bundle} associated with the specified class.
+ * Returns the {@link Bundle} associated with the specified class.
* <p>
* This helper method is called by {@link FrameworkUtil#getBundle(Class)} if
- * the standard implementation of {@code FrameworkUtil} cannot find the
- * bundle.
+ * the standard implementation of {@link FrameworkUtil} is unable to find
+ * the bundle.
*
- * @param classFromBundle A class associated with a bundle
- * @return An Optional containing a {@code Bundle} for the specified class
- * or an empty Optional if the specified class is not from a bundle.
+ * @param classFromBundle A class associated with a bundle.
+ * @return An {@code Optional} containing the {@link Bundle} for the
+ * specified class, or an empty {@code Optional} if the specified
+ * class is not from a bundle.
*/
default Optional<Bundle> getBundle(Class< ? > classFromBundle) {
return Optional.empty();
diff --git a/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java b/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java
index 4e2ef7c..e62b0e0 100644
--- a/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java
+++ b/framework/src/main/java/org/osgi/framework/connect/ModuleConnector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -19,77 +19,87 @@ import java.io.File;
import java.util.Map;
import java.util.Optional;
+import org.osgi.annotation.versioning.ConsumerType;
import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkListener;
import org.osgi.framework.launch.Framework;
/**
- * A <code>ModuleConnector</code> provides connections to instances of
+ * A {@code ModuleConnector} provides connections to instances of
* {@link ConnectModule} that are used by a {@link Framework} instance to
* connect installed bundles locations with content provided by the
- * <code>ModuleConnector</code>. This allows a <code>ModuleConnector</code> to
- * provide content and classes for a connected bundle installed in the
- * <code>Framework</code>. A <code>ModuleConnector</code> is provided when
- * {@link ConnectFrameworkFactory#newFramework(java.util.Map, ModuleConnector)
- * creating} a framework instance. Because a <code>ModuleConnector</code>
- * instance can participate in the initialization of the <code>Framework</code>
- * and the life cycle of a <code>Framework</code> instance the
- * <code>ModuleConnector</code> instance should only be used with a single
- * <code>Framework</code> instance at a time.
+ * {@code ModuleConnector}.
+ * <p>
+ * This allows a {@code ModuleConnector} to provide content and classes for a
+ * connected bundle installed in the {@code Framework}. A
+ * {@code ModuleConnector} is provided when
+ * {@link ConnectFrameworkFactory#newFramework(Map, ModuleConnector) creating} a
+ * framework instance. Because a {@code ModuleConnector} instance can
+ * participate in the initialization of the {@code Framework} and the life cycle
+ * of a {@code Framework} instance the {@code ModuleConnector} instance should
+ * only be used with a single {@code Framework} instance at a time.
*
* @ThreadSafe
- * @author $Id: 3f9a112c56a213eb81baf1fe568ce4f0ecdd1321 $
+ * @author $Id: 5ee358acfec177e4bf92994fee8e61c9c841ec06 $
*/
+@ConsumerType
public interface ModuleConnector {
/**
- * Initializes this module connector with the
+ * Initializes this {@code ModuleConnector} with the
* {@link Constants#FRAMEWORK_STORAGE framework persistent storage} file and
- * framework properties configured for a {@link Framework} instance. This
- * method is called once by a {@link Framework} instance and is called
+ * framework properties configured for a {@link Framework} instance.
+ * <p>
+ * This method is called once by a {@link Framework} instance and is called
* before any other methods on this module connector are called.
*
- * @param configuration The framework properties used configure the new
- * framework instance. An unmodifiable map of framework
- * configuration properties that were used to create a new
- * framework instance.
- * @param storage the persistent storage area used by the {@link Framework}
+ * @param storage The persistent storage area used by the {@link Framework}
* or {@code null} if the platform does not have file system
* support.
+ * @param configuration An unmodifiable map of framework configuration
+ * properties that were used to configure the new framework
+ * instance.
*/
void initialize(File storage, Map<String,String> configuration);
/**
- * Connects a bundle location with a {@link ConnectModule}. If an
- * {@link Optional#empty() empty} optional is returned the the framework
- * must handle reading the content of the bundle itself. If a value is
- * {@link Optional#isPresent() present} in the returned optional then the
- * <code>ConnectModule</code> {@link Optional#get() value} from the optional
- * must be used to connect the bundle to the returned {@link ConnectModule}.
- * The returned connect module is used by the framework to access the
- * content of the bundle.
+ * Connects a bundle location with a {@link ConnectModule}.
+ * <p>
+ * When the result is empty, then the framework must handle reading the
+ * content of the bundle itself. Otherwise, the returned
+ * {@link ConnectModule} must be used by the framework to access the content
+ * of the bundle.
*
- * @param location the bundle location used to install a bundle
- * @return the connect module for the specified bundle location
- * @throws BundleException if the location cannot be handled
+ * @param location The bundle location used to install a bundle.
+ * @return An {@code Optional} containing the {@link ConnectModule} for the
+ * specified bundle location, or an empty {@code Optional} if the
+ * framework must handle reading the content of the bundle itself.
+ * @throws BundleException If the location cannot be handled.
*/
Optional<ConnectModule> connect(String location) throws BundleException;
/**
- * Creates a new activator for this module connector. A new activator is
- * created by the framework each time the framework is
- * {@link Framework#init() initialized}. An activator allows the module
- * connector to participate in the framework life cycle. When the framework
- * is {@link Framework#init() initialized} the activator
- * {@link BundleActivator#start(org.osgi.framework.BundleContext) start}
- * method is called. When the framework is {@link Framework#stop() stopped}
- * the activator
- * {@link BundleActivator#stop(org.osgi.framework.BundleContext) stop}
- * method is called
+ * Creates a new activator for this {@code ModuleConnector}.
+ * <p>
+ * This method is called by the framework during framework
+ * {@link Framework#init(FrameworkListener...) initialization}. Returning an
+ * activator allows this {@code ModuleConnector} to participate in the
+ * framework life cycle. If an activator is returned:
+ * <ul>
+ * <li>The framework will call the activator's
+ * {@link BundleActivator#start(BundleContext) start} method prior to
+ * activating any extension bundles.</li>
+ * <li>The framework will call the activator's
+ * {@link BundleActivator#stop(BundleContext) stop} method after
+ * deactivating any extension bundles.</li>
+ * </ul>
*
- * @return a new activator for this module connector or
- * {@link Optional#empty() empty} if no activator is available
+ * @return An {@code Optional} containing a new {@link BundleActivator} for
+ * this {@code ModuleConnector}, or an empty {@code Optional} if no
+ * {@link BundleActivator} is necessary.
*/
Optional<BundleActivator> newBundleActivator();
}
diff --git a/framework/src/main/java/org/osgi/framework/connect/package-info.java b/framework/src/main/java/org/osgi/framework/connect/package-info.java
index 3ca3ca6..d4e22a4 100644
--- a/framework/src/main/java/org/osgi/framework/connect/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/connect/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2010, 2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2019, 2020). 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.
@@ -24,11 +24,10 @@
* <p>
* {@code Import-Package: org.osgi.framework.connect; version="[1.0,2.0)"}
*
- * @author $Id: a196dc76c5b8d5acb472bd10a4ab382ed58d92d1 $
+ * @author $Id: b7344ca62c5cef84330e009ce4a0704e4d83b6c0 $
*/
@Version("1.0")
package org.osgi.framework.connect;
import org.osgi.annotation.versioning.Version;
-
diff --git a/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java b/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
index 58429b4..6b83401 100644
--- a/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/BundleDTO.java
@@ -25,7 +25,7 @@ import org.osgi.framework.Bundle;
* <p>
* A Bundle can be adapted to provide a {@code BundleDTO} for the Bundle.
*
- * @author $Id: BundleDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: aa30709351d8fe70b19c9ea99456ebd15ecab7c3 $
* @NotThreadSafe
*/
public class BundleDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java b/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
index cd1c4e0..7b32f93 100644
--- a/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/FrameworkDTO.java
@@ -30,7 +30,7 @@ import org.osgi.framework.BundleContext;
* framework will contain only the launch properties of the framework. These
* properties will not include the System properties.
*
- * @author $Id: FrameworkDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 7c525727cbe877e888b460cd14d8f9054f99ee0c $
* @NotThreadSafe
*/
public class FrameworkDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java b/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
index 0ee46b7..2f92fb1 100644
--- a/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
+++ b/framework/src/main/java/org/osgi/framework/dto/ServiceReferenceDTO.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2019). 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.
@@ -17,22 +17,23 @@
package org.osgi.framework.dto;
import java.util.Map;
+
import org.osgi.dto.DTO;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
/**
* Data Transfer Object for a ServiceReference.
- *
* <p>
* {@code ServiceReferenceDTO}s for all registered services can be obtained from
- * a {@link FrameworkDTO}. A started Bundle can be adapted to provide a
+ * a {@link FrameworkDTO}. A {@link ServiceReference} can be adapted to a
+ * {@code ServiceReferenceDTO}. A started Bundle can be adapted to provide a
* {@code ServiceReferenceDTO[]} of the services registered by the Bundle. A
* {@code ServiceReferenceDTO} obtained from a framework must convert service
* property values which are not valid value types for DTOs to type
* {@code String} using {@code String.valueOf(Object)}.
*
- * @author $Id: ServiceReferenceDTO.java 1825132 2018-02-23 15:11:00Z pauls $
+ * @author $Id: 8ac26a24b8adacdcd09f441dcdfc8d6a27bbaabd $
* @NotThreadSafe
*/
public class ServiceReferenceDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/dto/package-info.java b/framework/src/main/java/org/osgi/framework/dto/package-info.java
index 286362b..4499fc8 100644
--- a/framework/src/main/java/org/osgi/framework/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/dto/package-info.java
@@ -32,7 +32,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.dto; version="[1.8,1.9)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 2acfb6f1633e18f1ceedd27c04e70131cae4f293 $
*/
@Version("1.8")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
index f701a5f..ce89815 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/bundle/package-info.java
@@ -26,7 +26,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.hooks.bundle; version="[1.1,2.0)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 08c20cab669f1850f585c5cd4b3b897ce587b2bd $
*/
@Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
index 2f447ff..6333093 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/resolver/package-info.java
@@ -26,7 +26,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.hooks.resolver; version="[1.0,2.0)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: de050037c6b835045603f09b12ad58a6353d1229 $
*/
@Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
index 1cdd0e9..5fd8020 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/service/package-info.java
@@ -26,7 +26,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.hooks.service; version="[1.1,2.0)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 74f0c41d5ebf20181942ee393965d885deb3889c $
*/
@Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
index 254dd9b..8768402 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2020). 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.
@@ -18,12 +18,11 @@ package org.osgi.framework.hooks.weaving;
/**
* A weaving exception used to indicate that the class load should be failed but
- * the weaving hook must not be blacklisted by the framework.
- *
+ * the weaving hook must not be deny listed by the framework.
* <p>
* This exception conforms to the general purpose exception chaining mechanism.
*
- * @author $Id: 7575fc1b015fea7c77397391df6c8d2085513e76 $
+ * @author $Id: 29ebe6460fbe20ce8037f14a162c72f633b1de31 $
*/
public class WeavingException extends RuntimeException {
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
index 760b00c..b3e7ac4 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WeavingHook.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2010, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2020). 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.
@@ -36,30 +36,29 @@ import org.osgi.annotation.versioning.ConsumerType;
* bytes as modified by previously called weaving hooks.
*
* @ThreadSafe
- * @author $Id: 8d99df5b0f3e7ffa9573695923afe86de9835fde $
+ * @author $Id: e5b54121d2cab7caefbae3b718421b28e5a9ede7 $
*/
@ConsumerType
public interface WeavingHook {
/**
* Weaving hook method.
- *
+ * <p>
* This method can modify the specified woven class object to weave the
* class being defined.
- *
* <p>
* If this method throws any exception, the framework must log the exception
* and fail the class load in progress. This weaving hook service must be
- * blacklisted by the framework and must not be called again. The
- * blacklisting of this weaving hook service must expire when this weaving
- * hook service is unregistered. However, this method can throw a
+ * deny listed by the framework and must not be called again. The deny
+ * listing of this weaving hook service must expire when this weaving hook
+ * service is unregistered. However, this method can throw a
* {@link WeavingException} to deliberately fail the class load in progress
- * without being blacklisted by the framework.
+ * without being deny listed by the framework.
*
* @param wovenClass The {@link WovenClass} object that represents the data
- * that will be used to define the class.
+ * that will be used to define the class.
* @throws WeavingException If this weaving hook wants to deliberately fail
- * the class load in progress without being blacklisted by the
- * framework
+ * the class load in progress without being deny listed by the
+ * framework
*/
public void weave(WovenClass wovenClass);
}
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
index 915b249..36e7303 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/WovenClassListener.java
@@ -47,7 +47,7 @@ import org.osgi.annotation.versioning.ConsumerType;
*
* @ThreadSafe
* @since 1.1
- * @author $Id: WovenClassListener.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 4a7a69943bffbc53738f050c51d49f11b67a13cb $
*/
@ConsumerType
public interface WovenClassListener {
diff --git a/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java b/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
index 05810dd..bffee3e 100644
--- a/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/hooks/weaving/package-info.java
@@ -28,7 +28,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.hooks.weaving; version="[1.1,2.0)"}
* </p>
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 5b48f041a1764e8b2979cdbbb528082054ab3e7f $
*/
@Version("1.1")
diff --git a/framework/src/main/java/org/osgi/framework/launch/Framework.java b/framework/src/main/java/org/osgi/framework/launch/Framework.java
index 37a519d..fd6d325 100644
--- a/framework/src/main/java/org/osgi/framework/launch/Framework.java
+++ b/framework/src/main/java/org/osgi/framework/launch/Framework.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2008, 2018). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2008, 2020). 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.
@@ -19,6 +19,7 @@ package org.osgi.framework.launch;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
+
import org.osgi.annotation.versioning.ProviderType;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
@@ -35,7 +36,7 @@ import org.osgi.framework.FrameworkListener;
* instance.
*
* @ThreadSafe
- * @author $Id: 7fa67978e59a43dfedd6e755ddfa5b1aa6ea9141 $
+ * @author $Id: bf960bdc39d19a780694a8cab5a555b3e0dc0fde $
*/
@ProviderType
public interface Framework extends Bundle {
@@ -117,37 +118,33 @@ public interface Framework extends Bundle {
* A Framework Event is returned to indicate why this Framework has stopped.
*
* @param timeout Maximum number of milliseconds to wait until this
- * Framework has completely stopped. A value of zero will wait
- * indefinitely.
+ * Framework has completely stopped. A value of zero will wait
+ * indefinitely.
* @return A Framework Event indicating the reason this method returned. The
* following {@code FrameworkEvent} types may be returned by this
* method.
* <ul>
* <li>{@link FrameworkEvent#STOPPED STOPPED} - This Framework has
- * been stopped. </li>
- *
+ * been stopped.</li>
* <li>{@link FrameworkEvent#STOPPED_UPDATE STOPPED_UPDATE} - This
* Framework has been updated which has shutdown and will now
* restart.</li>
- *
- * <li> {@link FrameworkEvent#STOPPED_BOOTCLASSPATH_MODIFIED
- * STOPPED_BOOTCLASSPATH_MODIFIED} - This Framework has been stopped
- * and a bootclasspath extension bundle has been installed or
- * updated. The VM must be restarted in order for the changed boot
- * class path to take effect. </li>
- *
+ * <li>{@link FrameworkEvent#STOPPED_SYSTEM_REFRESHED
+ * STOPPED_SYSTEM_REFRESHED} - The Framework has been stopped
+ * because of a refresh operation on the system bundle. A new class
+ * loader must be used to restart the Framework.</li>
* <li>{@link FrameworkEvent#ERROR ERROR} - The Framework
* encountered an error while shutting down or an error has occurred
- * which forced the framework to shutdown. </li>
- *
- * <li> {@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
+ * which forced the framework to shutdown.</li>
+ * <li>{@link FrameworkEvent#WAIT_TIMEDOUT WAIT_TIMEDOUT} - This
* method has timed out and returned before this Framework has
* stopped.</li>
* </ul>
* @throws InterruptedException If another thread interrupted the current
- * thread before or while the current thread was waiting for this
- * Framework to completely stop. The <i>interrupted status</i> of
- * the current thread is cleared when this exception is thrown.
+ * thread before or while the current thread was waiting for
+ * this Framework to completely stop. The <i>interrupted
+ * status</i> of the current thread is cleared when this
+ * exception is thrown.
* @throws IllegalArgumentException If the value of timeout is negative.
*/
FrameworkEvent waitForStop(long timeout) throws InterruptedException;
diff --git a/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
index 6d656d3..f5e29a9 100644
--- a/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
+++ b/framework/src/main/java/org/osgi/framework/launch/FrameworkFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2009, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2009, 2019). 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.
@@ -17,6 +17,7 @@
package org.osgi.framework.launch;
import java.util.Map;
+
import org.osgi.annotation.versioning.ProviderType;
import org.osgi.framework.Bundle;
@@ -45,7 +46,7 @@ import org.osgi.framework.Bundle;
* the resource.
*
* @ThreadSafe
- * @author $Id: c1647bcb8416b6dfa9e37c6cc146bb54c7173526 $
+ * @author $Id: ecb53ee09a939a2c23a47ecad6f94fcfdf2f7c46 $
*/
@ProviderType
public interface FrameworkFactory {
diff --git a/framework/src/main/java/org/osgi/framework/launch/package-info.java b/framework/src/main/java/org/osgi/framework/launch/package-info.java
index ca81049..77d416f 100644
--- a/framework/src/main/java/org/osgi/framework/launch/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/launch/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2010, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2019). 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.
@@ -26,7 +26,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.launch; version="[1.2,2.0)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 70417d372c5e8200dc743847b14aeb300870b839 $
*/
@Version("1.2")
diff --git a/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
index 2f843a8..c6af9d8 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/HostNamespace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). 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.
@@ -54,19 +54,19 @@ import org.osgi.resource.Namespace;
* </ul>
*
* <p>
- * A non-fragment resource with the with the
- * {@link IdentityNamespace#TYPE_BUNDLE osgi.bundle} type
- * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} provides zero or
- * one<sup>†</sup> host capabilities. A fragment resource with the
- * {@link IdentityNamespace#TYPE_FRAGMENT osgi.fragment} type
- * {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE identity} must not declare
- * a host capability and must declare exactly one host requirement.
+ * A non-fragment resource with the {@link IdentityNamespace#TYPE_BUNDLE
+ * osgi.bundle} type {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
+ * identity} provides zero or one<sup>†</sup> host capabilities. A
+ * fragment resource with the {@link IdentityNamespace#TYPE_FRAGMENT
+ * osgi.fragment} type {@link IdentityNamespace#CAPABILITY_TYPE_ATTRIBUTE
+ * identity} must not declare a host capability and must declare exactly one
+ * host requirement.
* <p>
* † A resource with no bundle symbolic name must not provide a host
* capability.
*
* @Immutable
- * @author $Id: 9f789ca25dafcf9d5e9a4f45d377f943d62b134a $
+ * @author $Id: 79484b4d0c372d8cebf7c767ec12e134b60b8411 $
*/
public final class HostNamespace extends AbstractWiringNamespace {
@@ -135,7 +135,6 @@ public final class HostNamespace extends AbstractWiringNamespace {
* fragment. The default value is {@link #EXTENSION_FRAMEWORK framework}.
*
* @see #EXTENSION_FRAMEWORK
- * @see #EXTENSION_BOOTCLASSPATH
*/
public final static String REQUIREMENT_EXTENSION_DIRECTIVE = "extension";
@@ -153,6 +152,7 @@ public final class HostNamespace extends AbstractWiringNamespace {
* loaded by the boot class loader.
*
* @see #REQUIREMENT_EXTENSION_DIRECTIVE
+ * @deprecated As of 1.2.
*/
public final static String EXTENSION_BOOTCLASSPATH = "bootclasspath";
diff --git a/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
index ffb9703..3ef3f11 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/IdentityNamespace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2019). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). 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.
@@ -41,7 +41,7 @@ import org.osgi.resource.Namespace;
* capability.
*
* @Immutable
- * @author $Id: 27ae5d1c50d9fffcd7089d0fb225d8e793c4677a $
+ * @author $Id: d2357fa05b1e68f952710e07a2fab46bf4ea3cec $
*/
public final class IdentityNamespace extends Namespace {
diff --git a/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java b/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
index eb30c71..4376082 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/NativeNamespace.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2020). 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.
@@ -31,7 +31,7 @@ import org.osgi.resource.Namespace;
*
* @Immutable
* @since 1.1
- * @author $Id: NativeNamespace.java 1825132 2018-02-23 15:11:00Z pauls $
+ * @author $Id: f252fb2850001968fe0ee4e741a66847560dce33 $
*/
public final class NativeNamespace extends Namespace {
@@ -44,7 +44,7 @@ public final class NativeNamespace extends Namespace {
* The capability attribute contains alias values of the
* {@link Constants#FRAMEWORK_OS_NAME org.osgi.framework.os.name} launching
* property value according to the
- * <a href="https://www.osgi.org/developer/specifications/reference/">OSGi
+ * <a href="https://docs.osgi.org/reference/">OSGi
* Specification References</a>. The value of this attribute must be of type
* {@code List<String>}.
*/
@@ -62,7 +62,7 @@ public final class NativeNamespace extends Namespace {
* The capability attribute contains alias values of the
* {@link Constants#FRAMEWORK_PROCESSOR org.osgi.framework.processor}
* launching property value according to the
- * <a href="https://www.osgi.org/developer/specifications/reference/">OSGi
+ * <a href="https://docs.osgi.org/reference/">OSGi
* Specification References</a>. The value of this attribute must be of type
* {@code List<String>}.
*/
diff --git a/framework/src/main/java/org/osgi/framework/namespace/package-info.java b/framework/src/main/java/org/osgi/framework/namespace/package-info.java
index 7d661e3..78fec59 100644
--- a/framework/src/main/java/org/osgi/framework/namespace/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/namespace/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2013). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2012, 2019). 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.
@@ -15,17 +15,17 @@
*/
/**
- * Namespace Package Version 1.1.
+ * Namespace Package Version 1.2.
*
* <p>
* Bundles should not need to import this package at runtime since all
* the types in this package just contain constants for capability and
* requirement namespaces specified by the OSGi Alliance.
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 43f3804d39ad166dc082926b3a3679be67962fcc $
*/
-@Version("1.1")
+@Version("1.2")
package org.osgi.framework.namespace;
import org.osgi.annotation.versioning.Version;
diff --git a/framework/src/main/java/org/osgi/framework/package-info.java b/framework/src/main/java/org/osgi/framework/package-info.java
index a4283d3..44ad83a 100644
--- a/framework/src/main/java/org/osgi/framework/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2010, 2016). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2010, 2019). 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.
@@ -15,16 +15,16 @@
*/
/**
- * Framework Package Version 1.9.
+ * Framework Package Version 1.10.
* <p>
* Bundles wishing to use this package must list the package in the
* Import-Package header of the bundle's manifest.
* <p>
* Example import for consumers using the API in this package:
* <p>
- * {@code Import-Package: org.osgi.framework; version="[1.9,2.0)"}
+ * {@code Import-Package: org.osgi.framework; version="[1.10,2.0)"}
*
- * @author $Id: package-info.java 1874504 2020-02-25 15:53:01Z pauls $
+ * @author $Id: 5b7956509a6fcf8b3f7ad23ca343dcae27cf37c6 $
*/
@Version("1.10")
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
index f430124..c36575b 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/BundleStartLevelDTO.java
@@ -26,7 +26,7 @@ import org.osgi.framework.startlevel.BundleStartLevel;
* An installed Bundle can be adapted to provide a {@code BundleStartLevelDTO}
* for the Bundle.
*
- * @author $Id: BundleStartLevelDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 81430e24483d75fd406e57214284ec43b4b3f6a7 $
* @NotThreadSafe
*/
public class BundleStartLevelDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
index 0ea44fe..cf9ff88 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/FrameworkStartLevelDTO.java
@@ -26,7 +26,7 @@ import org.osgi.framework.startlevel.FrameworkStartLevel;
* The System Bundle can be adapted to provide a {@code FrameworkStartLevelDTO}
* for the framework of the Bundle.
*
- * @author $Id: FrameworkStartLevelDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 2d1de40ba2b1d12832ebe0e5cdd4f789d439b6f6 $
* @NotThreadSafe
*/
public class FrameworkStartLevelDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java b/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
index 2ef56ec..cef11d9 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/dto/package-info.java
@@ -32,7 +32,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.startlevel.dto; version="[1.0,1.1)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 62262c52e6446fbe4a7b29725881f01791396c29 $
*/
@Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/startlevel/package-info.java b/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
index 14618ed..3265948 100644
--- a/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/startlevel/package-info.java
@@ -73,7 +73,7 @@
* Import-Package: org.osgi.framework.startlevel; version="[1.0,2.0)"
* </pre>
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 27d775bbe53df5e1dd5d7fe6f5e1c95b294c2301 $
*/
@Version("1.0")
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
index b9d4580..1358b2a 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleRevisionDTO.java
@@ -28,7 +28,7 @@ import org.osgi.resource.dto.ResourceDTO;
* in use revisions of the Bundle can be obtained by adapting the bundle to
* {@code BundleRevisionDTO[]}.
*
- * @author $Id: BundleRevisionDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 43d74167b8b59468b148ceb9dcde4509b68c2a90 $
* @NotThreadSafe
*/
public class BundleRevisionDTO extends ResourceDTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
index 967ece4..b55e634 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWireDTO.java
@@ -26,7 +26,7 @@ import org.osgi.resource.dto.WiringDTO;
* <p>
* {@code BundleWireDTO}s are referenced {@link BundleWiringDTO.NodeDTO}s.
*
- * @author $Id: BundleWireDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: ef923b41460de6d3e34fad73dc794a788533c1e9 $
* @NotThreadSafe
*/
public class BundleWireDTO extends WireDTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
index 74f0b35..a95c185 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/BundleWiringDTO.java
@@ -30,7 +30,7 @@ import org.osgi.resource.dto.WiringDTO;
* wirings of the Bundle can be obtained by adapting the bundle to
* {@code BundleWiringDTO[]}.
*
- * @author $Id: BundleWiringDTO.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: e23e80fcf8a14cbc9f565ec146821a4f22f2731b $
* @NotThreadSafe
*/
public class BundleWiringDTO extends DTO {
diff --git a/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java b/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
index 8db1a91..6a41ae5 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/dto/package-info.java
@@ -30,7 +30,7 @@
* <p>
* {@code Import-Package: org.osgi.framework.wiring.dto; version="[1.3,1.4)"}
*
- * @author $Id: package-info.java 1825132 2018-02-23 15:11:00Z pauls $
+ * @author $Id: 47eb1eed801ba77d58d8807aa85e9e000bca00d0 $
*/
@Version("1.3")
diff --git a/framework/src/main/java/org/osgi/framework/wiring/package-info.java b/framework/src/main/java/org/osgi/framework/wiring/package-info.java
index 27c3f94..199d60c 100644
--- a/framework/src/main/java/org/osgi/framework/wiring/package-info.java
+++ b/framework/src/main/java/org/osgi/framework/wiring/package-info.java
@@ -25,7 +25,7 @@
* Import-Package: org.osgi.framework.wiring; version="[1.2,2.0)"
* </pre>
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 6fb7232ca6c7b389c20f75566a46c4022b8dd5d5 $
*/
@Version("1.2")
diff --git a/framework/src/main/java/org/osgi/service/condition/Condition.java b/framework/src/main/java/org/osgi/service/condition/Condition.java
new file mode 100755
index 0000000..fcd6da8
--- /dev/null
+++ b/framework/src/main/java/org/osgi/service/condition/Condition.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) OSGi Alliance (2020). 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.condition;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Condition Service interface.
+ * <p>
+ * In dynamic systems, such as OSGi, one of the more challenging problems can be
+ * to define when a system or part of it is ready to do work. The answer can
+ * change depending on the individual perspective. The developer of a web server
+ * might say, the system is ready when the server starts listening on port 80.
+ * An application developer however would define the system as ready when the
+ * database connection is up and all servlets are registered. Taking the
+ * application developers view, the web server should start listening on port 80
+ * when the application is ready and not beforehand.
+ * <p>
+ * The {@code Condition} service interface is a marker interface designed to
+ * address this issue. Its role is to provide a dependency that can be tracked.
+ * It acts as a defined signal to other services.
+ * <p>
+ * A {@code Condition} service must be registered with the
+ * {@link Condition#CONDITION_ID} service property.
+ *
+ * @ThreadSafe
+ * @author $Id: 9736e5e1c38c45254f733d73ed7ae2c0e253f544 $
+ */
+@ConsumerType
+public interface Condition {
+
+ /**
+ * Service property identifying a condition's unique identifier.
+ * <p>
+ * Since a {@code Condition} service can potentially describe more then one
+ * condition, the type of this service property is {@code String+}.
+ */
+ String CONDITION_ID = "osgi.condition.id";
+
+ /**
+ * The unique identifier for the default True condition.
+ * <p>
+ * The default True condition is registered by the framework during
+ * framework initialization and therefore can always be relied upon.
+ *
+ * @see Condition#CONDITION_ID
+ */
+ String CONDITION_ID_TRUE = "true";
+
+ /**
+ * A condition instance that can be used to register {@code Condition}
+ * services.
+ * <p>
+ * This can be helpful to avoid a bundle having to implement this interface
+ * to register a {@code Condition} service
+ */
+ Condition INSTANCE = new ConditionImpl();
+}
+
+final class ConditionImpl implements Condition {
+ ConditionImpl() {
+ }
+}
diff --git a/framework/src/main/java/org/osgi/framework/dto/package-info.java b/framework/src/main/java/org/osgi/service/condition/package-info.java
old mode 100644
new mode 100755
similarity index 72%
copy from framework/src/main/java/org/osgi/framework/dto/package-info.java
copy to framework/src/main/java/org/osgi/service/condition/package-info.java
index 286362b..a3ddce5
--- a/framework/src/main/java/org/osgi/framework/dto/package-info.java
+++ b/framework/src/main/java/org/osgi/service/condition/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) OSGi Alliance (2012, 2014). All Rights Reserved.
+ * Copyright (c) OSGi Alliance (2020). 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.
@@ -15,28 +15,25 @@
*/
/**
- * OSGi Data Transfer Object Framework Package Version 1.8.
- *
+ * Condition Service Package Version 1.0.
* <p>
* Bundles wishing to use this package must list the package in the
* Import-Package header of the bundle's manifest. This package has two types of
* users: the consumers that use the API in this package and the providers that
* implement the API in this package.
- *
* <p>
* Example import for consumers using the API in this package:
* <p>
- * {@code Import-Package: org.osgi.framework.dto; version="[1.8,2.0)"}
+ * {@code Import-Package: org.osgi.service.condition; version="[1.0,2.0)"}
* <p>
* Example import for providers implementing the API in this package:
* <p>
- * {@code Import-Package: org.osgi.framework.dto; version="[1.8,1.9)"}
+ * {@code Import-Package: org.osgi.service.condition; version="[1.0,1.1)"}
*
- * @author $Id: package-info.java 1614569 2014-07-30 07:22:32Z cziegeler $
+ * @author $Id: 52df94eac922bd9d4f2f680cdd98e6d405844958 $
*/
-@Version("1.8")
-package org.osgi.framework.dto;
+@Version("1.0")
+package org.osgi.service.condition;
import org.osgi.annotation.versioning.Version;
-
diff --git a/framework/src/main/resources/default.properties b/framework/src/main/resources/default.properties
index e2396ba..a46c5f3 100644
--- a/framework/src/main/resources/default.properties
+++ b/framework/src/main/resources/default.properties
@@ -106,13 +106,14 @@ org.osgi.framework.system.packages=\
osgi-exports= \
org.osgi.framework;version="1.10", \
+ org.osgi.framework.connect;version="1.0.0", \
org.osgi.framework.dto;version="1.8";uses:="org.osgi.dto", \
org.osgi.framework.hooks.bundle;version="1.1";uses:="org.osgi.framework", \
org.osgi.framework.hooks.resolver;version="1.0";uses:="org.osgi.framework.wiring", \
org.osgi.framework.hooks.service;version="1.1";uses:="org.osgi.framework", \
org.osgi.framework.hooks.weaving;version="1.1";uses:="org.osgi.framework.wiring", \
org.osgi.framework.launch;version="1.2";uses:="org.osgi.framework", \
- org.osgi.framework.namespace;version="1.1";uses:="org.osgi.resource", \
+ org.osgi.framework.namespace;version="1.2";uses:="org.osgi.resource", \
org.osgi.framework.startlevel;version="1.0";uses:="org.osgi.framework", \
org.osgi.framework.startlevel.dto;version="1.0";uses:="org.osgi.dto", \
org.osgi.framework.wiring;version="1.2";uses:="org.osgi.framework,org.osgi.resource", \
@@ -125,7 +126,7 @@ osgi-exports= \
org.osgi.service.resolver;version="1.1";uses:="org.osgi.resource", \
org.osgi.util.tracker;version="1.5.2";uses:="org.osgi.framework", \
org.osgi.dto;version="1.1", \
- org.osgi.framework.connect;version="1.0.0"
+ org.osgi.service.condition;version="1.0"
#
# Java platform package export properties.