    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 }