View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.maven.archetype.ui;
21  
22  import org.apache.commons.collections.iterators.ArrayIterator;
23  import org.apache.maven.archetype.ArchetypeGenerationRequest;
24  import org.apache.maven.archetype.catalog.Archetype;
25  import org.apache.maven.archetype.common.ArchetypeDefinition;
26  import org.apache.maven.archetype.exception.ArchetypeNotDefined;
27  import org.apache.maven.archetype.exception.ArchetypeSelectionFailure;
28  import org.apache.maven.archetype.exception.UnknownArchetype;
29  import org.apache.maven.archetype.exception.UnknownGroup;
30  import org.codehaus.plexus.components.interactivity.PrompterException;
31  import org.codehaus.plexus.logging.AbstractLogEnabled;
32  import org.codehaus.plexus.util.StringUtils;
33  
34  import java.io.IOException;
35  import java.util.HashMap;
36  import java.util.Iterator;
37  import java.util.List;
38  import java.util.Map;
39  import java.util.Properties;
40  
41  /** @plexus.component */
42  public class DefaultArchetypeSelector
43      extends AbstractLogEnabled
44      implements ArchetypeSelector
45  {
46      static final String DEFAULT_ARCHETYPE_GROUPID = "org.apache.maven.archetypes";
47  
48      static final String DEFAULT_ARCHETYPE_VERSION = "1.0";
49  
50      static final String DEFAULT_ARCHETYPE_ARTIFACTID = "maven-archetype-quickstart";
51  
52      /** @plexus.requirement */
53      private ArchetypeSelectionQueryer archetypeSelectionQueryer;
54      /** @plexus.requirement */
55      private org.apache.maven.archetype.Archetype archetype;
56  
57      public void selectArchetype( ArchetypeGenerationRequest request, 
58              Boolean interactiveMode, String catalogs )
59          throws
60          ArchetypeNotDefined,
61          UnknownArchetype,
62          UnknownGroup,
63          IOException,
64          PrompterException,
65          ArchetypeSelectionFailure                    
66      {
67          //This should be an internal class
68          ArchetypeDefinition definition = new ArchetypeDefinition();
69  
70          definition.setGroupId( request.getArchetypeGroupId() );
71          definition.setArtifactId( request.getArchetypeArtifactId() );
72          definition.setVersion( request.getArchetypeVersion() );
73          
74          Map archetypes = getArchetypesByCatalog ( catalogs );
75  
76          if ( definition.isDefined ()
77              && StringUtils.isNotEmpty ( request.getArchetypeRepository () )
78          )
79          {
80              getLogger ().info ( "Archetype defined by properties" );
81          }
82          else
83          {
84              if ( definition.isDefined ()
85                  && StringUtils.isEmpty ( request.getArchetypeRepository () )
86              )
87              {
88                  Iterator ca = new ArrayIterator ( StringUtils.split ( catalogs, "," ) );
89                  boolean found = false;
90                  while ( !found && ca.hasNext () )
91                  {
92                      String catalogKey = (String) ca.next ();
93                      String[] keySplitted = catalogKey.split("-", 2);
94                      List catalog = (List) archetypes.get ( catalogKey );
95                      Archetype example = new Archetype ();
96                      example.setGroupId ( request.getArchetypeGroupId () );
97                      example.setArtifactId ( request.getArchetypeArtifactId () );
98                      if ( catalog.contains ( example ) )
99                      {
100                         found = true;
101 
102                         Archetype foundArchetype =
103                             (Archetype) catalog.get ( catalog.indexOf ( example ) );
104                         definition.setName ( foundArchetype.getArtifactId () );
105                         if ( StringUtils.isNotEmpty( foundArchetype.getRepository () ) )
106                         {
107                             definition.setRepository ( foundArchetype.getRepository () );
108                         }
109                         else if ( keySplitted.length > 1 )
110                         {
111                             int lastIndex = catalogKey.lastIndexOf("/");
112                             String catalogBase = catalogKey.substring(0, 
113                                     (lastIndex > 7 ? lastIndex : catalogKey.length()));
114                             definition.setRepository ( catalogBase );
115                         }
116 
117                         getLogger ().info (
118                             "Archetype repository missing. Using the one from " + foundArchetype
119                             + " found in catalog " + catalogKey
120                         );
121                     }
122                 }
123                 if ( !found )
124                 {
125                     getLogger ().warn ( "No archetype repository found. Falling back to central repository (http://repo1.maven.org/maven2). " );
126                     getLogger ().warn ( "Use -DarchetypeRepository=<your repository> if archetype's repository is elsewhere." );
127                     
128                     definition.setRepository("http://repo1.maven.org/maven2");
129                 }
130             }
131             if ( !definition.isDefined () && definition.isPartiallyDefined () )
132             {
133                 Iterator ca = new ArrayIterator ( StringUtils.split ( catalogs, "," ) );
134                 boolean found = false;
135                 while ( !found && ca.hasNext () )
136                 {
137                     String catalogKey = (String) ca.next ();
138                     List catalog = (List) archetypes.get ( catalogKey );
139                     String[] keySplitted = catalogKey.split(":", 2);
140                     Archetype example = new Archetype ();
141                     example.setGroupId ( request.getArchetypeGroupId () );
142                     example.setArtifactId ( request.getArchetypeArtifactId () );
143                     if ( catalog.contains ( example ) )
144                     {
145                         found = true;
146 
147                         Archetype foundArchetype =
148                             (Archetype) catalog.get ( catalog.indexOf ( example ) );
149                         definition.setGroupId ( foundArchetype.getGroupId () );
150                         definition.setArtifactId ( foundArchetype.getArtifactId () );
151                         definition.setVersion ( foundArchetype.getVersion () );
152                         definition.setName ( foundArchetype.getArtifactId () );
153                         if ( StringUtils.isNotEmpty( foundArchetype.getRepository () ) )
154                         {
155                             definition.setRepository ( foundArchetype.getRepository () );
156                         }
157                         else if ( keySplitted.length > 1 )
158                         {
159                             int lastIndex = catalogKey.lastIndexOf("/");
160                             String catalogBase = catalogKey.substring(0, 
161                                     (lastIndex > 7 ? lastIndex : catalogKey.length()));
162                             definition.setRepository ( catalogBase );
163                         }
164 
165                         String goals =
166                             StringUtils.join ( foundArchetype.getGoals ().iterator (), "," );
167                         definition.setGoals ( goals );
168 
169                         getLogger ().info (
170                             "Archetype " + foundArchetype
171                             + " found in catalog " + catalogKey
172                         );
173                     }
174                 }
175                 if ( !found )
176                 {
177                     getLogger ().warn ( "Specified archetype not found." );
178                     if ( interactiveMode.booleanValue () )
179                     {
180                         definition.setVersion ( null );
181                         definition.setGroupId ( null );
182                         definition.setArtifactId ( null );
183                     }
184                 }
185             }
186         }
187 
188         // set the defaults - only group and version can be auto-defaulted
189         if ( definition.getGroupId() == null )
190         {
191             definition.setGroupId( DEFAULT_ARCHETYPE_GROUPID );
192         }
193         if ( definition.getVersion() == null )
194         {
195             definition.setVersion( DEFAULT_ARCHETYPE_VERSION );
196         }
197 
198         if ( !definition.isDefined() && !definition.isPartiallyDefined() )
199         {
200             // if artifact ID is set to it's default, we still prompt to confirm 
201             if ( definition.getArtifactId() == null )
202             {
203                 getLogger().info( "No archetype defined. Using " + DEFAULT_ARCHETYPE_ARTIFACTID + " ("
204                     + definition.getGroupId() + ":" + DEFAULT_ARCHETYPE_ARTIFACTID + ":" + definition.getVersion()
205                     + ")" );
206                 definition.setArtifactId( DEFAULT_ARCHETYPE_ARTIFACTID );
207             }
208 
209             if ( interactiveMode.booleanValue() )
210             {
211                 if ( archetypes.size() > 0 )
212                 {
213                     Archetype selectedArchetype = archetypeSelectionQueryer.selectArchetype( archetypes, definition );
214 
215                     definition.setGroupId( selectedArchetype.getGroupId() );
216                     definition.setArtifactId( selectedArchetype.getArtifactId() );
217                     definition.setVersion( selectedArchetype.getVersion() );
218                     definition.setName( selectedArchetype.getArtifactId() );
219                     String catalogKey = getCatalogKey ( archetypes, selectedArchetype );
220                     String[] keySplitted = catalogKey.split(":", 2);
221                     if ( StringUtils.isNotEmpty( selectedArchetype.getRepository () ) )
222                     {
223                         definition.setRepository ( selectedArchetype.getRepository () );
224                     }
225                     else if ( keySplitted.length > 1 )
226                     {
227                         int lastIndex = catalogKey.lastIndexOf("/");
228                         String catalogBase = catalogKey.substring(0, 
229                                 (lastIndex > 7 ? lastIndex : catalogKey.length()));
230                         definition.setRepository ( catalogBase );
231                     }
232                     String goals = StringUtils.join( selectedArchetype.getGoals().iterator(), "," );
233                     definition.setGoals( goals );
234                 }
235             }
236         }
237 
238         // Make sure the groupId and artifactId are valid, the version may just default to
239         // the latest release.
240 
241         if ( !definition.isPartiallyDefined() )
242         {
243             throw new ArchetypeSelectionFailure( "No valid archetypes could be found to choose." );
244         }
245 
246         request.setArchetypeGroupId( definition.getGroupId() );
247 
248         request.setArchetypeArtifactId( definition.getArtifactId() );
249 
250         request.setArchetypeVersion( definition.getVersion() );
251 
252         request.setArchetypeGoals( definition.getGoals() );
253 
254         request.setArchetypeName( definition.getName() );
255 
256         if (StringUtils.isNotEmpty(definition.getRepository())){
257             request.setArchetypeRepository( definition.getRepository() );
258         }
259     }
260 
261     private Map getArchetypesByCatalog(String catalogs) {
262         if ( catalogs == null )
263         {
264             throw new NullPointerException( "catalogs can not be null" );
265         }
266 
267         Map archetypes = new HashMap();
268 
269         Iterator ca = new ArrayIterator(StringUtils.split(catalogs, ","));
270         while (ca.hasNext()) {
271             String catalog = (String) ca.next();
272 
273             if ("internal".equalsIgnoreCase(catalog)) {
274                 archetypes.put("internal", archetype.getInternalCatalog().getArchetypes());
275             } else if ("local".equalsIgnoreCase(catalog)) {
276                 archetypes.put("local", archetype.getDefaultLocalCatalog().getArchetypes());
277             } else if ("remote".equalsIgnoreCase(catalog)) {
278                 archetypes.put("remote", archetype.getRemoteCatalog().getArchetypes());
279             } else if (catalog.startsWith("file://")) {
280                 String path = catalog.substring(7);
281                 archetypes.put(catalog, archetype.getLocalCatalog(path).getArchetypes());
282             } else if (catalog.startsWith("http://")) {
283                 archetypes.put(catalog, archetype.getRemoteCatalog(catalog).getArchetypes());
284             }
285         }
286 
287         if (archetypes.size() == 0) {
288             getLogger().info("No catalog defined. Using internal catalog");
289 
290             archetypes.put("internal", archetype.getInternalCatalog().getArchetypes());
291         }
292         return archetypes;
293     }
294 
295     private Properties getArchetypeDataSourceProperties( String sourceRoleHint,
296                                                          Properties archetypeCatalogProperties )
297     {
298         Properties p = new Properties();
299 
300         for ( Iterator i = archetypeCatalogProperties.keySet().iterator(); i.hasNext(); )
301         {
302             String key = (String) i.next();
303 
304             if ( key.startsWith( sourceRoleHint ) )
305             {
306                 String k = key.substring( sourceRoleHint.length() + 1 );
307 
308                 p.setProperty( k, archetypeCatalogProperties.getProperty( key ) );
309             }
310         }
311 
312         return p;
313     }
314 
315     public void setArchetypeSelectionQueryer( ArchetypeSelectionQueryer archetypeSelectionQueryer )
316     {
317         this.archetypeSelectionQueryer = archetypeSelectionQueryer;
318     }
319 
320     private String getCatalogKey(Map archetypes, Archetype selectedArchetype) {
321         String key = "";
322         Iterator keys = archetypes.keySet().iterator();
323         boolean found = false;
324         while ( keys.hasNext() && !found)
325         {
326             key = (String) keys.next();
327             List catalog = (List) archetypes.get( key );
328             if ( catalog.contains( selectedArchetype ) )
329             {
330                 found = true;
331             }
332         }
333         return key;
334     }
335 }