View Javadoc

1   /* ==========================================================================
2    * Copyright 2003-2004 Mevenide Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   * =========================================================================
16   */
17  package org.codehaus.mojo.nbm;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.text.SimpleDateFormat;
22  import java.util.Calendar;
23  import java.util.Date;
24  import java.util.Iterator;
25  import java.util.List;
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.factory.ArtifactFactory;
28  import org.apache.maven.artifact.repository.ArtifactRepository;
29  import org.apache.maven.model.Developer;
30  import org.apache.maven.model.License;
31  import org.apache.maven.model.Organization;
32  import org.apache.maven.plugin.MojoExecutionException;
33  import org.apache.maven.plugin.MojoFailureException;
34  import org.apache.maven.plugins.annotations.Component;
35  import org.apache.maven.plugins.annotations.LifecyclePhase;
36  import org.apache.maven.plugins.annotations.Mojo;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.plugins.annotations.ResolutionScope;
39  import org.apache.maven.project.MavenProjectHelper;
40  import org.apache.tools.ant.BuildException;
41  import org.apache.tools.ant.util.FileUtils;
42  import org.codehaus.plexus.PlexusConstants;
43  import org.codehaus.plexus.PlexusContainer;
44  import org.codehaus.plexus.context.Context;
45  import org.codehaus.plexus.context.ContextException;
46  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
47  import org.netbeans.nbbuild.MakeNBM;
48  import org.netbeans.nbbuild.MakeNBM.Blurb;
49  import org.netbeans.nbbuild.MakeNBM.Signature;
50  
51  /**
52   * Create the NetBeans module artifact (nbm file), part of "nbm" lifecycle/packaging.
53   * <p/>
54   *
55   * @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
56   */
57  @Mojo(name="nbm", 
58          requiresProject=true, 
59          threadSafe = true,
60          requiresDependencyResolution= ResolutionScope.RUNTIME, 
61          defaultPhase= LifecyclePhase.PACKAGE )
62  public class CreateNbmMojo
63          extends CreateNetBeansFileStructure
64          implements Contextualizable
65  {
66  
67      /**
68       * keystore location for signing the nbm file
69       */
70      @Parameter(property="keystore")
71      private String keystore;
72      /**
73       * keystore password
74       */
75      @Parameter(property="keystorepass")
76      private String keystorepassword;
77      /**
78       * keystore alias
79       */
80      @Parameter(property="keystorealias")
81      private String keystorealias;
82  
83      /**
84       * Boolean parameter denoting if creation of NBM file shall be skipped or not.
85       * If skipped, just the expanded directory for cluster is created
86       * @since 3.0
87       */
88      @Parameter(defaultValue="false", property="maven.nbm.skip")
89      private boolean skipNbm;
90      
91      /**
92       * if true, upon installing the NBM the platform app/IDE restart is requested. Not necessary in most cases.
93       * @since 3.8
94       */
95      @Parameter(defaultValue="false")
96      private boolean requiresRestart;
97      
98      /**
99       * Get homepage URL of the module. Is accessible from NetBeans
100      * UI upon installation, should point to place with additional
101      * information about the functionality. 
102      * @since 3.8
103      */
104     @Parameter(defaultValue="${project.url}")
105     private String homePageUrl;
106     
107     /**
108      * Author of the module. Shown in the Module manager UI.
109      * @since 3.8
110      */
111     @Parameter(defaultValue="${project.organization.name}")
112     private String author;
113     
114     /**
115      * Distribution base URL for the NBM at runtime deployment time.
116      * Note: Usefulness of the parameter is questionable, it doesn't allow for mirrors and
117      * usually when downloading the nbm, one already knows the location anyway.
118      * Please note that the netbeans.org Ant scripts put a dummy url here.
119      * The actual correct value used when constructing update site is
120      * explicitly set there. The general assumption there is that all modules from one update
121      * center come from one base URL. Also see <code>distBase</code> parameter in auto-update mojo.
122      * <p/>
123      * The value is either a direct http protocol based URL that points to
124      * the location under which nbm file will be located, or
125      * <p/>
126      * it allows to create an update site based on maven repository content.
127      * The later created autoupdate site document can use this information and
128      * compose the application from one or multiple maven repositories.
129      * <br/>
130      * Format: id::layout::url same as in maven-deploy-plugin
131      * <br/>
132      * with the 'default' and 'legacy' layouts. (maven2 vs maven1 layout)
133      * <br/>
134      * If the value doesn't contain :: characters,
135      * it's assumed to be the flat structure and the value is just the URL.
136      * 
137      */
138     @Parameter(property="maven.nbm.distributionURL")
139     private String distributionUrl;
140     
141     /**
142      * name of the license applicable to the NBM. The value should be equal across modules with the same license. If the user already agreed to the
143      * same license before, he/she won't be asked again to agree and for multiple one installed at the same time, just one license agreement is shown.
144      * When defined, <code>licenseFile</code> needs to be defined as well.
145      * @since 3.8
146      */
147     @Parameter
148     private String licenseName;
149     
150     /**
151      * path to the license agreement file that will be shown when installing the module. When defined, <code>licenseName</code> needs to be defined as well.
152      * @since 3.8
153      */
154     @Parameter
155     private File licenseFile;
156     
157 
158     // <editor-fold defaultstate="collapsed" desc="Component parameters">
159 
160     /**
161      * Contextualized.
162      */
163     private PlexusContainer container;
164 
165     @Component
166     private ArtifactFactory artifactFactory;
167     /**
168      * Used for attaching the artifact in the project
169      */
170     @Component
171     private MavenProjectHelper projectHelper;
172 
173     // end of component params custom code folding
174     // </editor-fold>
175     
176     private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat ("yyyy/MM/dd");
177 
178     public void execute()
179         throws MojoExecutionException, MojoFailureException
180     {
181         if ( skipNbm )
182         {
183             getLog().info( "Skipping generation of NBM file." );
184             return;
185         }
186 
187         if ( "pom".equals( project.getPackaging() ) )
188         {
189             getLog().info(
190                     "Skipping " + project.getId() + ", no nbm:nbm execution for 'pom' packaging" );
191             return;
192         }
193         super.execute();
194 
195 
196         // 3. generate nbm
197         File nbmFile = new File( nbmBuildDir, finalName + ".nbm" );
198         MakeNBM nbmTask = (MakeNBM) antProject.createTask( "makenbm" );
199         nbmTask.setFile( nbmFile );
200         nbmTask.setProductDir( clusterDir );
201 
202         nbmTask.setModule( "modules" + File.separator + moduleJarName + ".jar" );
203         boolean reqRestart = requiresRestart;
204         if (!reqRestart && module.isRequiresRestart()) {
205             reqRestart = module.isRequiresRestart();
206             getLog().warn( "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
207         }
208         nbmTask.setNeedsrestart( Boolean.toString( reqRestart ) );
209         String moduleAuthor = author;
210         if (module.getAuthor() != null) {
211             moduleAuthor = module.getAuthor();
212             getLog().warn( "Module descriptor's requiresRestart field is deprecated, use plugin's configuration in pom.xml");
213         }
214         nbmTask.setModuleauthor( moduleAuthor );
215         if ( keystore != null && keystorealias != null && keystorepassword != null )
216         {
217             File ks = new File( keystore );
218             if ( !ks.exists() )
219             {
220                 getLog().warn( "Cannot find keystore file at " + ks.getAbsolutePath() );
221             }
222             else
223             {
224                 Signature sig = nbmTask.createSignature();
225                 sig.setKeystore( ks );
226                 sig.setAlias( keystorealias );
227                 sig.setStorepass( keystorepassword );
228                 getLog().debug( "Setup the Ant task to sign the NBM file." );
229             }
230         }
231         else if ( keystore != null || keystorepassword != null || keystorealias != null )
232         {
233             getLog().warn(
234                     "If you want to sign the nbm file, you need to define all three keystore related parameters." );
235         }
236         String licName = licenseName;
237         File licFile = licenseFile;
238         if (module.getLicenseName() != null) {
239             licName = module.getLicenseName();
240             getLog().warn( "Module descriptor's licenseName field is deprecated, use plugin's configuration in pom.xml");
241         }
242         if (module.getLicenseFile() != null) {
243             File lf = new File( project.getBasedir(), module.getLicenseFile() );
244             licFile = lf;
245             getLog().warn( "Module descriptor's licenseFile field is deprecated, use plugin's configuration in pom.xml");
246             
247         }
248         if ( licName != null && licFile != null )
249         {
250             if ( !licFile.exists() || !licFile.isFile() )
251             {
252                 getLog().warn( "Cannot find license file at " + licFile.getAbsolutePath() );
253             }
254             else
255             {
256                 Blurb lb = nbmTask.createLicense();
257                 lb.setFile( licFile );
258                 lb.addText( licName );
259             }
260         }
261         else if ( licName != null || licFile != null )
262         {
263             getLog().warn(
264                     "To set license for the nbm, you need to specify both licenseName and licenseFile parameters." );
265         }
266         else
267         {
268             Blurb lb = nbmTask.createLicense();
269             lb.addText( createDefaultLicenseHeader() );
270             lb.addText( createDefaultLicenseText() );
271         }
272         String hpUrl = homePageUrl;
273         if (module.getHomepageUrl() != null) {
274             getLog().warn( "Module descriptor's homePageUrl field is deprecated, use plugin's configuration in pom.xml");
275             hpUrl = module.getHomepageUrl();
276         }
277         if ( hpUrl != null )
278         {
279             nbmTask.setHomepage( hpUrl );
280         }
281         String distribUrl = distributionUrl;
282         if (module.getDistributionUrl() != null) {
283             distribUrl = module.getDistributionUrl();
284             getLog().warn( "Module descriptor's distributionUrl field is deprecated, use plugin's configuration in pom.xml");
285         }
286         if ( distribUrl != null )
287         {
288             ArtifactRepository distRepository = CreateUpdateSiteMojo.getDeploymentRepository(
289                     distribUrl, container, getLog() );
290             String dist = null;
291             if ( distRepository == null )
292             {
293                 if ( !distribUrl.contains( "::" ) )
294                 {
295                     dist =
296                         distribUrl + ( distribUrl.endsWith( "/" ) ? "" : "/" )
297                             + nbmFile.getName();
298                 }
299             }
300             else
301             {
302                 Artifact art = artifactFactory.createArtifact(
303                         project.getGroupId(), project.getArtifactId(),
304                         project.getVersion(), null, "nbm-file" );
305 
306                 dist =
307                     distRepository.getUrl() + ( distRepository.getUrl().endsWith( "/" ) ? "" : "/" )
308                         + distRepository.pathOf( art );
309 
310             }
311             nbmTask.setDistribution( dist );
312         }
313         else
314         {
315             nbmTask.setDistribution( nbmFile.getName() );
316         }
317         if ( ! "extra".equals( cluster ) )
318         {
319             nbmTask.setTargetcluster( cluster );
320         }
321         //MNBMODULE-217 avoid using the static DATE_FORMAT variable in MavenNBM.java (in ant harness)
322         nbmTask.setReleasedate( DATE_FORMAT.format(new Date(System.currentTimeMillis())) );
323         try
324         {
325             nbmTask.execute();
326         }
327         catch ( BuildException e )
328         {
329             throw new MojoExecutionException( "Cannot Generate nbm file:" + e.getMessage(), e );
330         }
331         try
332         {
333             File nbmfile = new File( buildDir, nbmFile.getName() );
334             FileUtils.getFileUtils().copyFile( nbmFile, nbmfile );
335             projectHelper.attachArtifact( project, "nbm-file", null, nbmfile );
336         }
337         catch ( IOException ex )
338         {
339             throw new MojoExecutionException( "Cannot copy nbm to build directory", ex );
340         }
341     }
342 
343     public void contextualize( Context context )
344             throws ContextException
345     {
346         this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
347     }
348 
349     private String createDefaultLicenseHeader()
350     {
351         String organization = "";
352         Organization org = project.getOrganization();
353         if (org != null) {
354             organization = org.getName();
355 }
356         if (organization == null) {
357             List devs = project.getDevelopers();
358             if (devs.size() > 0) {
359                 Iterator dvs = devs.iterator();
360                 String devsString = "";
361                 while (dvs.hasNext()) {
362                     Developer d = ( Developer )dvs.next();
363                     devsString = devsString + "," + d.getName() != null ? d.getName() : d.getId();
364                 }
365                 organization = devsString.substring( 1 );    
366             }
367         }
368         if (organization == null) {
369             organization = ""; //what's a good default value?
370         }
371         String date = "";
372         if (project.getInceptionYear() != null) {
373             date = project.getInceptionYear();
374         }
375         String year = Integer.toString( Calendar.getInstance().get( Calendar.YEAR ));
376         if (!year.equals( date ) ) {
377             date = date.length() == 0 ? year : date + "-" + year;
378         }
379         return "Copyright " + organization + " " + date;
380     }
381     
382     private String createDefaultLicenseText() {
383         String toRet = "License terms:\n";
384         
385         List licenses = project.getLicenses();
386         if (licenses != null && licenses.size() > 0) {
387             Iterator lic = licenses.iterator();
388             while (lic.hasNext()) {
389                 License ll = ( License )lic.next();
390                 
391                 if (ll.getName() != null) {
392                    toRet = toRet + ll.getName() + " - "; 
393                 }
394                 if (ll.getUrl() != null) {
395                     toRet = toRet + ll.getUrl();
396                 }
397                 if (lic.hasNext()) {
398                     toRet = toRet + ",\n";
399                 }
400             }
401         } else {
402            toRet = toRet + "Unknown";
403         }
404         return toRet;
405     }
406 }