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  package org.apache.felix.obrplugin;
20  
21  
22  import java.io.File;
23  import java.io.FileFilter;
24  import java.io.FileWriter;
25  import java.io.IOException;
26  import java.io.Writer;
27  import java.net.URI;
28  import java.net.URISyntaxException;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.apache.felix.bundlerepository.Property;
33  import org.apache.felix.bundlerepository.Resource;
34  import org.apache.felix.bundlerepository.impl.DataModelHelperImpl;
35  import org.apache.felix.bundlerepository.impl.RepositoryImpl;
36  import org.apache.felix.bundlerepository.impl.ResourceImpl;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.plugin.AbstractMojo;
39  import org.apache.maven.plugin.MojoExecutionException;
40  import org.apache.maven.plugin.logging.Log;
41  
42  
43  /**
44   * Index the content of a maven repository using OBR
45   *
46   * @goal index
47   * @requiresProject false
48   *
49   * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
50   */
51  public final class ObrIndex extends AbstractMojo
52  {
53  
54      /**
55       * OBR Repository.
56       *
57       * @parameter expression="${obrRepository}"
58       */
59      private String obrRepository;
60  
61      /**
62       * Template for urls
63       *
64       * @parameter expression="${urlTemplate}"
65       */
66      private String urlTemplate;
67  
68      /**
69       * The repository to index
70       *
71       * @parameter expression="${mavenRepository}
72       */
73      private String mavenRepository;
74  
75      /**
76       * Local Repository.
77       *
78       * @parameter expression="${localRepository}"
79       * @required
80       * @readonly
81       */
82      private ArtifactRepository localRepository;
83  
84  
85      public void execute() throws MojoExecutionException
86      {
87          Log log = getLog();
88          try
89          {
90              log.info( "Indexing..." );
91  
92              String repo = mavenRepository;
93              if ( repo == null )
94              {
95                  repo = localRepository.getBasedir();
96              }
97              URI mavenRepoUri = new File( repo ).toURI();
98  
99              URI repositoryXml = ObrUtils.findRepositoryXml( repo, obrRepository );
100 
101             log.info( "Repository:   " + mavenRepoUri );
102             log.info( "OBR xml:      " + repositoryXml );
103             log.info( "URL template: " + urlTemplate );
104 
105             List<File> files = new ArrayList<File>();
106             findAllJars( new File( repo ), files );
107 
108             DataModelHelperImpl dmh = new DataModelHelperImpl();
109             RepositoryImpl repository;
110 
111             File obrRepoFile = new File( repositoryXml );
112             if ( obrRepoFile.isFile() )
113             {
114                 repository = ( RepositoryImpl ) dmh.repository( repositoryXml.toURL() );
115             }
116             else
117             {
118                 repository = new RepositoryImpl();
119             }
120 
121             for ( File file : files )
122             {
123                 try
124                 {
125                     ResourceImpl resource = ( ResourceImpl ) dmh.createResource( file.toURI().toURL() );
126                     if ( resource != null )
127                     {
128                         repository.addResource( resource );
129                         doTemplate( mavenRepoUri, file, resource );
130                         log.info( "Adding resource: " + file );
131                     }
132                     else
133                     {
134                         log.info( "Ignoring non OSGi bundle: " + file );
135                     }
136                 }
137                 catch ( Exception e )
138                 {
139                     log.warn( "Error processing bundle: " + file + " " + e.getMessage() );
140                 }
141             }
142             Writer writer = new FileWriter( obrRepoFile );
143             try
144             {
145                 dmh.writeRepository( repository, writer );
146             }
147             finally
148             {
149                 writer.close();
150             }
151         }
152         catch ( Exception e )
153         {
154             log.warn( "Exception while updating local OBR: " + e.getLocalizedMessage(), e );
155         }
156     }
157 
158 
159     protected void doTemplate( URI root, File path, ResourceImpl resource ) throws IOException, URISyntaxException
160     {
161         path = path.getAbsoluteFile().getCanonicalFile();
162         String finalUri = root.relativize( path.toURI() ).toString();
163         if ( "maven".equals( urlTemplate ) )
164         {
165             String dir = root.relativize( path.toURI() ).toString();
166             String[] p = dir.split( "/" );
167             if ( p.length >= 4 && p[p.length - 1].startsWith( p[p.length - 3] + "-" + p[p.length - 2] ) )
168             {
169                 String artifactId = p[p.length - 3];
170                 String version = p[p.length - 2];
171                 String classifier;
172                 String type;
173                 String artifactIdVersion = artifactId + "-" + version;
174                 StringBuffer sb = new StringBuffer();
175                 if ( p[p.length - 1].charAt( artifactIdVersion.length() ) == '-' )
176                 {
177                     classifier = p[p.length - 1].substring( artifactIdVersion.length() + 1,
178                         p[p.length - 1].lastIndexOf( '.' ) );
179                 }
180                 else
181                 {
182                     classifier = null;
183                 }
184                 type = p[p.length - 1].substring( p[p.length - 1].lastIndexOf( '.' ) + 1 );
185                 sb.append( "mvn:" );
186                 for ( int j = 0; j < p.length - 3; j++ )
187                 {
188                     if ( j > 0 )
189                     {
190                         sb.append( '.' );
191                     }
192                     sb.append( p[j] );
193                 }
194                 sb.append( '/' ).append( artifactId ).append( '/' ).append( version );
195                 if ( !"jar".equals( type ) || classifier != null )
196                 {
197                     sb.append( '/' );
198                     if ( !"jar".equals( type ) )
199                     {
200                         sb.append( type );
201                     }
202                     if ( classifier != null )
203                     {
204                         sb.append( '/' ).append( classifier );
205                     }
206                 }
207                 finalUri = sb.toString();
208             }
209         }
210         else if ( urlTemplate != null )
211         {
212             URI parentDir = path.getParentFile().toURI();
213 
214             String absoluteDir = trim( root.toString(), parentDir.toURL().toString() );
215             String relativeDir = trim( root.toString(), root.relativize( parentDir ).toString() );
216 
217             String url = urlTemplate.replaceAll( "%v", "" + resource.getVersion() );
218             url = url.replaceAll( "%s", resource.getSymbolicName() );
219             url = url.replaceAll( "%f", path.getName() );
220             url = url.replaceAll( "%p", absoluteDir );
221             url = url.replaceAll( "%rp", relativeDir );
222             finalUri = url;
223         }
224         resource.put( Resource.URI, finalUri, Property.URI );
225     }
226 
227 
228     private String trim( String prefix, String path )
229     {
230         if ( path.endsWith( "/" ) )
231             path = path.substring( 0, path.length() - 1 );
232 
233         if ( path.startsWith( prefix ) )
234             path = path.substring( prefix.length() );
235 
236         return path;
237     }
238 
239 
240     private final FileFilter filter = new FileFilter()
241     {
242         public boolean accept( File pathname )
243         {
244             return pathname.getName().endsWith( "ar" );
245         }
246     };
247 
248 
249     private void findAllJars( File mainRoot, List<File> files )
250     {
251         List<File> roots = new ArrayList<File>();
252         roots.add( mainRoot );
253         while ( !roots.isEmpty() )
254         {
255             File root = roots.remove( 0 );
256             File[] children = root.listFiles();
257             if ( children != null )
258             {
259                 for ( File child : children )
260                 {
261                     if ( child.isFile() && filter.accept( child ) )
262                     {
263                         files.add( child );
264                     }
265                     else if ( child.isDirectory() )
266                     {
267                         roots.add( child );
268                     }
269                 }
270             }
271         }
272     }
273 
274 }