From 216b32c524ac0c41753a0623e0429cbfab75bcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Thu, 22 Feb 2024 09:03:36 +0100 Subject: [PATCH] Fix ModuleCapability/ModuleRequirement hashcode/equals according to API The API of Capability/Requirement currently defines the contract to be: This Capability/Requirement is equal to another Capability/Requirement if they have the same namespace, directives and attributes and are declared by the same resource. But Felix currently implements hashCode/equals in terms of object identity. --- .../wiring/BundleCapabilityImpl.java | 41 +++++++++++++++--- .../wiring/BundleRequirementImpl.java | 43 ++++++++++++++++--- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java index ddc6a4169c..c803df9877 100644 --- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleCapabilityImpl.java @@ -24,16 +24,17 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.StringTokenizer; import java.util.function.Function; -import org.apache.felix.framework.capabilityset.SimpleFilter; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.ManifestParser; import org.osgi.framework.Constants; import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRevision; +import org.osgi.resource.Capability; public class BundleCapabilityImpl implements BundleCapability { @@ -45,6 +46,7 @@ public class BundleCapabilityImpl implements BundleCapability private final Map m_attrs; private final List m_uses; private final Set m_mandatory; + private transient int hashCode; public static BundleCapabilityImpl createFrom(BundleCapabilityImpl capability, Function cache) { @@ -114,27 +116,32 @@ public BundleCapabilityImpl(BundleRevision revision, String namespace, m_mandatory = mandatory; } - public BundleRevision getResource() + @Override + public BundleRevision getResource() { return m_revision; } - public BundleRevision getRevision() + @Override + public BundleRevision getRevision() { return m_revision; } - public String getNamespace() + @Override + public String getNamespace() { return m_namespace; } - public Map getDirectives() + @Override + public Map getDirectives() { return m_dirs; } - public Map getAttributes() + @Override + public Map getAttributes() { return m_attrs; } @@ -158,4 +165,26 @@ public String toString() } return "[" + m_revision + "] " + m_namespace + "; " + m_attrs; } + + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + return hashCode = Objects.hash(m_namespace, m_dirs, m_attrs, m_revision); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Capability) { + Capability other = (Capability) obj; + return Objects.equals(m_namespace, other.getNamespace()) && Objects.equals(m_dirs, other.getDirectives()) + && Objects.equals(m_attrs, other.getAttributes()) + && Objects.equals(m_revision, other.getResource()); + } + return false; + } } \ No newline at end of file diff --git a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java index a8a111913a..b81b4e22e6 100644 --- a/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/wiring/BundleRequirementImpl.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import org.apache.felix.framework.capabilityset.CapabilitySet; @@ -30,6 +31,7 @@ import org.osgi.framework.wiring.BundleCapability; import org.osgi.framework.wiring.BundleRequirement; import org.osgi.framework.wiring.BundleRevision; +import org.osgi.resource.Requirement; public class BundleRequirementImpl implements BundleRequirement { @@ -39,6 +41,7 @@ public class BundleRequirementImpl implements BundleRequirement private final boolean m_optional; private final Map m_dirs; private final Map m_attrs; + private transient int hashCode; public static BundleRequirementImpl createFrom(BundleRequirementImpl requirement, Function cache) { @@ -87,32 +90,38 @@ public BundleRequirementImpl( this(revision, namespace, dirs, Collections.emptyMap(), SimpleFilter.convert(attrs)); } - public String getNamespace() + @Override + public String getNamespace() { return m_namespace; } - public Map getDirectives() + @Override + public Map getDirectives() { return m_dirs; } - public Map getAttributes() + @Override + public Map getAttributes() { return m_attrs; } - public BundleRevision getResource() + @Override + public BundleRevision getResource() { return m_revision; } - public BundleRevision getRevision() + @Override + public BundleRevision getRevision() { return m_revision; } - public boolean matches(BundleCapability cap) + @Override + public boolean matches(BundleCapability cap) { return CapabilitySet.matches(cap, getFilter()); } @@ -132,4 +141,26 @@ public String toString() { return "[" + m_revision + "] " + m_namespace + "; " + getFilter().toString(); } + + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + return hashCode = Objects.hash(m_namespace, m_dirs, m_attrs, m_revision); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Requirement) { + Requirement other = (Requirement) obj; + return Objects.equals(m_namespace, other.getNamespace()) && Objects.equals(m_dirs, other.getDirectives()) + && Objects.equals(m_attrs, other.getAttributes()) + && Objects.equals(m_revision, other.getResource()); + } + return false; + } } \ No newline at end of file