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>
+ *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
+ *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
+ *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
+ *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
+ *   &lt;not&gt; ::= '!' &lt;filter&gt;
+ *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
+ *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
+ *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
+ *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
+ *   &lt;equal&gt; ::= '='
+ *   &lt;approx&gt; ::= '&tilde;='
+ *   &lt;greater&gt; ::= '&gt;='
+ *   &lt;less&gt; ::= '&lt;='
+ *   &lt;present&gt; ::= &lt;attr&gt; '=*'
+ *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
+ *   &lt;initial&gt; ::= NULL | &lt;value&gt;
+ *   &lt;any&gt; ::= '*' &lt;starval&gt;
+ *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
+ *   &lt;final&gt; ::= NULL | &lt;value&gt;
+ * </pre>
+ * 
+ * {@code &lt;attr&gt;} 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 &lt;value&gt;} is a string representing the value, or part of one, of
+ * a key in the properties objects of the registered services. If a
+ * {@code &lt;value&gt;} 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 &lt;substring&gt;} and {@code &lt;present&gt;} productions can produce
+ * the {@code 'attr=*'} construct, this construct is used only to denote a
+ * presence filter.
+ * <p>
+ * Examples of LDAP filters are:
+ * 
+ * <pre>
+ *   &quot;(cn=Babs Jensen)&quot;
+ *   &quot;(!(cn=Tim Howes))&quot;
+ *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
+ *   &quot;(o=univ*of*mich*)&quot;
+ * </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(&quot;cn&quot;, new String[] {
+ * 		&quot;a&quot;, &quot;b&quot;, &quot;c&quot;
+ * });
+ * </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 &amp; 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 '-'} &#92;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>
-	 *   &lt;filter&gt; ::= '(' &lt;filtercomp&gt; ')'
-	 *   &lt;filtercomp&gt; ::= &lt;and&gt; | &lt;or&gt; | &lt;not&gt; | &lt;item&gt;
-	 *   &lt;and&gt; ::= '&amp;' &lt;filterlist&gt;
-	 *   &lt;or&gt; ::= '|' &lt;filterlist&gt;
-	 *   &lt;not&gt; ::= '!' &lt;filter&gt;
-	 *   &lt;filterlist&gt; ::= &lt;filter&gt; | &lt;filter&gt; &lt;filterlist&gt;
-	 *   &lt;item&gt; ::= &lt;simple&gt; | &lt;present&gt; | &lt;substring&gt;
-	 *   &lt;simple&gt; ::= &lt;attr&gt; &lt;filtertype&gt; &lt;value&gt;
-	 *   &lt;filtertype&gt; ::= &lt;equal&gt; | &lt;approx&gt; | &lt;greater&gt; | &lt;less&gt;
-	 *   &lt;equal&gt; ::= '='
-	 *   &lt;approx&gt; ::= '&tilde;='
-	 *   &lt;greater&gt; ::= '&gt;='
-	 *   &lt;less&gt; ::= '&lt;='
-	 *   &lt;present&gt; ::= &lt;attr&gt; '=*'
-	 *   &lt;substring&gt; ::= &lt;attr&gt; '=' &lt;initial&gt; &lt;any&gt; &lt;final&gt;
-	 *   &lt;initial&gt; ::= NULL | &lt;value&gt;
-	 *   &lt;any&gt; ::= '*' &lt;starval&gt;
-	 *   &lt;starval&gt; ::= NULL | &lt;value&gt; '*' &lt;starval&gt;
-	 *   &lt;final&gt; ::= NULL | &lt;value&gt;
-	 * </pre>
-	 * 
-	 * {@code &lt;attr&gt;} 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 &lt;value&gt;} is a string representing the value, or part of one,
-	 * of a key in the properties objects of the registered services. If a
-	 * {@code &lt;value&gt;} 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 &lt;substring&gt;} and {@code &lt;present&gt;}
-	 * productions can produce the {@code 'attr=*'} construct, this construct is
-	 * used only to denote a presence filter.
-	 * 
-	 * <p>
-	 * Examples of LDAP filters are:
-	 * 
-	 * <pre>
-	 *   &quot;(cn=Babs Jensen)&quot;
-	 *   &quot;(!(cn=Tim Howes))&quot;
-	 *   &quot;(&amp;(&quot; + Constants.OBJECTCLASS + &quot;=Person)(|(sn=Jensen)(cn=Babs J*)))&quot;
-	 *   &quot;(o=univ*of*mich*)&quot;
-	 * </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(&quot;cn&quot;, new String[] {&quot;a&quot;, &quot;b&quot;, &quot;c&quot;});
-	 * </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 &amp; 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 '-'} &#92;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
 	 * &quot;/&quot; 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>&#8224;</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>&#8224;</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>
  * &#8224; 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=&quot;[1.0,2.0)&quot;
  * </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=&quot;[1.2,2.0)&quot;
  * </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.