package org.codehaus.mojo.pomtools.console.screens.custom; /* * Copyright 2005-2006 The Apache Software Foundation. * * 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. */ import java.util.List; import java.util.ListIterator; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.ResolutionNode; import org.codehaus.mojo.pomtools.PomToolsException; import org.codehaus.mojo.pomtools.console.screens.editors.AbstractEditListItemScreen; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleEvent; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleExecutionException; import org.codehaus.mojo.pomtools.console.toolkit.ConsoleScreenDisplay; import org.codehaus.mojo.pomtools.console.toolkit.event.ConsoleEventDispatcher; import org.codehaus.mojo.pomtools.console.toolkit.event.DefaultListener; import org.codehaus.mojo.pomtools.console.toolkit.event.NumericRangeListener; import org.codehaus.mojo.pomtools.console.toolkit.widgets.LabeledList; import org.codehaus.mojo.pomtools.helpers.ModelHelper; import org.codehaus.mojo.pomtools.helpers.TransitiveDependencyInfo; import org.codehaus.mojo.pomtools.helpers.TreeNode; import org.apache.maven.project.ProjectBuildingException; import org.codehaus.plexus.util.StringUtils; /** * * @author <a href="mailto:dhawkins@codehaus.org">David Hawkins</a> * @version $Id$ */ public class TransitiveEndPointDetailScreen extends AbstractEditListItemScreen { private static final String TITLE = "Transitive Dependency Detail"; private final String resolutionKey; private final ListTransitiveDependenciesScreen transListScreen; private List cachedDependencyNodes; public TransitiveEndPointDetailScreen( List containingList, int itemIndex, ListTransitiveDependenciesScreen transListScreen ) throws PomToolsException { super( TITLE, containingList, itemIndex ); // this shouldn't change regardless of reloading the underlying data. TransitiveDependencyInfo resolutionInfo = (TransitiveDependencyInfo) getEditorObject(); this.resolutionKey = resolutionInfo.getKey(); this.transListScreen = transListScreen; } protected void setCurrentIndex( int index ) { super.setCurrentIndex( index ); this.cachedDependencyNodes = null; } private List getDependencyNodes() throws ConsoleExecutionException { if ( cachedDependencyNodes == null ) { try { cachedDependencyNodes = ( (TransitiveDependencyInfo) getEditorObject() ).getInclusionTree() .getChildren(); } catch ( PomToolsException e ) { throw new ConsoleExecutionException( e ); } } return cachedDependencyNodes; } /** Returns whether this detail screen is operating on a single dependencyNode that has no children. * That would make it a direct project dependency. * @throws ConsoleExecutionException * */ protected boolean isSingleDirectDependency() throws ConsoleExecutionException { return getDependencyNodes().size() == 1 && !( (TreeNode) getDependencyNodes().get( 0 ) ).hasChildren(); } public ConsoleScreenDisplay getDisplay() throws ConsoleExecutionException { final TransitiveDependencyInfo resolutionInfo = (TransitiveDependencyInfo) getEditorObject(); if ( resolutionInfo == null ) { return getNoInfoDisplay(); } List dependencyNodes = getDependencyNodes(); TreeNode.Stringifier stringifier = new TreeNode.Stringifier() { public String getNodeLabel( TreeNode treeNode ) { ResolutionNode node = (ResolutionNode) treeNode.getId(); String label = ModelHelper.versionedKey( node.getArtifact() ); if ( node.getArtifact().isOptional() ) { label += " (optional)"; } if ( !treeNode.hasChildren() ) { // This is an endpoint node, so print it in bold if ( treeNode.getId() == resolutionInfo.getSelectedNode() ) { label = getTerminal().bold( label + " <<< (selected)" ); } else { label = getTerminal().bold( label ); } } return label; } }; StringBuffer sb = new StringBuffer( getHeader( TITLE ) ); sb.append( "Artifact: " ) .append( resolutionKey ) .append( NEWLINE ); sb.append( "Version: " ) .append( resolutionInfo.getSelectedArtifact().getVersion() ) .append( NEWLINE ); if ( isSingleDirectDependency() ) { // This is only 1 item in the list and it is a direct dependency from the project. // Don't give the user the option to exclude it. sb.append( "\nIncluded via explicit dependency: \n" ) .append( ( (TreeNode) dependencyNodes.get( 0 ) ).toString( stringifier ) ); } else { sb.append( "Paths:" ) .append( NEWLINE ); LabeledList lil = new LabeledList( getTerminal(), true, true ); for ( ListIterator iter = dependencyNodes.listIterator(); iter.hasNext(); ) { TreeNode tree = (TreeNode) iter.next(); String treeOutput = tree.toString( stringifier ); lil.add( numberPrompt( iter.nextIndex() ), treeOutput ); } sb.append( lil.getOutput() ); } return createDisplay( sb.toString(), "Select an item to add an explicit exclude to the dependency" ); } protected ConsoleScreenDisplay getSingleItemDisplay( TreeNode node, TreeNode.Stringifier stringifier ) { StringBuffer sb = new StringBuffer( getHeader( TITLE ) ); sb.append( "There are no endpoints to display. You probably excluded all possible paths to:\n" + resolutionKey ); return createDisplay( sb.toString(), PRESS_ENTER_TO_CONTINUE ); } protected ConsoleScreenDisplay getNoInfoDisplay() { StringBuffer sb = new StringBuffer( getHeader( TITLE ) ); sb.append( "There are no endpoints to display. You probably excluded all possible paths to:\n" + resolutionKey ); return createDisplay( sb.toString(), PRESS_ENTER_TO_CONTINUE ); } protected void reload() throws ConsoleExecutionException { try { List infoList = transListScreen.reloadTransitiveDependencies(); for ( ListIterator iter = infoList.listIterator(); iter.hasNext(); ) { TransitiveDependencyInfo info = (TransitiveDependencyInfo) iter.next(); if ( StringUtils.equals( info.getKey(), resolutionKey ) ) { setContainingList( infoList, iter.nextIndex() - 1 ); return; } } setContainingList( infoList, -1 ); } catch ( ProjectBuildingException e ) { // I don't think this should happen because we couldn't have navigated to this // screen without passing model validation first. throw new ConsoleExecutionException( "Unable to reload transitive dependencies", e ); } catch ( PomToolsException e ) { throw new ConsoleExecutionException( "Unable to reload transitive dependencies", e ); } } public ConsoleEventDispatcher getEventDispatcher() throws ConsoleExecutionException { ConsoleEventDispatcher ced = super.getDefaultEventDispatcher(); final TransitiveDependencyInfo resolutionInfo = (TransitiveDependencyInfo) getEditorObject(); if ( resolutionInfo == null ) { ced.addFirst( new DefaultListener() { public void processEvent( ConsoleEvent event ) throws ConsoleExecutionException { event.setReturnToPreviousScreen(); } } ); } else if ( !isSingleDirectDependency() ) { final List dependencyNodes = getDependencyNodes(); ced.addFirst( new NumericRangeListener( 1, dependencyNodes.size(), "Select an item to add an explicit exclude to the dependency." ) { public void processEvent( ConsoleEvent event ) throws ConsoleExecutionException { int index = Integer.parseInt( event.getConsoleInput() ) - 1; try { TreeNode treeNode = (TreeNode) dependencyNodes.get( index ); if ( treeNode.hasChildren() ) { Artifact depArtifact = ( (ResolutionNode) treeNode.getId() ).getArtifact(); Artifact artifactToExclude = resolutionInfo.getSelectedNode().getArtifact(); String excludedGroupId = artifactToExclude.getGroupId(); String excludedArtifactId = artifactToExclude.getArtifactId(); if ( ModelHelper.addExclusionForNode( depArtifact, excludedGroupId, excludedArtifactId ) ) { event.addConsoleMessage( "Exclusion " + ModelHelper.versionlessKey( excludedGroupId, excludedArtifactId ) + " was added to dependency\n" + ModelHelper.versionedKey( depArtifact ) ); reload(); } else { event.addConsoleMessage( "Exclusion was not added because it already existed." ); } } else { event.addConsoleMessage( "You cannot exclude a direct project dependency." ); } } catch ( PomToolsException e ) { throw new ConsoleExecutionException( e ); } } } ); } return ced; } }