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<>();
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         return new ArtifactDescription( relocation, dependencies, managedDependencies, repositories );
179     }
180 
181     private List<RemoteRepository> repositories( List<String> list )
182     {
183         ArrayList<RemoteRepository> ret = new ArrayList<>();
184         if ( list == null )
185         {
186             return ret;
187         }
188         for ( String coords : list )
189         {
190             String[] split = coords.split( ":", 3 );
191             String id = split[0];
192             String type = split[1];
193             String url = split[2];
194 
195             ret.add( new RemoteRepository.Builder( id, type, url ).build() );
196         }
197         return ret;
198     }
199 
200     private List<Dependency> dependencies( List<String> list, boolean managed )
201     {
202         List<Dependency> ret = new ArrayList<>();
203         if ( list == null )
204         {
205             return ret;
206         }
207 
208         Collection<Exclusion> exclusions = new ArrayList<>();
209 
210         Boolean optional = null;
211         Artifact artifact = null;
212         String scope = null;
213 
214         for ( String coords : list )
215         {
216             if ( coords.startsWith( "-" ) )
217             {
218                 coords = coords.substring( 1 );
219                 String[] split = coords.split( ":" );
220                 exclusions.add( new Exclusion( split[0], split[1], "*", "*" ) );
221             }
222             else
223             {
224                 if ( artifact != null )
225                 {
226                     // commit dependency
227                     Dependency dep = new Dependency( artifact, scope, optional, exclusions );
228                     ret.add( dep );
229 
230                     exclusions = new ArrayList<>();
231                 }
232 
233                 ArtifactDefinition def = new ArtifactDefinition( coords );
234 
235                 optional = managed ? def.getOptional() : Boolean.valueOf( Boolean.TRUE.equals( def.getOptional() ) );
236 
237                 scope = "".equals( def.getScope() ) && !managed ? "compile" : def.getScope();
238 
239                 artifact =
240                     new DefaultArtifact( def.getGroupId(), def.getArtifactId(), "", def.getExtension(),
241                                          def.getVersion() );
242             }
243         }
244         if ( artifact != null )
245         {
246             // commit dependency
247             Dependency dep = new Dependency( artifact, scope, optional, exclusions );
248             ret.add( dep );
249         }
250 
251         return ret;
252     }
253 
254     private Artifact relocation( List<String> list )
255     {
256         if ( list == null || list.isEmpty() )
257         {
258             return null;
259         }
260         String coords = list.get( 0 );
261         ArtifactDefinition def = new ArtifactDefinition( coords );
262         return new DefaultArtifact( def.getGroupId(), def.getArtifactId(), "", def.getExtension(), def.getVersion() );
263     }
264 
265     private static boolean isEmpty( String line )
266     {
267         return line == null || line.length() == 0;
268     }
269 
270     private static String cutComment( String line )
271     {
272         int idx = line.indexOf( '#' );
273 
274         if ( idx != -1 )
275         {
276             line = line.substring( 0, idx );
277         }
278 
279         return line;
280     }
281 
282     static class Definition
283     {
284         private String groupId;
285 
286         private String artifactId;
287 
288         private String extension;
289 
290         private String version;
291 
292         private String scope = "";
293 
294         private String definition;
295 
296         private String id = null;
297 
298         private String reference = null;
299 
300         private boolean optional = false;
301 
302         Definition( String def )
303         {
304             this.definition = def.trim();
305 
306             if ( definition.startsWith( "(" ) )
307             {
308                 int idx = definition.indexOf( ')' );
309                 this.id = definition.substring( 1, idx );
310                 this.definition = definition.substring( idx + 1 );
311             }
312             else if ( definition.startsWith( "^" ) )
313             {
314                 this.reference = definition.substring( 1 );
315                 return;
316             }
317 
318             String[] split = definition.split( ":" );
319             if ( split.length < 4 )
320             {
321                 throw new IllegalArgumentException( "Need definition like 'gid:aid:ext:ver[:scope]', but was: "
322                     + definition );
323             }
324             groupId = split[0];
325             artifactId = split[1];
326             extension = split[2];
327             version = split[3];
328             if ( split.length > 4 )
329             {
330                 scope = split[4];
331             }
332             if ( split.length > 5 && "true".equalsIgnoreCase( split[5] ) )
333             {
334                 optional = true;
335             }
336         }
337 
338         public String getGroupId()
339         {
340             return groupId;
341         }
342 
343         public String getArtifactId()
344         {
345             return artifactId;
346         }
347 
348         public String getType()
349         {
350             return extension;
351         }
352 
353         public String getVersion()
354         {
355             return version;
356         }
357 
358         public String getScope()
359         {
360             return scope;
361         }
362 
363         @Override
364         public String toString()
365         {
366             return definition;
367         }
368 
369         public String getId()
370         {
371             return id;
372         }
373 
374         public String getReference()
375         {
376             return reference;
377         }
378 
379         public boolean isReference()
380         {
381             return reference != null;
382         }
383 
384         public boolean hasId()
385         {
386             return id != null;
387         }
388 
389         public boolean isOptional()
390         {
391             return optional;
392         }
393     }
394 
395 }