/** * Copyright (C) 2012 Red Hat, Inc. (jdcasey@commonjava.org) * * 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.commonjava.cartographer.graph; import org.apache.commons.codec.digest.DigestUtils; import org.commonjava.cartographer.graph.filter.AnyFilter; import org.commonjava.cartographer.graph.filter.ProjectRelationshipFilter; import org.commonjava.cartographer.graph.mutate.GraphMutator; import org.commonjava.cartographer.graph.mutate.ManagedDependencyMutator; import org.commonjava.cartographer.graph.util.RelationshipUtils; import org.commonjava.maven.atlas.ident.ref.ProjectRef; import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef; import java.io.Serializable; import java.net.URI; import java.util.*; import java.util.Map.Entry; import static org.apache.commons.lang.StringUtils.join; import static org.commonjava.maven.atlas.graph.rel.RelationshipConstants.POM_ROOT_URI; import static org.commonjava.maven.atlas.graph.rel.RelationshipConstants.UNKNOWN_SOURCE_URI; /** * <p> * View of a graph database that may include a set of traversal root-nodes, * a {@link ProjectRelationshipFilter}, and a {@link GraphMutator}. This view * also supports selection of a GAV to override either all references to a GA, or * references to a specific GAV. * </p> * * <p> * <b>NOTE(1):</b> Selections currently cannot be overridden or * cleared once set, and root GAVs cannot be overridden with a selection. * </p> * * <p> * <b>NOTE(2):</b> If root nodes are unspecified, then neither filter nor mutator can be used! * </p> * * @author jdcasey */ public class ViewParams implements Serializable { private static final long serialVersionUID = 1L; private static final Set<URI> DEFAULT_SOURCES = Collections.unmodifiableSet( Collections.singleton( UNKNOWN_SOURCE_URI ) ); private static final Set<URI> DEFAULT_POM_LOCATIONS = Collections.unmodifiableSet( Collections.singleton( POM_ROOT_URI ) ); private final Set<ProjectVersionRef> roots = new HashSet<ProjectVersionRef>(); private final ProjectRelationshipFilter filter; private final GraphMutator mutator; private Set<URI> activePomLocations; private Set<URI> activeSources; private long lastAccess = System.currentTimeMillis(); private Map<String, String> properties; private final Map<ProjectRef, ProjectVersionRef> selections; private transient String longId; private transient String shortId; private final String workspaceId; public ViewParams( final String workspaceId, final ProjectRelationshipFilter filter, final GraphMutator mutator, final Collection<ProjectVersionRef> roots ) { this( workspaceId, filter, mutator, null, roots ); } public ViewParams( final String workspaceId, final ProjectRelationshipFilter filter, final GraphMutator mutator, final ProjectVersionRef... roots ) { this( workspaceId, filter, mutator, null, roots ); } public ViewParams( final String workspaceId, final Collection<ProjectVersionRef> roots ) { this( workspaceId, null, null, null, roots ); } public ViewParams( final String workspaceId, final ProjectVersionRef... roots ) { this( workspaceId, null, null, null, roots ); } public ViewParams( final String workspaceId, final ProjectRelationshipFilter filter, final GraphMutator mutator, final Map<ProjectRef, ProjectVersionRef> selections, final Collection<ProjectVersionRef> roots ) { this.workspaceId = workspaceId; this.filter = filter; this.selections = selections; this.roots.addAll( roots ); this.mutator = mutator; } public ViewParams( final String workspaceId, final ProjectRelationshipFilter filter, final GraphMutator mutator, final Map<ProjectRef, ProjectVersionRef> selections, final ProjectVersionRef... roots ) { this.workspaceId = workspaceId; this.filter = filter; this.selections = selections; this.roots.addAll( Arrays.asList( roots ) ); this.mutator = mutator; } public ViewParams( final String workspaceId, final Map<ProjectRef, ProjectVersionRef> selections, final Collection<ProjectVersionRef> roots ) { this( workspaceId, null, null, selections, roots ); } public ViewParams( final String workspaceId, final Map<ProjectRef, ProjectVersionRef> selections, final ProjectVersionRef... roots ) { this( workspaceId, null, null, selections, roots ); } public ViewParams( final String workspaceId, final ProjectRelationshipFilter filter, final GraphMutator mutator, final Set<URI> activePomLocations, final Set<URI> activeSources, final Map<ProjectRef, ProjectVersionRef> selections, final Map<String, String> properties, final Collection<ProjectVersionRef> roots ) { this.workspaceId = workspaceId; this.filter = filter; this.mutator = mutator; this.activePomLocations = activePomLocations; this.activeSources = activeSources; this.selections = selections; this.properties = properties; this.roots.addAll( roots ); } public GraphMutator getMutator() { return mutator == null ? ManagedDependencyMutator.INSTANCE : mutator; } public ProjectRelationshipFilter getFilter() { return filter == null ? AnyFilter.INSTANCE : filter; } public Set<ProjectVersionRef> getRoots() { return roots; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ( ( filter == null ) ? 0 : filter.hashCode() ); result = prime * result + ( ( roots == null ) ? 0 : roots.hashCode() ); return result; } @Override public boolean equals( final Object obj ) { if ( this == obj ) { return true; } if ( obj == null ) { return false; } if ( getClass() != obj.getClass() ) { return false; } final ViewParams other = (ViewParams) obj; return getShortId().equals( other.getShortId() ); } @Override public String toString() { return getLongId() + " (shortId: " + getShortId() + ")"; } public String getLongId() { if ( longId == null ) { final StringBuilder sb = new StringBuilder(); final String abbreviatedPackage = getClass().getPackage() .getName() .replaceAll( "([a-zA-Z])[a-zA-Z]+", "$1" ); sb.append( abbreviatedPackage ) .append( '.' ) .append( getClass().getSimpleName() ) .append( "(roots:" ) .append( join( roots, "," ) ) .append( ",filter:" ) .append( filter == null ? "none" : filter.getLongId() ) .append( ",mutator:" ) .append( mutator == null ? "none" : mutator.getLongId() ) .append( ",selections:\n " ) .append( renderSelections() ); sb.append( ")" ); longId = sb.toString(); } return longId; } public String getShortId() { if ( shortId == null ) { shortId = DigestUtils.shaHex( getLongId() ); } return shortId; } public void touch() { lastAccess = System.currentTimeMillis(); } public ViewParams addActivePomLocation( final URI location ) { if ( activePomLocations == null ) { activePomLocations = new HashSet<URI>(); } activePomLocations.add( location ); return this; } public ViewParams addActivePomLocations( final Collection<URI> locations ) { if ( activePomLocations == null ) { activePomLocations = new HashSet<URI>(); } activePomLocations.addAll( locations ); return this; } public ViewParams addActivePomLocations( final URI... locations ) { if ( activePomLocations == null ) { activePomLocations = new HashSet<URI>(); } activePomLocations.addAll( Arrays.asList( locations ) ); return this; } public ViewParams addActiveSources( final Collection<URI> sources ) { if ( activeSources == null ) { activeSources = new HashSet<URI>(); } activeSources.addAll( sources ); return this; } public ViewParams addActiveSources( final URI... sources ) { if ( activeSources == null ) { activeSources = new HashSet<URI>(); } activeSources.addAll( Arrays.asList( sources ) ); return this; } public ViewParams addActiveSource( final URI source ) { if ( activeSources == null ) { activeSources = new HashSet<URI>(); } activeSources.add( source ); return this; } public long getLastAccess() { return lastAccess; } public String setProperty( final String key, final String value ) { if ( properties == null ) { properties = new HashMap<String, String>(); } return properties.put( key, value ); } public String removeProperty( final String key ) { return properties == null ? null : properties.remove( key ); } public String getProperty( final String key ) { return properties == null ? null : properties.get( key ); } public String getProperty( final String key, final String def ) { final String val = properties == null ? null : properties.get( key ); return val == null ? def : val; } public final String getWorkspaceId() { return workspaceId; } public final Set<URI> getActivePomLocations() { return activePomLocations == null ? DEFAULT_POM_LOCATIONS : activePomLocations; } public final Set<URI> getActiveSources() { return activeSources == null ? DEFAULT_SOURCES : activeSources; } public final Iterable<URI> activePomLocations() { return activePomLocations; } public final Iterable<URI> activeSources() { return activeSources; } public final Map<ProjectRef, ProjectVersionRef> getSelections() { return selections == null ? Collections.<ProjectRef, ProjectVersionRef> emptyMap() : selections; } public final ProjectVersionRef getSelection( final ProjectRef ref ) { if ( selections == null ) { return null; } ProjectVersionRef selected = selections.get( ref ); if ( selected == null ) { selected = selections.get( ref.asProjectRef() ); } return selected; } public boolean hasSelection( final ProjectVersionRef ref ) { return selections != null && ( selections.containsKey( ref ) || selections.containsKey( ref.asProjectRef() ) ); } public String renderSelections() { if ( selections == null ) { return ""; } final StringBuilder sb = new StringBuilder(); for ( final Entry<ProjectRef, ProjectVersionRef> entry : selections.entrySet() ) { final ProjectRef key = entry.getKey(); final ProjectVersionRef value = entry.getValue(); sb.append( "\n " ) .append( key ) .append( " => " ) .append( value ); } return sb.toString(); } public boolean hasSelections() { return selections != null && !selections.isEmpty(); } public static final class Builder { private final Set<ProjectVersionRef> roots; private ProjectRelationshipFilter filter; private GraphMutator mutator; private final Set<URI> activePomLocations; private final Set<URI> activeSources; private final Map<String, String> properties; private final Map<ProjectRef, ProjectVersionRef> selections; private final String workspaceId; public Builder( final String workspaceId, final ProjectVersionRef... roots ) { this.workspaceId = workspaceId; this.roots = new HashSet<ProjectVersionRef>( Arrays.asList( roots ) ); this.activePomLocations = new HashSet<URI>(); this.activeSources = new HashSet<URI>(); this.properties = new HashMap<String, String>(); this.selections = new HashMap<ProjectRef, ProjectVersionRef>(); this.filter = AnyFilter.INSTANCE; this.mutator = ManagedDependencyMutator.INSTANCE; } public Builder( final String workspaceId, final Collection<ProjectVersionRef> roots ) { this.workspaceId = workspaceId; this.roots = new HashSet<ProjectVersionRef>( roots ); this.activePomLocations = new HashSet<URI>(); this.activeSources = new HashSet<URI>(); this.properties = new HashMap<String, String>(); this.selections = new HashMap<ProjectRef, ProjectVersionRef>(); this.filter = AnyFilter.INSTANCE; this.mutator = ManagedDependencyMutator.INSTANCE; } public Builder( final ViewParams params ) { this.workspaceId = params.getWorkspaceId(); this.roots = params.roots == null ? new HashSet<ProjectVersionRef>() : new HashSet<ProjectVersionRef>( params.roots ); this.filter = params.filter; this.mutator = params.mutator; this.activePomLocations = params.activePomLocations == null ? new HashSet<URI>() : new HashSet<URI>( params.activePomLocations ); this.activeSources = params.activeSources == null ? new HashSet<URI>() : new HashSet<URI>( params.activeSources ); this.properties = params.properties == null ? new HashMap<String, String>() : new HashMap<String, String>( params.properties ); this.selections = params.selections == null ? new HashMap<ProjectRef, ProjectVersionRef>() : new HashMap<ProjectRef, ProjectVersionRef>( params.selections ); } public Builder withRoots( final ProjectVersionRef... roots ) { this.roots.clear(); this.roots.addAll( Arrays.asList( roots ) ); return this; } public Builder withFilter( final ProjectRelationshipFilter filter ) { this.filter = filter; return this; } public Builder withMutator( final GraphMutator mutator ) { this.mutator = mutator; return this; } /** * Adds selected versions into selections map. To work properly keys * must be instances of {@link ProjectRef} or of the same class as the * one used in {@link ViewParams#getSelection(ProjectRef)} and * {@link ViewParams#hasSelection(ProjectVersionRef)}. * * @param selections * map of {@link ProjectRef} to {@link ProjectVersionRef}, * can be {@code null} indicating that no selections were * done * @return this instance for method chaining */ public Builder withSelections( final Map<ProjectRef, ProjectVersionRef> selections ) { this.selections.clear(); if ( selections != null ) { this.selections.putAll( selections ); } return this; } public Builder withProperties( final Map<String, String> properties ) { this.properties.clear(); this.properties.putAll( properties ); return this; } public Builder withActivePomLocations( final Set<URI> activePomLocations ) { this.activePomLocations.clear(); this.activePomLocations.addAll( activePomLocations ); return this; } public Builder withActiveSources( final Set<URI> activeSources ) { this.activeSources.clear(); this.activeSources.addAll( activeSources ); return this; } public ViewParams build() { return new ViewParams( workspaceId, filter, mutator, activePomLocations, activeSources, selections, properties, roots ); } public Builder withSelection( final ProjectRef target, final ProjectVersionRef selection ) { selections.put( target, selection ); return this; } public Builder withRoots( final Collection<ProjectVersionRef> roots ) { this.roots.clear(); this.roots.addAll( roots ); return this; } } }