/******************************************************************************* * Copyright (c) 2008, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMware Inc. - initial contribution *******************************************************************************/ package org.eclipse.virgo.kernel.model.internal; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.equinox.region.Region; import org.eclipse.virgo.kernel.model.Artifact; import org.eclipse.virgo.nano.serviceability.NonNull; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.Version; import org.osgi.util.tracker.ServiceTracker; /** * An abstract implementation of {@link Artifact} that all implementations should extend. * <p/> * Implements {@link #getDependents()} by delegating to {@link DependencyDeterminer} found in the service registry. The * appropriate {@link DependencyDeterminer} is located by finding a a service with the property * <code>artifactType</code> with the a value equal to the value of {@link #getType()}. * <p /> * {@link #equals(Object)} and {@link #hashCode()} are also implemented to guarantee that equality is based on the type, * name, and version of the artifact. * <p/> * * <strong>Concurrent Semantics</strong><br /> * * Threadsafe and all subclasses should be threadsafe * * @see DependencyDeterminer */ public abstract class AbstractArtifact implements Artifact { private static final String FILTER_FORMAT = "(&(objectClass=%s)(artifactType=%s))"; private final String type; private final String name; private final Version version; private final ServiceTracker<DependencyDeterminer, DependencyDeterminer> dependencyDeterminerTracker; private final Region region; public AbstractArtifact(@NonNull BundleContext bundleContext, @NonNull String type, @NonNull String name, @NonNull Version version, @NonNull Region region) { this.type = type; this.name = name; this.version = version; this.region = region; Filter filter; try { filter = bundleContext.createFilter(String.format(FILTER_FORMAT, DependencyDeterminer.class.getCanonicalName(), type)); } catch (InvalidSyntaxException e) { throw new RuntimeException(String.format("Cannot create Service Registry filter for a DependencyDeterminer of type '%s'", type), e); } this.dependencyDeterminerTracker = new ServiceTracker<DependencyDeterminer, DependencyDeterminer>(bundleContext, filter, null); this.dependencyDeterminerTracker.open(); } /** * {@inheritDoc} */ public final String getType() { return this.type; } /** * {@inheritDoc} */ public final String getName() { return this.name; } /** * {@inheritDoc} */ public final Version getVersion() { return this.version; } /** * {@inheritDoc} */ @Override public final Region getRegion() { return this.region; } /** * {@inheritDoc} */ public final Set<Artifact> getDependents() { Set<Artifact> dependents = new HashSet<Artifact>(); Object[] dependencyDeterminers = this.dependencyDeterminerTracker.getServices(); if (dependencyDeterminers != null) { for (Object dependencyDeterminer : dependencyDeterminers) { dependents.addAll(((DependencyDeterminer) dependencyDeterminer).getDependents(this)); } } return Collections.unmodifiableSet(dependents); } /** * {@inheritDoc} */ public Map<String, String> getProperties() { return Collections.<String, String> emptyMap(); } /** * {@inheritDoc} */ @Override public final int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((region == null) ? 0 : region.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); result = prime * result + ((version == null) ? 0 : version.hashCode()); return result; } /** * {@inheritDoc} */ @Override public final boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof AbstractArtifact)) return false; AbstractArtifact other = (AbstractArtifact) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (region == null) { if (other.region != null) return false; } else if (!region.equals(other.region)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; if (version == null) { if (other.version != null) return false; } else if (!version.equals(other.version)) return false; return true; } @Override public String toString() { return String.format("type: %s, name: %s, version: %s, region: " + (this.region == null ? "?" : this.region.getName()), this.type, this.name, this.version.toString()); } }