/* * 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.apache.aries.subsystem.core.internal; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import org.osgi.service.subsystem.Subsystem; import org.osgi.service.subsystem.SubsystemException; public class SubsystemGraph { private static class SubsystemWrapper { private final Subsystem s; public SubsystemWrapper(Subsystem subsystem) { s = subsystem; } @Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof SubsystemWrapper)) return false; SubsystemWrapper that = (SubsystemWrapper)o; return s.getLocation().equals(that.s.getLocation()); } public Subsystem getSubsystem() { return s; } @Override public int hashCode() { int result = 17; result = 31 * result + s.getLocation().hashCode(); return result; } @Override public String toString() { return new StringBuilder("location=").append(s.getLocation()) .append(", symbolicName=").append(s.getSymbolicName()) .append(", version=").append(s.getVersion()) .append(", type=").append(s.getType()).toString(); } } private final Map<SubsystemWrapper, Collection<SubsystemWrapper>> adjacencyList = new HashMap<SubsystemWrapper, Collection<SubsystemWrapper>>(); public SubsystemGraph(BasicSubsystem root) { adjacencyList.put(new SubsystemWrapper(root), new HashSet<SubsystemWrapper>()); } public synchronized void add(BasicSubsystem parent, BasicSubsystem child) { SubsystemWrapper parentWrap = new SubsystemWrapper(parent); SubsystemWrapper childWrap = new SubsystemWrapper(child); if (containsAncestor(childWrap, parentWrap)) throw new SubsystemException("Cycle detected between '" + parentWrap + "' and '" + childWrap + "'"); Collection<SubsystemWrapper> subsystems = adjacencyList.get(childWrap); if (subsystems == null) { subsystems = new HashSet<SubsystemWrapper>(); adjacencyList.put(childWrap, subsystems); } subsystems = adjacencyList.get(parentWrap); if (subsystems == null) { subsystems = new HashSet<SubsystemWrapper>(); adjacencyList.put(parentWrap, subsystems); } subsystems.add(childWrap); } public synchronized Collection<Subsystem> getChildren(BasicSubsystem parent) { Collection<SubsystemWrapper> children = adjacencyList.get(new SubsystemWrapper(parent)); if (children == null || children.isEmpty()) return Collections.emptySet(); Collection<Subsystem> result = new ArrayList<Subsystem>(children.size()); for (SubsystemWrapper child : children) result.add(child.getSubsystem()); return Collections.unmodifiableCollection(result); } public synchronized Collection<Subsystem> getParents(BasicSubsystem child) { Collection<SubsystemWrapper> parents = getParents(new SubsystemWrapper(child)); Collection<Subsystem> result = new ArrayList<Subsystem>(parents.size()); for (SubsystemWrapper parent : parents) { result.add(parent.getSubsystem()); } return Collections.unmodifiableCollection(result); } public synchronized void remove(BasicSubsystem child) { SubsystemWrapper subsystemWrap = new SubsystemWrapper(child); Collection<SubsystemWrapper> parents = getParents(subsystemWrap); for (SubsystemWrapper parent : parents) adjacencyList.get(parent).remove(subsystemWrap); adjacencyList.remove(subsystemWrap); } public synchronized void remove(BasicSubsystem parent, BasicSubsystem child) { SubsystemWrapper parentWrap = new SubsystemWrapper(parent); SubsystemWrapper childWrap = new SubsystemWrapper(child); adjacencyList.get(parentWrap).remove(childWrap); } private boolean containsAncestor(SubsystemWrapper subsystem, SubsystemWrapper ancestor) { Collection<SubsystemWrapper> subsystems = adjacencyList.get(subsystem); if (subsystems == null) return false; if (subsystems.contains(ancestor)) return true; for (SubsystemWrapper s : subsystems) { return containsAncestor(s, ancestor); } return false; } private Collection<SubsystemWrapper> getParents(SubsystemWrapper child) { ArrayList<SubsystemWrapper> result = new ArrayList<SubsystemWrapper>(); for (Entry<SubsystemWrapper, Collection<SubsystemWrapper>> entry : adjacencyList.entrySet()) if (entry.getValue().contains(child)) result.add(entry.getKey()); result.trimToSize(); return result; } }