Author: davidb Date: Fri Apr 20 06:34:25 2018 New Revision: 1829625 URL: http://svn.apache.org/viewvc?rev=1829625&view=rev Log: Improvements to the OSGi Capability and Requirement implementations
These come from the Apache Sling Whitenboard Feature Model project. Merged with Felix Utils to increase sharing across projects. Added: felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/AbstractCapabilityRequirement.java Modified: felix/trunk/utils/pom.xml felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/CapabilityImpl.java felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/RequirementImpl.java felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/CapabilityImplTest.java felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/RequirementImplTest.java Modified: felix/trunk/utils/pom.xml URL: http://svn.apache.org/viewvc/felix/trunk/utils/pom.xml?rev=1829625&r1=1829624&r2=1829625&view=diff ============================================================================== --- felix/trunk/utils/pom.xml (original) +++ felix/trunk/utils/pom.xml Fri Apr 20 06:34:25 2018 @@ -27,7 +27,7 @@ <modelVersion>4.0.0</modelVersion> <name>Apache Felix Utils</name> <description>Utility classes for OSGi.</description> - <version>1.10.5-SNAPSHOT</version> + <version>1.11.0-SNAPSHOT</version> <artifactId>org.apache.felix.utils</artifactId> <scm> Added: felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/AbstractCapabilityRequirement.java URL: http://svn.apache.org/viewvc/felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/AbstractCapabilityRequirement.java?rev=1829625&view=auto ============================================================================== --- felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/AbstractCapabilityRequirement.java (added) +++ felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/AbstractCapabilityRequirement.java Fri Apr 20 06:34:25 2018 @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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.apache.felix.utils.capabilities; + +import org.osgi.resource.Resource; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +abstract class AbstractCapabilityRequirement { + + /** The namespace. Required. */ + private final String namespace; + + /** Optional resource. */ + private volatile Resource resource; + + /** Optional attributes. Never null. */ + private final Map<String, Object> attributes; + + /** Optional attributes. Never null. */ + private final Map<String, String> directives; + + AbstractCapabilityRequirement(final String ns, final Map<String, Object> attrs, final Map<String, String> dirs, final Resource res) { + if ( ns == null ) { + throw new IllegalArgumentException("Namespace must not be null."); + } + namespace = ns; + attributes = attrs == null + ? Collections.<String, Object>emptyMap() + : Collections.unmodifiableMap(new HashMap<String, Object>(attrs)); + directives = dirs == null + ? Collections.<String,String>emptyMap() + : Collections.unmodifiableMap(new HashMap<String,String>(dirs)); + resource = res; + } + + /** + * Return the namespace. + * @return The namespace. This is never @{code null}. + */ + public String getNamespace() { + return namespace; + } + + /** + * Return the attributes. + * @return The attributes, might be empty. + */ + public Map<String, Object> getAttributes() { + return attributes; + } + + /** + * Return the directives. + * @return The directives, might be empty. + */ + public Map<String, String> getDirectives() { + return directives; + } + + /** + * Return the resource. + * @return The resource or @{code null}. + */ + public Resource getResource() { + return resource; + } + + /** + * Set the resource associated with this requirement. + * + * @param res The resource. + */ + public void setResource(Resource res) { + resource = res; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + attributes.hashCode(); + result = prime * result + directives.hashCode(); + result = prime * result + namespace.hashCode(); + + if (resource != null) + result = prime * result + resource.hashCode(); + + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbstractCapabilityRequirement other = (AbstractCapabilityRequirement) obj; + if (!namespace.equals(other.namespace)) + return false; + if (!attributes.equals(other.attributes)) + return false; + if (!directives.equals(other.directives)) + return false; + if (resource == null) { + return other.resource == null; + } else { + return resource.equals(other.resource); + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + " [resource=" + resource + ", namespace=" + namespace + ", attributes=" + attributes + + ", directives=" + directives + "]"; + } +} Modified: felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/CapabilityImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/CapabilityImpl.java?rev=1829625&r1=1829624&r2=1829625&view=diff ============================================================================== --- felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/CapabilityImpl.java (original) +++ felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/CapabilityImpl.java Fri Apr 20 06:34:25 2018 @@ -1,161 +1,59 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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 + * 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. + * 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.apache.felix.utils.capabilities; import org.osgi.resource.Capability; import org.osgi.resource.Resource; -import java.util.Collections; import java.util.Map; /** * Implementation of the OSGi Capability interface. */ -public class CapabilityImpl implements Capability -{ - private final String namespace; - private final Map<String, Object> attributes; - private final Map<String, String> directives; - private volatile Resource resource; - +public class CapabilityImpl extends AbstractCapabilityRequirement implements Capability { /** - * Create a capability. - * + * Create a capability that is not associated with a resource. + * @param res The resource associated with the capability. May be null. * @param ns The namespace of the capability. * @param attrs The attributes of the capability. * @param dirs The directives of the capability. */ - public CapabilityImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs) - { + public CapabilityImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs) { this(ns, attrs, dirs, null); } /** * Create a capability. - * * @param ns The namespace of the capability. * @param attrs The attributes of the capability. * @param dirs The directives of the capability. - * @param res The resource associated with the capability. - */ - public CapabilityImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs, Resource res) - { - namespace = ns; - attributes = Collections.unmodifiableMap(attrs); - directives = Collections.unmodifiableMap(dirs); - resource = res; - } - - /** - * Returns the namespace of this capability. - * - * @return The namespace of this capability. - */ - public String getNamespace() - { - return namespace; - } - - /** - * Returns the attributes of this capability. - * - * @return An unmodifiable map of attribute names to attribute values for - * this capability, or an empty map if this capability has no - * attributes. - */ - public Map<String, Object> getAttributes() - { - return attributes; - } - - /** - * Returns the directives of this capability. - * - * @return An unmodifiable map of directive names to directive values for - * this capability, or an empty map if this capability has no - * directives. + * @param res The resource associated with the capability. May be null. */ - public Map<String, String> getDirectives() - { - return directives; + public CapabilityImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs, Resource res) { + super(ns, attrs, dirs, res); } /** - * Returns the resource declaring this capability. - * - * @return The resource declaring this capability. + * Create a capability based on an existing capability, providing the resource. + * The namespace, attributes and directives are copied from the provided capability. + * @param capability The capability to base the new requirement on. + * @param resource The resource to be associated with the capability */ - public Resource getResource() - { - return resource; - } - - /** - * Sets the resource associated with this capability. - * - * @param res The resource. - */ - public void setResource(Resource res) - { - resource = res; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((attributes == null) ? 0 : attributes.hashCode()); - result = prime * result + ((directives == null) ? 0 : directives.hashCode()); - result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); - result = prime * result + ((resource == null) ? 0 : resource.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - CapabilityImpl other = (CapabilityImpl) obj; - if (attributes == null) { - if (other.attributes != null) - return false; - } else if (!attributes.equals(other.attributes)) - return false; - if (directives == null) { - if (other.directives != null) - return false; - } else if (!directives.equals(other.directives)) - return false; - if (namespace == null) { - if (other.namespace != null) - return false; - } else if (!namespace.equals(other.namespace)) - return false; - if (resource == null) { - if (other.resource != null) - return false; - } else if (!resource.equals(other.resource)) - return false; - return true; + public CapabilityImpl(Resource resource, Capability capability) { + this(capability.getNamespace(), capability.getAttributes(), capability.getDirectives(), resource); } } Modified: felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/RequirementImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/RequirementImpl.java?rev=1829625&r1=1829624&r2=1829625&view=diff ============================================================================== --- felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/RequirementImpl.java (original) +++ felix/trunk/utils/src/main/java/org/apache/felix/utils/capabilities/RequirementImpl.java Fri Apr 20 06:34:25 2018 @@ -1,20 +1,18 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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 + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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 + * 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. + * 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.apache.felix.utils.capabilities; @@ -28,154 +26,51 @@ import java.util.Map; /** * Implementation of the OSGi Requirement interface. */ -public class RequirementImpl implements Requirement -{ - private final String namespace; - private final Map<String, Object> attributes; - private final Map<String, String> directives; - private volatile Resource resource; - +public class RequirementImpl extends AbstractCapabilityRequirement implements Requirement { /** - * Create a requirement. - * + * Create a requirement that is not associated with a resource. + * @param res The resource associated with the requirement. * @param ns The namespace of the requirement. * @param attrs The attributes of the requirement. * @param dirs The directives of the requirement. */ - public RequirementImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs) - { + public RequirementImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs) { this(ns, attrs, dirs, null); } /** * Create a requirement. - * * @param ns The namespace of the requirement. * @param attrs The attributes of the requirement. * @param dirs The directives of the requirement. * @param res The resource associated with the requirement. */ - public RequirementImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs, Resource res) - { - namespace = ns; - attributes = attrs; - directives = dirs; - resource = res; - } - - /** - * Create a requirement with a namespace and a filter. - * - * This is a convenience method that creates a requirement with - * an empty attributes map and a single 'filter' directive. - * @param ns The namespace for the requirement. - * @param filter The filter. - */ - public RequirementImpl(String ns, String filter) - { - this(ns, Collections.<String, Object>emptyMap(), - filter == null ? Collections.<String, String> emptyMap() : - Collections.singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter)); + public RequirementImpl(String ns, Map<String, Object> attrs, Map<String, String> dirs, Resource res) { + super(ns, attrs, dirs, res); } /** - * Returns the namespace of this requirement. - * - * @return The namespace of this requirement. + * Create a requirement with a namespace and a filter. + * + * This is a convenience method that creates a requirement with + * an empty attributes map and a single 'filter' directive. + * @param ns The namespace for the requirement. + * @param filter The filter. + */ + public RequirementImpl(String ns, String filter) + { + this(ns, Collections.<String, Object>emptyMap(), + filter == null ? Collections.<String, String> emptyMap() : + Collections.singletonMap(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter)); + } + + /** + * Create a requirement based on an existing requirement, providing the resource. + * The namespace, attributes and directives are copied from the provided requirement. + * @param requirement The requirement to base the new requirement on. + * @param resource The resource to be associated with the requirement */ - public String getNamespace() - { - return namespace; - } - - /** - * Returns the attributes of this requirement. - * - * <p> - * Requirement attributes have no specified semantics and are considered - * extra user defined information. - * - * @return An unmodifiable map of attribute names to attribute values for - * this requirement, or an empty map if this requirement has no - * attributes. - */ - public Map<String, Object> getAttributes() - { - return Collections.unmodifiableMap(attributes); - } - - /** - * Returns the directives of this requirement. - * - * @return An unmodifiable map of directive names to directive values for - * this requirement, or an empty map if this requirement has no - * directives. - */ - public Map<String, String> getDirectives() - { - return Collections.unmodifiableMap(directives); - } - - /** - * Returns the resource declaring this requirement. - * - * @return The resource declaring this requirement. This can be {@code null} - * if this requirement is synthesized. - */ - public Resource getResource() - { - return resource; - } - - /** - * Set the resource associated with this requirement. - * - * @param res The resource. - */ - public void setResource(Resource res) { - resource = res; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((attributes == null) ? 0 : attributes.hashCode()); - result = prime * result + ((directives == null) ? 0 : directives.hashCode()); - result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); - result = prime * result + ((resource == null) ? 0 : resource.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - RequirementImpl other = (RequirementImpl) obj; - if (attributes == null) { - if (other.attributes != null) - return false; - } else if (!attributes.equals(other.attributes)) - return false; - if (directives == null) { - if (other.directives != null) - return false; - } else if (!directives.equals(other.directives)) - return false; - if (namespace == null) { - if (other.namespace != null) - return false; - } else if (!namespace.equals(other.namespace)) - return false; - if (resource == null) { - if (other.resource != null) - return false; - } else if (!resource.equals(other.resource)) - return false; - return true; + public RequirementImpl(Resource resource, Requirement requirement) { + this(requirement.getNamespace(), requirement.getAttributes(), requirement.getDirectives(), resource); } } Modified: felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/CapabilityImplTest.java URL: http://svn.apache.org/viewvc/felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/CapabilityImplTest.java?rev=1829625&r1=1829624&r2=1829625&view=diff ============================================================================== --- felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/CapabilityImplTest.java (original) +++ felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/CapabilityImplTest.java Fri Apr 20 06:34:25 2018 @@ -57,4 +57,18 @@ public class CapabilityImplTest extends assertFalse(c1.equals(c3)); assertFalse(c1.hashCode() == c3.hashCode()); } + + public void testCopyCapability() { + CapabilityImpl c = new CapabilityImpl("x.y.z", + Collections.<String, Object>singletonMap("a", 123), + Collections.<String, String>singletonMap("x", "y"), + Mockito.mock(Resource.class)); + + Resource res2 = Mockito.mock(Resource.class); + CapabilityImpl c2 = new CapabilityImpl(res2, c); + assertFalse("Should not be equal, the resources are different", c.equals(c2)); + + c.setResource(res2); + assertEquals(c, c2); + } } Modified: felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/RequirementImplTest.java URL: http://svn.apache.org/viewvc/felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/RequirementImplTest.java?rev=1829625&r1=1829624&r2=1829625&view=diff ============================================================================== --- felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/RequirementImplTest.java (original) +++ felix/trunk/utils/src/test/java/org/apache/felix/utils/capabilities/RequirementImplTest.java Fri Apr 20 06:34:25 2018 @@ -69,4 +69,18 @@ public class RequirementImplTest extends assertEquals(0, r2.getAttributes().size()); assertEquals(0, r2.getDirectives().size()); } + + public void testCopyRequirement() { + RequirementImpl r = new RequirementImpl("x.y.z", + Collections.<String, Object>singletonMap("a", 123), + Collections.<String, String>singletonMap("x", "y"), + Mockito.mock(Resource.class)); + + Resource res2 = Mockito.mock(Resource.class); + RequirementImpl r2 = new RequirementImpl(res2, r); + assertFalse("Should not be equal, the resources are different", r.equals(r2)); + + r.setResource(res2); + assertEquals(r, r2); + } }