View Javadoc
1   package org.eclipse.aether.internal.test.util;
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 java.io.BufferedReader;
23  import java.io.IOException;
24  import java.io.InputStreamReader;
25  import java.io.Reader;
26  import java.io.StringReader;
27  import java.net.URL;
28  import java.nio.charset.StandardCharsets;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Map;
35  
36  import org.eclipse.aether.artifact.Artifact;
37  import org.eclipse.aether.artifact.DefaultArtifact;
38  import org.eclipse.aether.graph.Dependency;
39  import org.eclipse.aether.graph.Exclusion;
40  import org.eclipse.aether.repository.RemoteRepository;
41  
42  /**
43   * @see IniArtifactDescriptorReader
44   */
45  class IniArtifactDataReader
46  {
47  
48      private String prefix = "";
49  
50      /**
51       * Constructs a data reader with the prefix {@code ""}.
52       */
53      IniArtifactDataReader()
54      {
55          this( "" );
56      }
57  
58      /**
59       * Constructs a data reader with the given prefix.
60       * 
61       * @param prefix the prefix to use for loading resources from the classpath.
62       */
63      IniArtifactDataReader( String prefix )
64      {
65          this.prefix = prefix;
66  
67      }
68  
69      /**
70       * Load an artifact description from the classpath and parse it.
71       */
72      public ArtifactDescription parse( String resource )
73          throws IOException
74      {
75          URL res = this.getClass().getClassLoader().getResource( prefix + resource );
76  
77          if ( res == null )
78          {
79              throw new IOException( "cannot find resource: " + resource );
80          }
81          return parse( res );
82      }
83  
84      /**
85       * Open the given URL and parse ist.
86       */
87      public ArtifactDescription parse( URL res )
88          throws IOException
89      {
90          return parse( new InputStreamReader( res.openStream(), StandardCharsets.UTF_8 ) );
91      }
92  
93      /**
94       * Parse the given String.
95       */
96      public ArtifactDescription parseLiteral( String description )
97          throws IOException
98      {
99          StringReader reader = new StringReader( description );
100         return parse( reader );
101     }
102 
103     private enum State
104     {
105         NONE, RELOCATION, DEPENDENCIES, MANAGEDDEPENDENCIES, REPOSITORIES
106     }
107 
108     private ArtifactDescription parse( Reader reader )
109         throws IOException
110     {
111         String line = null;
112 
113         State state = State.NONE;
114 
115         Map<State, List<String>> sections = new HashMap<State, List<String>>();
116 
117         BufferedReader in = null;
118         try
119         {
120             in = new BufferedReader( reader );
121             while ( ( line = in.readLine() ) != null )
122             {
123 
124                 line = cutComment( line );
125                 if ( isEmpty( line ) )
126                 {
127                     continue;
128                 }
129 
130                 if ( line.startsWith( "[" ) )
131                 {
132                     try
133                     {
134                         String name = line.substring( 1, line.length() - 1 );
135                         name = name.replace( "-", "" ).toUpperCase( Locale.ENGLISH );
136                         state = State.valueOf( name );
137                         sections.put( state, new ArrayList<String>() );
138                     }
139                     catch ( IllegalArgumentException e )
140                     {
141                         throw new IOException( "unknown section: " + line );
142                     }
143                 }
144                 else
145                 {
146                     List<String> lines = sections.get( state );
147                     if ( lines == null )
148                     {
149                         throw new IOException( "missing section: " + line );
150                     }
151                     lines.add( line.trim() );
152                 }
153             }
154 
155             in.close();
156             in = null;
157         }
158         finally
159         {
160             try
161             {
162                 if ( in != null )
163                 {
164                     in.close();
165                 }
166             }
167             catch ( final IOException e )
168             {
169                 // Suppressed due to an exception already thrown in the try block.
170             }
171         }
172 
173         Artifact relocation = relocation( sections.get( State.RELOCATION ) );
174         List<Dependency> dependencies = dependencies( sections.get( State.DEPENDENCIES ), false );
175         List<Dependency> managedDependencies = dependencies( sections.get( State.MANAGEDDEPENDENCIES ), true );
176         List<RemoteRepository> repositories = repositories( sections.get( State.REPOSITORIES ) );
177 
178         ArtifactDescription description =
179             new ArtifactDescription( relocation, dependencies, managedDependencies, repositories );
180         return description;
181     }
182 
183     private List<RemoteRepository> repositories( List<String> list )
184     {
185         ArrayList<RemoteRepository> ret = new ArrayList<RemoteRepository>();
186         if ( list == null )
187         {
188             return ret;
189         }
190         for ( String coords : list )
191         {
192             String[] split = coords.split( ":", 3 );
193             String id = split[0];
194             String type = split[1];
195             String url = split[2];
196 
197             ret.add( new RemoteRepository.Builder( id, type, url ).build() );
198         }
199         return ret;
200     }
201 
202     private List<Dependency> dependencies( List<String> list, boolean managed )
203     {
204         List<Dependency> ret = new ArrayList<Dependency>();
205         if ( list == null )
206         {
207             return ret;
208         }
209 
210         Collection<Exclusion> exclusions = new ArrayList<Exclusion>();
211 
212         Boolean optional = null;
213         Artifact artifact = null;
214         String scope = null;
215 
216         for ( String coords : list )
217         {
218             if ( coords.startsWith( "-" ) )
219             {
220                 coords = coords.substring( 1 );
221                 String[] split = coords.split( ":" );
222                 exclusions.add( new Exclusion( split[0], split[1], "*", "*" ) );
223             }
224             else
225             {
226                 if ( artifact != null )
227                 {
228                     // commit dependency
229                     Dependency dep = new Dependency( artifact, scope, optional, exclusions );
230                     ret.add( dep );
231 
232                     exclusions = new ArrayList<Exclusion>();
233                 }
234 
235                 ArtifactDefinition def = new ArtifactDefinition( coords );
236 
237                 optional = managed ? def.getOptional() : Boolean.valueOf( Boolean.TRUE.equals( def.getOptional() ) );
238 
239                 scope = "".equals( def.getScope() ) && !managed ? "compile" : def.getScope();
240 
241                 artifact =
242                     new DefaultArtifact( def.getGroupId(), def.getArtifactId(), "", def.getExtension(),
243                                          def.getVersion() );
244             }
245         }
246         if ( artifact != null )
247         {
248             // commit dependency
249             Dependency dep = new Dependency( artifact, scope, optional, exclusions );
250             ret.add( dep );
251         }
252 
253         return ret;
254     }
255 
256     private Artifact relocation( List<String> list )
257     {
258         if ( list == null || list.isEmpty() )
259         {
260             return null;
261         }
262         String coords = list.get( 0 );
263         ArtifactDefinition def = new ArtifactDefinition( coords );
264         return new DefaultArtifact( def.getGroupId(), def.getArtifactId(), "", def.getExtension(), def.getVersion() );
265     }
266 
267     private static boolean isEmpty( String line )
268     {
269         return line == null || line.length() == 0;
270     }
271 
272     private static String cutComment( String line )
273     {
274         int idx = line.indexOf( '#' );
275 
276         if ( idx != -1 )
277         {
278             line = line.substring( 0, idx );
279         }
280 
281         return line;
282     }
283 
284     static class Definition
285     {
286         private String groupId;
287 
288         private String artifactId;
289 
290         private String extension;
291 
292         private String version;
293 
294         private String scope = "";
295 
296         private String definition;
297 
298         private String id = null;
299 
300         private String reference = null;
301 
302         private boolean optional = false;
303 
304         Definition( String def )
305         {
306             this.definition = def.trim();
307 
308             if ( definition.startsWith( "(" ) )
309             {
310                 int idx = definition.indexOf( ')' );
311                 this.id = definition.substring( 1, idx );
312                 this.definition = definition.substring( idx + 1 );
313             }
314             else if ( definition.startsWith( "^" ) )
315             {
316                 this.reference = definition.substring( 1 );
317                 return;
318             }
319 
320             String[] split = definition.split( ":" );
321             if ( split.length < 4 )
322             {
323                 throw new IllegalArgumentException( "Need definition like 'gid:aid:ext:ver[:scope]', but was: "
324                     + definition );
325             }
326             groupId = split[0];
327             artifactId = split[1];
328             extension = split[2];
329             version = split[3];
330             if ( split.length > 4 )
331             {
332                 scope = split[4];
333             }
334             if ( split.length > 5 && "true".equalsIgnoreCase( split[5] ) )
335             {
336                 optional = true;
337             }
338         }
339 
340         public String getGroupId()
341         {
342             return groupId;
343         }
344 
345         public String getArtifactId()
346         {
347             return artifactId;
348         }
349 
350         public String getType()
351         {
352             return extension;
353         }
354 
355         public String getVersion()
356         {
357             return version;
358         }
359 
360         public String getScope()
361         {
362             return scope;
363         }
364 
365         @Override
366         public String toString()
367         {
368             return definition;
369         }
370 
371         public String getId()
372         {
373             return id;
374         }
375 
376         public String getReference()
377         {
378             return reference;
379         }
380 
381         public boolean isReference()
382         {
383             return reference != null;
384         }
385 
386         public boolean hasId()
387         {
388             return id != null;
389         }
390 
391         public boolean isOptional()
392         {
393             return optional;
394         }
395     }
396 
397 }