/***************************************************************************** * Copyright (c) 2006-2013, Cloudsmith Inc. * The code, documentation and other materials contained herein have been * licensed under the Eclipse Public License - v 1.0 by the copyright holder * listed above, as the Initial Contributor under such license. The text of * such license is available at www.eclipse.org. *****************************************************************************/ package org.eclipse.buckminster.core.metadata.model; import java.net.URI; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.eclipse.buckminster.core.CorePlugin; import org.eclipse.buckminster.core.KeyConstants; import org.eclipse.buckminster.core.Messages; import org.eclipse.buckminster.core.RMContext; import org.eclipse.buckminster.core.XMLConstants; import org.eclipse.buckminster.core.cspec.QualifiedDependency; import org.eclipse.buckminster.core.cspec.model.CSpec; import org.eclipse.buckminster.core.cspec.model.ComponentIdentifier; import org.eclipse.buckminster.core.cspec.model.ComponentRequest; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.helpers.TextUtils; import org.eclipse.buckminster.core.metadata.IResolution; import org.eclipse.buckminster.core.metadata.MissingComponentException; import org.eclipse.buckminster.core.metadata.StorageManager; import org.eclipse.buckminster.core.metadata.WorkspaceInfo; import org.eclipse.buckminster.core.metadata.builder.ResolutionBuilder; import org.eclipse.buckminster.core.resolver.NodeQuery; import org.eclipse.buckminster.core.rmap.model.Provider; import org.eclipse.buckminster.core.version.ProviderMatch; import org.eclipse.buckminster.core.version.VersionMatch; import org.eclipse.buckminster.core.version.VersionSelector; import org.eclipse.buckminster.osgi.filter.Filter; import org.eclipse.buckminster.sax.UUIDKeyed; import org.eclipse.buckminster.sax.Utils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.equinox.p2.metadata.Version; import org.eclipse.equinox.p2.metadata.VersionRange; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * @author Thomas Hallgren */ public class Resolution extends UUIDKeyed implements IUUIDPersisted, IResolution { public static final String ATTR_ATTRIBUTES = "attributes"; //$NON-NLS-1$ public static final String ATTR_COMPONENT_TYPE = "componentType"; //$NON-NLS-1$ public static final String ATTR_CONTENT_TYPE = "contentType"; //$NON-NLS-1$ public static final String ATTR_CSPEC_ID = "cspecId"; //$NON-NLS-1$ public static final String ATTR_LAST_MODIFIED = "lastModified"; //$NON-NLS-1$ public static final String ATTR_MATERIALIZABLE = "materializable"; //$NON-NLS-1$ public static final String ATTR_PERSISTENT_ID = "persistentId"; //$NON-NLS-1$ public static final String ATTR_PROVIDER_ID = "providerId"; //$NON-NLS-1$ public static final String ATTR_QUERY_ID = "queryId"; //$NON-NLS-1$ public static final String ATTR_REMOTE_NAME = "remoteName"; //$NON-NLS-1$ public static final String ATTR_REPOSITORY = "repository"; //$NON-NLS-1$ public static final String ATTR_SIZE = "size"; //$NON-NLS-1$ public static final String ATTR_UNPACK = "unpack"; //$NON-NLS-1$ public static final String ELEM_REQUEST = "request"; //$NON-NLS-1$ public static final int SEQUENCE_NUMBER = 2; public static final String TAG = "resolution"; //$NON-NLS-1$ private final List<String> attributes; private final String componentTypeId; private final String contentType; private transient CSpec cspec; private final long lastModified; private final boolean materializable; private final String persistentId; private transient Provider provider; private final String remoteName; private final String repository; private final ComponentRequest request; private final long size; private final boolean unpack; private final VersionMatch versionMatch; private Map<String, ? extends Object> properties; public Resolution(CSpec cspec, Resolution old) { this.cspec = cspec; this.request = old.getRequest(); this.attributes = old.getAttributes(); this.persistentId = old.getPersistentId(); this.provider = old.getProvider(); this.componentTypeId = old.getComponentTypeId(); this.versionMatch = old.getVersionMatch().copyWithVersion(cspec.getVersion()); this.materializable = old.isMaterializable(); this.repository = old.getRepository(); this.remoteName = old.getRemoteName(); this.contentType = old.getContentType(); this.lastModified = old.getLastModified(); this.size = old.getSize(); this.unpack = old.isUnpack(); } public Resolution(CSpec cspec, String componentTypeId, VersionMatch versionMatch, Provider provider, boolean materializeable, ComponentRequest request, List<String> attributes, String persistentId, String repository, String remoteName, String contentType, long lastModified, long size, boolean unpack) { this.cspec = cspec; this.provider = provider; this.componentTypeId = componentTypeId; this.versionMatch = versionMatch; this.materializable = materializeable; this.request = request; this.attributes = Utils.createUnmodifiableList(attributes); this.persistentId = persistentId; this.repository = repository; this.remoteName = remoteName; this.contentType = contentType; this.lastModified = lastModified; this.size = size; this.unpack = unpack; } public Resolution(ResolutionBuilder bld) { this.attributes = Utils.createUnmodifiableList(bld.getAttributes()); this.componentTypeId = bld.getComponentTypeId(); this.contentType = bld.getContentType(); this.cspec = bld.getCSpec(); this.lastModified = bld.getLastModified(); this.materializable = bld.isMaterializable(); this.persistentId = bld.getPersistentId(); this.provider = bld.getProvider(); this.remoteName = bld.getRemoteName(); this.repository = bld.getRepository(); this.request = bld.getRequest().createComponentRequest(); this.size = bld.getSize(); this.versionMatch = bld.getVersionMatch(); this.unpack = bld.isUnpack(); } public Resolution(Version version, Resolution old) { this.cspec = old.getCSpec(); this.request = old.getRequest(); this.attributes = old.getAttributes(); this.persistentId = old.getPersistentId(); this.provider = old.getProvider(); this.componentTypeId = old.getComponentTypeId(); this.versionMatch = old.getVersionMatch().copyWithVersion(version); this.materializable = old.isMaterializable(); this.repository = old.getRepository(); this.remoteName = old.getRemoteName(); this.contentType = old.getContentType(); this.lastModified = old.getLastModified(); this.size = old.getSize(); this.unpack = old.isUnpack(); } @Override public void emitElements(ContentHandler handler, String namespace, String prefix) throws SAXException { request.toSax(handler, XMLConstants.BM_METADATA_NS, XMLConstants.BM_METADATA_PREFIX, ELEM_REQUEST); versionMatch.toSax(handler, XMLConstants.BM_METADATA_NS, XMLConstants.BM_METADATA_PREFIX, versionMatch.getDefaultTag()); } @Override public String getArtifactInfo() { return versionMatch.getArtifactInfo(); } public URI getArtifactURI(RMContext context) throws CoreException { return getProvider().getReaderType().getArtifactURL(this, context); } @Override public List<String> getAttributes() { return attributes; } /** * Returns the identifier of the contained <code>CSpec</code>. * * @return The component identifier * @throws CoreException */ public ComponentIdentifier getComponentIdentifier() { return getCSpec().getComponentIdentifier(); } public IComponentType getComponentType() throws CoreException { return CorePlugin.getDefault().getComponentType(componentTypeId); } @Override public String getComponentTypeId() { return componentTypeId; } @Override public String getContentType() { return contentType; } /** * Returns the CSpec at the time when this resolution was created. The * actual cspec in the workspace might have changed since then. * * @return The resolved cspec. */ @Override public CSpec getCSpec() { return cspec; } /** * Returns the id of the contained CSpec. * * @return The id of the contained CSpec. */ public UUID getCSpecId() { return cspec.getId(); } @Override public String getDefaultTag() { return TAG; } @Override public long getLastModified() { return lastModified; } @Override public VersionSelector getMatchedBranchOrTag() { return versionMatch.getBranchOrTag(); } /** * Returns the name of the component. * * @return the name. */ public final String getName() { return request.getName(); } @Override public String getPersistentId() { return persistentId; } public synchronized Map<String, ? extends Object> getProperties() { if (properties == null) { HashMap<String, Object> props = new HashMap<String, Object>(); props.put(KeyConstants.READER_TYPE, provider.getReaderTypeId()); props.put(KeyConstants.IS_MUTABLE, Boolean.toString(provider.isMutable())); props.put(KeyConstants.IS_SOURCE, Boolean.toString(provider.hasSource())); props.putAll(cspec.getComponentIdentifier().getProperties()); properties = props; } return properties; } /** * Returns the provider used when reading the repository. * * @return the repository provider. */ @Override public Provider getProvider() { return provider; } /** * Returns the id of the contained provider * * @return the id of the contained provider */ public UUID getProviderId() { return provider.getId(); } public ProviderMatch getProviderMatch(RMContext context) throws CoreException { ProviderMatch pm = new ProviderMatch(provider, getComponentType(), getVersionMatch(), context.getNodeQuery(getQualifiedDependency())); pm.setRepositoryURI(repository); return pm; } public final QualifiedDependency getQualifiedDependency() { return new QualifiedDependency(request, attributes); } @Override public String getReaderTypeId() { return getProvider().getReaderTypeId(); } @Override public String getRemoteName() { return remoteName; } @Override public String getRepository() { return repository; } /** * @return Returns the properties. */ @Override public final ComponentRequest getRequest() { return request; } @Override public Filter getResolutionFilter() { return getProvider().getResolutionFilter(); } @Override public String getSelectedRevision() { return versionMatch.getRevision(); } @Override public Date getSelectedTimestamp() { return getVersionMatch().getTimestamp(); } @Override public long getSize() { return size; } /** * Returns the final version that was used when the specification was * obtained. * * @return the version used when retrieving the spec. */ public final Version getVersion() { return versionMatch.getVersion(); } /** * Returns the original version designator. * * @return The original (unresolved) version designator */ public final VersionRange getVersionDesignator() throws CoreException { return request.getVersionRange(); } @Override public VersionMatch getVersionMatch() { return versionMatch; } /** * Check if the request designates the versioned component that this * component info represents. * * @param rq * the request that might appoint the component * @return <code>true</code> if the versioned component is designated * @throws CoreException */ public boolean isDesignatedBy(ComponentRequest rq) throws CoreException { if (!rq.getName().equals(request.getName())) return false; // If the request has a component type then it must match // String componentType = rq.getComponentTypeID(); if (componentType != null && !componentType.equals(request.getComponentTypeID())) return false; VersionRange vd = rq.getVersionRange(); return vd == null ? true : vd.isIncluded(getVersion()); } /** * Returns true if this resolution is a match for the given * <code>query</code> with respect to provided properties. The method will * update the filter attributes map of the query context. * * @param The * query to match * @return True if this resolution is a match for the given query. * @see RMContext#getFilterAttributeUsageMap() */ public boolean isFilterMatchFor(NodeQuery query) { return isFilterMatchFor(query, null); } /** * Returns true if this resolution is a match for the given * <code>query</code> with respect to provided properties. The method will * update the filter attributes map of the query context. * * @param The * query to match * @param A * one element array that will receive the failing filter. Can be * <code>null</code>. * @return True if this resolution is a match for the given query. * @see RMContext#getFilterAttributeUsageMap() */ public boolean isFilterMatchFor(NodeQuery query, Filter[] failingFilter) { Filter cspecFilter = getCSpec().getFilter(); if (cspecFilter == null) return true; Map<String, String[]> attributeUsageMap = query.getContext().getFilterAttributeUsageMap(); Map<String, ? extends Object> queryProps = query.getProperties(); cspecFilter.addConsultedAttributes(attributeUsageMap); if (cspecFilter.matchCase(queryProps)) return true; if (failingFilter != null) failingFilter[0] = cspecFilter; return false; } /** * Returns <code>true</code> if the reader associated with the component * will be able to materialized the component. Readers that check for the * existence of pre-installed components (such as Eclipse plugins that are * already present in the running eclipse installation) will return * <code>false</code>. * * @return <code>true</code> if the component can be materialized on disk. */ @Override public boolean isMaterializable() { return materializable; } /** * Returns <code>true</code> if the component is materialized at the given * location according to the workspace meta-data. * * @return <code>true</code> if the component is materialized. */ public boolean isMaterialized(IPath location) throws CoreException { try { IPath myLocation = getCSpec().getComponentLocation(); return location.equals(myLocation); } catch (MissingComponentException e) { return false; } } @Override public boolean isPersisted(StorageManager sm) throws CoreException { return sm.getResolutions().contains(this); } @Override public boolean isUnpack() { return unpack; } @Override public void remove(StorageManager sm) throws CoreException { WorkspaceInfo.updateResolutionCache(getComponentIdentifier(), null); synchronized (sm.getResolutions()) { sm.getResolutions().removeElement(getId()); } } @Override public void store(StorageManager sm) throws CoreException { WorkspaceInfo.updateResolutionCache(getComponentIdentifier(), this); cspec.store(sm); provider.store(sm); synchronized (sm.getResolutions()) { sm.getResolutions().putElement(this); } } @Override public void toSax(ContentHandler receiver) throws SAXException { receiver.startDocument(); toSax(receiver, XMLConstants.BM_METADATA_NS, XMLConstants.BM_METADATA_PREFIX, getDefaultTag()); receiver.endDocument(); } @Override public void toSax(ContentHandler handler, String namespace, String prefix, String localName) throws SAXException { handler.startPrefixMapping(XMLConstants.BM_METADATA_PREFIX, XMLConstants.BM_METADATA_NS); super.toSax(handler, namespace, prefix, localName); handler.endPrefixMapping(XMLConstants.BM_METADATA_PREFIX); } @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(Messages.Name); result.append(request.getName()); result.append(", "); //$NON-NLS-1$ versionMatch.toString(result); return result.toString(); } @Override protected void addAttributes(AttributesImpl attrs) throws SAXException { Utils.addAttribute(attrs, ATTR_CSPEC_ID, cspec.getId().toString()); String tmp = TextUtils.concat(attributes, ","); //$NON-NLS-1$ if (tmp != null) Utils.addAttribute(attrs, ATTR_ATTRIBUTES, tmp); Utils.addAttribute(attrs, ATTR_MATERIALIZABLE, materializable ? "true" //$NON-NLS-1$ : "false"); //$NON-NLS-1$ Utils.addAttribute(attrs, ATTR_PROVIDER_ID, provider.getId().toString()); Utils.addAttribute(attrs, ATTR_REPOSITORY, repository); if (componentTypeId != null) Utils.addAttribute(attrs, ATTR_COMPONENT_TYPE, componentTypeId); if (persistentId != null) Utils.addAttribute(attrs, ATTR_PERSISTENT_ID, persistentId); if (remoteName != null) Utils.addAttribute(attrs, ATTR_REMOTE_NAME, remoteName); if (contentType != null) Utils.addAttribute(attrs, ATTR_CONTENT_TYPE, contentType); if (lastModified != -1L) Utils.addAttribute(attrs, ATTR_LAST_MODIFIED, Long.toString(lastModified)); if (size != -1L) Utils.addAttribute(attrs, ATTR_SIZE, Long.toString(size)); if (unpack) Utils.addAttribute(attrs, ATTR_UNPACK, "true"); //$NON-NLS-1$ } @Override protected String getElementNamespace(String namespace) { return XMLConstants.BM_METADATA_NS; } @Override protected String getElementPrefix(String prefix) { return XMLConstants.BM_METADATA_PREFIX; } }