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  package org.apache.felix.obrplugin;
20  
21  
22  import java.io.File;
23  import java.net.URI;
24  import java.net.URL;
25  import java.util.Arrays;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.regex.Matcher;
29  import java.util.regex.Pattern;
30  
31  import org.apache.maven.artifact.Artifact;
32  import org.apache.maven.artifact.manager.WagonManager;
33  import org.apache.maven.artifact.repository.ArtifactRepository;
34  import org.apache.maven.plugin.AbstractMojo;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugin.logging.Log;
37  import org.apache.maven.plugins.annotations.Component;
38  import org.apache.maven.plugins.annotations.LifecyclePhase;
39  import org.apache.maven.plugins.annotations.Mojo;
40  import org.apache.maven.plugins.annotations.Parameter;
41  import org.apache.maven.project.MavenProject;
42  import org.apache.maven.settings.Settings;
43  
44  
45  /**
46   * Deploys bundle details to a remote OBR repository (life-cycle goal)
47   *
48   * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
49   */
50  @Mojo( name = "deploy", threadSafe = true, defaultPhase = LifecyclePhase.DEPLOY )
51  public final class ObrDeploy extends AbstractMojo
52  {
53      /**
54       * When true, ignore remote locking.
55       */
56      @Parameter( property = "ignoreLock" )
57      private boolean ignoreLock;
58  
59      /**
60       * Optional public URL prefix for the remote repository.
61       */
62      @Parameter( property = "prefixUrl" )
63      private String prefixUrl;
64  
65      /**
66       * Optional public URL where the bundle has been deployed.
67       */
68      @Parameter( property = "bundleUrl" )
69      private String bundleUrl;
70  
71      /**
72       * Remote OBR Repository.
73       */
74      @Parameter( property = "remoteOBR", defaultValue = "NONE" )
75      private String remoteOBR;
76  
77      /**
78       * Local OBR Repository.
79       */
80      @Parameter( property = "obrRepository" )
81      private String obrRepository;
82  
83      /**
84       * Project types which this plugin supports.
85       */
86      @Parameter
87      private List supportedProjectTypes = Arrays.asList( new String[]
88          { "jar", "bundle" } );
89  
90      @Parameter( defaultValue = "${project.distributionManagementArtifactRepository}", readonly = true )
91      private ArtifactRepository deploymentRepository;
92  
93      /**
94       * Alternative deployment repository. Format: id::layout::url
95       */
96      @Parameter( property = "altDeploymentRepository" )
97      private String altDeploymentRepository;
98  
99      /**
100      * OBR specific deployment repository. Format: id::layout::url
101      */
102     @Parameter( property = "obrDeploymentRepository" )
103    private String obrDeploymentRepository;
104 
105     /**
106      * Local Repository.
107      */
108     @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
109     private ArtifactRepository localRepository;
110 
111     /**
112      * The Maven project.
113      */
114     @Parameter( defaultValue = "${project}", readonly = true, required = true )
115     private MavenProject project;
116 
117     @Parameter( defaultValue = "${project.attachedArtifacts}", readonly = true, required = true )
118     private List attachedArtifacts;
119 
120     /**
121      * Local Maven settings.
122      */
123     @Parameter( defaultValue = "${settings}", readonly = true, required = true )
124     private Settings settings;
125 
126     /**
127      * The Wagon manager.
128      */
129     @Component
130     private WagonManager m_wagonManager;
131 
132     /**
133      * Attached source artifact
134      */
135     private Artifact m_sourceArtifact;
136 
137     /**
138      * Attached doc artifact
139      */
140     private Artifact m_docArtifact;
141 
142 
143     public void execute() throws MojoExecutionException
144     {
145         String projectType = project.getPackaging();
146 
147         // ignore unsupported project types, useful when bundleplugin is configured in parent pom
148         if ( !supportedProjectTypes.contains( projectType ) )
149         {
150             getLog().warn(
151                 "Ignoring project type " + projectType + " - supportedProjectTypes = " + supportedProjectTypes );
152             return;
153         }
154         else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remoteOBR ) )
155         {
156             getLog().info( "Remote OBR update disabled (enable with -DremoteOBR)" );
157             return;
158         }
159 
160         // check for any attached sources or docs
161         for ( Iterator i = attachedArtifacts.iterator(); i.hasNext(); )
162         {
163             Artifact artifact = ( Artifact ) i.next();
164             if ( "sources".equals( artifact.getClassifier() ) )
165             {
166                 m_sourceArtifact = artifact;
167             }
168             else if ( "javadoc".equals( artifact.getClassifier() ) )
169             {
170                 m_docArtifact = artifact;
171             }
172         }
173 
174         // if the user doesn't supply an explicit name for the remote OBR file, use the local name instead
175         if ( null == remoteOBR || remoteOBR.trim().length() == 0 || "true".equalsIgnoreCase( remoteOBR ) )
176         {
177             remoteOBR = obrRepository;
178         }
179 
180         URI tempURI = ObrUtils.findRepositoryXml( "", remoteOBR );
181         String repositoryName = new File( tempURI.getSchemeSpecificPart() ).getName();
182 
183         Log log = getLog();
184         ObrUpdate update;
185 
186         RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
187         openRepositoryConnection( remoteFile );
188 
189         // ======== LOCK REMOTE OBR ========
190         log.info( "LOCK " + remoteFile + '/' + repositoryName );
191         remoteFile.lockFile( repositoryName, ignoreLock );
192         File downloadedRepositoryXml = null;
193 
194         try
195         {
196             // ======== DOWNLOAD REMOTE OBR ========
197             log.info( "Downloading " + repositoryName );
198             downloadedRepositoryXml = remoteFile.get( repositoryName, ".xml" );
199 
200             String mavenRepository = localRepository.getBasedir();
201 
202             URI repositoryXml = downloadedRepositoryXml.toURI();
203             URI obrXmlFile = ObrUtils.findObrXml( project );
204 
205             Config userConfig = new Config();
206             userConfig.setRemoteFile( true );
207 
208             if ( bundleUrl != null )
209             {
210                 // public URL differs from the bundle file location
211                 URI uri = URI.create( bundleUrl );
212                 log.info( "Computed bundle uri: " + uri );
213                 userConfig.setRemoteBundle( uri );
214             }
215             else if ( prefixUrl != null )
216             {
217                 // support absolute bundle URLs based on given prefix
218                 URI bundleJar = ObrUtils.getArtifactURI( localRepository, project.getArtifact() );
219                 String relative = ObrUtils.getRelativeURI( ObrUtils.toFileURI( mavenRepository ), bundleJar )
220                     .toASCIIString();
221                 URL resourceURL = new URL( new URL( prefixUrl + '/' ), relative );
222                 URI uri = URI.create( resourceURL.toString() );
223                 log.info( "Computed bundle uri: " + uri );
224                 userConfig.setRemoteBundle( uri );
225             }
226 
227             update = new ObrUpdate( repositoryXml, obrXmlFile, project, mavenRepository, userConfig, log );
228             update.parseRepositoryXml();
229 
230             updateRemoteBundleMetadata( project.getArtifact(), update );
231             for ( Iterator i = attachedArtifacts.iterator(); i.hasNext(); )
232             {
233                 updateRemoteBundleMetadata( ( Artifact ) i.next(), update );
234             }
235 
236             update.writeRepositoryXml();
237 
238             if ( downloadedRepositoryXml.exists() )
239             {
240                 // ======== UPLOAD MODIFIED OBR ========
241                 log.info( "Uploading " + repositoryName );
242                 remoteFile.put( downloadedRepositoryXml, repositoryName );
243             }
244         }
245         catch ( Exception e )
246         {
247             log.warn( "Exception while updating remote OBR: " + e.getLocalizedMessage(), e );
248         }
249         finally
250         {
251             // ======== UNLOCK REMOTE OBR ========
252             log.info( "UNLOCK " + remoteFile + '/' + repositoryName );
253             remoteFile.unlockFile( repositoryName );
254             remoteFile.disconnect();
255 
256             if ( null != downloadedRepositoryXml )
257             {
258                 downloadedRepositoryXml.delete();
259             }
260         }
261     }
262 
263     private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
264 
265 
266     private void openRepositoryConnection( RemoteFileManager remoteFile ) throws MojoExecutionException
267     {
268         // use OBR specific deployment location?
269         if ( obrDeploymentRepository != null )
270         {
271             altDeploymentRepository = obrDeploymentRepository;
272         }
273 
274         if ( deploymentRepository == null && altDeploymentRepository == null )
275         {
276             String msg = "Deployment failed: repository element was not specified in the pom inside"
277                 + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
278 
279             throw new MojoExecutionException( msg );
280         }
281 
282         if ( altDeploymentRepository != null )
283         {
284             getLog().info( "Using alternate deployment repository " + altDeploymentRepository );
285 
286             Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepository );
287             if ( !matcher.matches() )
288             {
289                 throw new MojoExecutionException( "Invalid syntax for alternative repository \""
290                     + altDeploymentRepository + "\". Use \"id::layout::url\"." );
291             }
292 
293             remoteFile.connect( matcher.group( 1 ).trim(), matcher.group( 3 ).trim() );
294         }
295         else
296         {
297             remoteFile.connect( deploymentRepository.getId(), deploymentRepository.getUrl() );
298         }
299     }
300 
301 
302     private void updateRemoteBundleMetadata( Artifact artifact, ObrUpdate update ) throws MojoExecutionException
303     {
304         if ( !supportedProjectTypes.contains( artifact.getType() ) )
305         {
306             return;
307         }
308         else if ( null == artifact.getFile() || artifact.getFile().isDirectory() )
309         {
310             getLog().error( "No artifact found, try \"mvn install bundle:deploy\"" );
311             return;
312         }
313 
314         URI bundleJar = ObrUtils.getArtifactURI( localRepository, artifact );
315 
316         URI sourceJar = null;
317         if ( null != m_sourceArtifact )
318         {
319             sourceJar = ObrUtils.getArtifactURI( localRepository, m_sourceArtifact );
320         }
321 
322         URI docJar = null;
323         if ( null != m_docArtifact )
324         {
325             docJar = ObrUtils.getArtifactURI( localRepository, m_docArtifact );
326         }
327 
328         update.updateRepository( bundleJar, sourceJar, docJar );
329     }
330 }