View Javadoc
1   package org.apache.maven.archetype.ui.generation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.math.NumberUtils;
23  import org.apache.maven.archetype.catalog.Archetype;
24  import org.apache.maven.archetype.ui.ArchetypeDefinition;
25  import org.apache.maven.artifact.versioning.ArtifactVersion;
26  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
27  import org.codehaus.plexus.component.annotations.Component;
28  import org.codehaus.plexus.component.annotations.Requirement;
29  import org.codehaus.plexus.components.interactivity.Prompter;
30  import org.codehaus.plexus.components.interactivity.PrompterException;
31  import org.codehaus.plexus.logging.AbstractLogEnabled;
32  
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.HashMap;
36  import java.util.HashSet;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Set;
40  import java.util.SortedMap;
41  import java.util.TreeMap;
42  
43  @Component( role = ArchetypeSelectionQueryer.class, hint = "default" )
44  public class DefaultArchetypeSelectionQueryer
45      extends AbstractLogEnabled
46      implements ArchetypeSelectionQueryer
47  {
48      @Requirement( hint = "archetype" )
49      private Prompter prompter;
50  
51      public boolean confirmSelection( ArchetypeDefinition archetypeDefinition )
52          throws PrompterException
53      {
54          String query =
55              "Confirm archetype selection: \n" + archetypeDefinition.getGroupId() + "/" + archetypeDefinition.getName()
56                  + "\n";
57  
58          String answer = prompter.prompt( query, Arrays.asList( new String[]{ "Y", "N" } ), "Y" );
59  
60          return "Y".equalsIgnoreCase( answer );
61      }
62  
63      public Archetype selectArchetype( Map<String, List<Archetype>> catalogs )
64          throws PrompterException
65      {
66          return selectArchetype( catalogs, null );
67      }
68  
69      public Archetype selectArchetype( Map<String, List<Archetype>> catalogs, ArchetypeDefinition defaultDefinition )
70          throws PrompterException
71      {
72          Archetype selection = null;
73          Map<String, List<Archetype>> filteredCatalogs = catalogs;
74  
75          do
76          {
77              StringBuilder query = new StringBuilder( "Choose archetype:\n" );
78  
79              Set<String> archetypeKeys = new HashSet<String>();
80              List<String> answers = new ArrayList<String>();
81              Map<String, Archetype> archetypeAnswerMap = new HashMap<String, Archetype>();
82  
83              int counter = 0;
84              int defaultSelection = 0;
85  
86              for ( Map.Entry<String, List<Archetype>> entry : filteredCatalogs.entrySet() )
87              {
88                  String catalog = entry.getKey();
89  
90                  for ( Archetype archetype : entry.getValue() )
91                  {
92                      String archetypeKey = archetype.getGroupId() + ":" + archetype.getArtifactId();
93  
94                      if ( !archetypeKeys.add( archetypeKey ) )
95                      {
96                          continue;
97                      }
98  
99                      counter++;
100 
101                     String description = archetype.getDescription();
102                     if ( description == null )
103                     {
104                         description = "-";
105                     }
106 
107                     String answer = String.valueOf( counter );
108 
109                     query.append( answer + ": " + catalog + " -> " + archetype.getGroupId() + ":"
110                         + archetype.getArtifactId() + " (" + description + ")\n" );
111 
112                     answers.add( answer );
113 
114                     archetypeAnswerMap.put( answer, archetype );
115 
116                     // the version is not tested. This is intentional.
117                     if ( defaultDefinition != null && archetype.getGroupId().equals( defaultDefinition.getGroupId() )
118                         && archetype.getArtifactId().equals( defaultDefinition.getArtifactId() ) )
119                     {
120                         defaultSelection = counter;
121                     }
122                 }
123             }
124 
125             if ( counter == 0 )
126             {
127                 query.append( "   Your filter doesn't match any archetype (hint: enter to return to initial list)\n" );
128             }
129 
130             query.append( "Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): " );
131 
132             String answer;
133             if ( defaultSelection == 0 )
134             {
135                 answer = prompter.prompt( query.toString() );
136             }
137             else
138             {
139                 answer = prompter.prompt( query.toString(), Integer.toString( defaultSelection ) );
140             }
141 
142             if ( NumberUtils.isNumber( answer ) )
143             {
144                 selection = archetypeAnswerMap.get( answer );
145             }
146             else
147             {
148                 // not a number so apply filter and ask again
149                 filteredCatalogs = ArchetypeSelectorUtils.getFilteredArchetypesByCatalog( catalogs, answer );
150             }
151         }
152         while ( selection == null );
153 
154         return selectVersion( catalogs, selection.getGroupId(), selection.getArtifactId() );
155     }
156 
157     private Archetype selectVersion( Map<String, List<Archetype>> catalogs, String groupId, String artifactId )
158         throws PrompterException
159     {
160         SortedMap<ArtifactVersion, Archetype> archetypeVersionsMap = new TreeMap<ArtifactVersion, Archetype>();
161 
162         for ( Map.Entry<String, List<Archetype>> entry : catalogs.entrySet() )
163         {
164             for ( Archetype archetype : entry.getValue() )
165             {
166                 if ( !groupId.equals( archetype.getGroupId() ) || !artifactId.equals( archetype.getArtifactId() ) )
167                 {
168                     continue;
169                 }
170 
171                 ArtifactVersion version = new DefaultArtifactVersion( archetype.getVersion() );
172 
173                 // don't override the first catalog containing a defined version of the artifact
174                 if ( !archetypeVersionsMap.containsKey( version ) )
175                 {
176                     archetypeVersionsMap.put( version, archetype );
177                 }
178             }
179         }
180 
181         if ( archetypeVersionsMap.size() == 1 )
182         {
183             return archetypeVersionsMap.values().iterator().next();
184         }
185 
186         // let the user choose between available versions
187         StringBuilder query = new StringBuilder( "Choose " + groupId + ":" + artifactId + " version: \n" );
188 
189         List<String> answers = new ArrayList<String>();
190         Map<String, Archetype> answerMap = new HashMap<String, Archetype>();
191 
192         int counter = 1;
193         String mapKey = null;
194 
195         for ( Map.Entry<ArtifactVersion, Archetype> entry : archetypeVersionsMap.entrySet() )
196         {
197             ArtifactVersion version = entry.getKey();
198             Archetype archetype = entry.getValue();
199 
200             mapKey = String.valueOf( counter );
201 
202             query.append( mapKey + ": " + version + "\n" );
203 
204             answers.add( mapKey );
205 
206             answerMap.put( mapKey, archetype );
207 
208             counter++;
209         }
210 
211         query.append( "Choose a number: " );
212 
213         Archetype archetype = null;
214 
215         do
216         {
217             String answer = prompter.prompt( query.toString(), answers, mapKey );
218 
219             archetype = answerMap.get( answer );
220         }
221         while ( archetype == null );
222 
223         return archetype;
224     }
225 
226     public void setPrompter( Prompter prompter )
227     {
228         this.prompter = prompter;
229     }
230 }