1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.mojo.nbm;
18
19 import java.io.*;
20 import java.lang.reflect.Field;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Hashtable;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Properties;
30 import java.util.jar.Attributes;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarInputStream;
33 import java.util.jar.JarOutputStream;
34 import java.util.jar.Manifest;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
37 import org.apache.maven.artifact.Artifact;
38 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
39
40 import org.apache.maven.execution.MavenSession;
41 import org.apache.maven.model.Resource;
42 import org.apache.maven.plugin.MojoExecutionException;
43 import org.apache.maven.plugin.MojoFailureException;
44 import org.apache.maven.plugins.annotations.Component;
45 import org.apache.maven.plugins.annotations.Parameter;
46 import org.apache.maven.shared.filtering.MavenFilteringException;
47 import org.codehaus.mojo.nbm.model.NbmResource;
48 import org.apache.maven.project.MavenProject;
49 import org.apache.maven.shared.filtering.MavenResourcesExecution;
50 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
51 import org.apache.tools.ant.BuildException;
52 import org.apache.tools.ant.Project;
53 import org.apache.tools.ant.taskdefs.Copy;
54 import org.apache.tools.ant.taskdefs.Jar;
55 import org.apache.tools.ant.types.FileSet;
56 import org.apache.tools.ant.types.Path;
57 import org.apache.tools.ant.types.PatternSet;
58 import org.apache.tools.ant.util.FileUtils;
59 import org.netbeans.nbbuild.CreateModuleXML;
60 import org.netbeans.nbbuild.MakeListOfNBM;
61 import org.codehaus.mojo.nbm.model.NetBeansModule;
62 import org.codehaus.mojo.nbm.utils.ExamineManifest;
63 import org.codehaus.plexus.util.ReaderFactory;
64 import org.codehaus.plexus.util.StringUtils;
65 import org.netbeans.nbbuild.JHIndexer;
66
67
68
69
70
71
72
73
74 public abstract class CreateNetBeansFileStructure
75 extends AbstractNbmMojo
76 {
77
78
79
80
81
82 @Parameter(defaultValue="${project.build.directory}/nbm", property="maven.nbm.buildDir")
83 protected File nbmBuildDir;
84
85
86
87 @Parameter(required=true, readonly=true, property="project.build.directory")
88 protected File buildDir;
89
90
91
92 @Parameter(alias="jarname", property="project.build.finalName")
93 protected String finalName;
94
95
96
97
98 @Parameter(defaultValue="${basedir}/src/main/nbm/module.xml")
99 protected File descriptor;
100
101
102
103
104 @Parameter(required=true, defaultValue="extra")
105 protected String cluster;
106
107
108
109
110
111
112
113
114 @Deprecated
115 @Parameter(defaultValue="${basedir}/src/main/javahelp")
116 protected File nbmJavahelpSource;
117
118 @Parameter(required=true, readonly=true, property="project")
119 protected MavenProject project;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140 @Parameter
141 protected Resource[] nbmResources;
142
143
144
145
146
147
148 @Parameter(property="encoding", defaultValue="${project.build.sourceEncoding}")
149
150 protected String encoding;
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 @Parameter(defaultValue="normal")
177 protected String moduleType;
178
179
180
181
182
183
184
185 @Parameter(defaultValue="${project.groupId}.${project.artifactId}")
186 private String codeNameBase;
187
188
189
190
191
192
193
194
195
196 @Parameter
197 private List<String> externals;
198
199
200 @Component
201 protected MavenResourcesFiltering mavenResourcesFiltering;
202
203 @Parameter(property="session", readonly=true, required=true)
204 protected MavenSession session;
205
206
207
208 protected Project antProject;
209 protected NetBeansModule module;
210 protected File clusterDir;
211 protected String moduleJarName;
212
213 public void execute()
214 throws MojoExecutionException, MojoFailureException
215 {
216 antProject = registerNbmAntTasks();
217 if ( descriptor != null && descriptor.exists() )
218 {
219 module = readModuleDescriptor( descriptor );
220 } else
221 {
222 module = createDefaultDescriptor( project, false );
223 }
224
225 String type = moduleType;
226 if ("normal".equals(type) && module.getModuleType() != null) {
227 type = module.getModuleType();
228 getLog().warn( "moduleType in module descriptor is deprecated, use the plugin's parameter moduleType");
229 }
230 if (!"normal".equals(type) && !"autoload".equals(type) && !"eager".equals(type) && !"disabled".equals(type)) {
231 getLog().error( "Only 'normal,autoload,eager,disabled' are allowed values in the moduleType parameter");
232 }
233 boolean autoload = "autoload".equals( type );
234 boolean eager = "eager".equals( type );
235 boolean disabled = "disabled".equals( type );
236
237 String moduleName = codeNameBase;
238 if (module.getCodeNameBase() != null) {
239 moduleName = module.getCodeNameBase();
240 getLog().warn( "codeNameBase in module descriptor is deprecated, use the plugin's parameter codeNameBase");
241 }
242 moduleName = NetBeansManifestUpdateMojo.stripVersionFromCodebaseName( moduleName.replaceAll( "-", "." ) );
243 moduleJarName = moduleName.replace( '.', '-' );
244 if ( "extra".equals( cluster ) && module.getCluster() != null )
245 {
246 getLog().warn(
247 "Parameter cluster in module descriptor is deprecated, use the plugin configuration element." );
248 cluster = module.getCluster();
249 }
250 File jarFile = new File( buildDir, finalName + ".jar" );
251 clusterDir = new File( nbmBuildDir, "netbeans" + File.separator + cluster );
252 File moduleJarLocation = new File( clusterDir, "modules" );
253 moduleJarLocation.mkdirs();
254
255
256 File moduleFile = new File( moduleJarLocation, moduleJarName + ".jar" );
257
258 try
259 {
260 boolean needPlainCopy = false;
261 InputStream is = new FileInputStream( jarFile );
262 try
263 {
264 JarInputStream jis = new JarInputStream( is );
265 Manifest m = jis.getManifest();
266 Attributes a = m.getMainAttributes();
267 String classPath = ( String ) a.remove( new Attributes.Name( "X-Class-Path" ) );
268 if ( classPath == null )
269 {
270 needPlainCopy = true;
271 }
272 else
273 {
274 getLog().info( "Copying module JAR to " + moduleJarLocation + " with manifest updates" );
275 a.putValue( "Class-Path", classPath );
276 a.remove( new Attributes.Name( "Maven-Class-Path" ) );
277 OutputStream os = new FileOutputStream( moduleFile );
278 try
279 {
280 JarOutputStream jos = new JarOutputStream( os, m );
281 JarEntry entry;
282 while ( ( entry = jis.getNextJarEntry() ) != null )
283 {
284 JarEntry entry2 = new JarEntry( entry );
285 jos.putNextEntry( entry2 );
286 int c;
287 while ( ( c = jis.read() ) != -1 )
288 {
289 jos.write( c );
290 }
291 jos.closeEntry();
292 }
293 jos.finish();
294 jos.close();
295 }
296 finally
297 {
298 os.close();
299 }
300 }
301 }
302 finally
303 {
304 is.close();
305 }
306 if ( needPlainCopy )
307 {
308 getLog().info( "Copying module JAR to " + moduleJarLocation );
309 FileUtils.getFileUtils().copyFile( jarFile, moduleFile, null, true, false );
310 }
311 }
312 catch ( IOException x )
313 {
314 throw new MojoExecutionException( "Cannot copy module jar", x );
315 }
316
317 ExamineManifest modExaminator = new ExamineManifest( getLog() );
318 modExaminator.setJarFile( moduleFile );
319 modExaminator.checkFile();
320 String classpathValue = modExaminator.getClasspath();
321
322 if ( module != null )
323 {
324
325 @SuppressWarnings("unchecked")
326 List<Artifact> artifacts = project.getRuntimeArtifacts();
327 for ( Artifact artifact : artifacts )
328 {
329 File source = artifact.getFile();
330
331 String path = NetBeansManifestUpdateMojo.artifactToClassPathEntry( artifact, codeNameBase );
332
333 if ( classpathValue.contains( path ) )
334 {
335 File target = new File( moduleJarLocation, path );
336
337 File targetDir = target.getParentFile();
338 targetDir.mkdirs();
339
340 try
341 {
342 FileUtils.getFileUtils().copyFile( source, target, null, true, false );
343 if ( externals != null && externals.contains(artifact.getGroupId() + ":" + artifact.getArtifactId()))
344 {
345 String name = target.getName();
346 getLog().info( "Using *.external replacement for " + name );
347 PrintWriter external = new PrintWriter( new File( targetDir, name + ".external" ), "UTF-8" );
348 try
349 {
350 writeExternal( external, artifact );
351 }
352 finally
353 {
354 external.close();
355 }
356 }
357 }
358 catch ( IOException ex )
359 {
360 getLog().error( "Cannot copy library jar" );
361 throw new MojoExecutionException( "Cannot copy library jar", ex );
362 }
363 }
364 }
365 if ( nbmResources != null )
366 {
367 copyNbmResources();
368 }
369 copyDeprecatedNbmResources();
370 }
371
372
373 if ( nbmJavahelpSource.exists() )
374 {
375 getLog().warn( "src/main/javahelp/ deprecated; use @HelpSetRegistration instead" );
376 File javahelp_target = new File( buildDir, "javahelp" );
377 String javahelpbase = moduleJarName.replace( '-', File.separatorChar ) + File.separator + "docs";
378 String javahelpSearch = "JavaHelpSearch";
379 File b = new File( javahelp_target, javahelpbase );
380 File p = new File( b, javahelpSearch );
381 p.mkdirs();
382 Copy cp = (Copy) antProject.createTask( "copy" );
383 cp.setTodir( javahelp_target );
384 FileSet set = new FileSet();
385 set.setDir( nbmJavahelpSource );
386 cp.addFileset( set );
387 cp.execute();
388 getLog().info( "Generating JavaHelp Index..." );
389
390 JHIndexer jhTask = (JHIndexer) antProject.createTask( "jhindexer" );
391 jhTask.setBasedir( b );
392 jhTask.setDb( p );
393 jhTask.setIncludes( "**/*.html" );
394 jhTask.setExcludes( javahelpSearch );
395 Path path = new Path( antProject );
396 jhTask.setClassPath( path );
397 clearStaticFieldsInJavaHelpIndexer();
398 try
399 {
400 jhTask.execute();
401 }
402 catch ( BuildException e )
403 {
404 getLog().error( "Cannot generate JavaHelp index." );
405 throw new MojoExecutionException( e.getMessage(), e );
406 }
407 File helpJarLocation = new File( clusterDir, "modules/docs" );
408 helpJarLocation.mkdirs();
409 Jar jar = (Jar) antProject.createTask( "jar" );
410 jar.setDestFile( new File( helpJarLocation, moduleJarName + ".jar" ) );
411 set = new FileSet();
412 set.setDir( javahelp_target );
413 jar.addFileset( set );
414 jar.execute();
415 }
416
417 File configDir = new File( clusterDir, "config" + File.separator + "Modules" );
418 configDir.mkdirs();
419 CreateModuleXML moduleXmlTask = (CreateModuleXML) antProject.createTask( "createmodulexml" );
420 moduleXmlTask.setXmldir( configDir );
421 FileSet fs = new FileSet();
422 fs.setDir( clusterDir );
423 fs.setIncludes( "modules" + File.separator + moduleJarName + ".jar" );
424 if ( autoload )
425 {
426 moduleXmlTask.addAutoload( fs );
427 }
428 else if ( eager )
429 {
430 moduleXmlTask.addEager( fs );
431 }
432 else if ( disabled )
433 {
434 moduleXmlTask.addDisabled( fs );
435 }
436 else
437 {
438 moduleXmlTask.addEnabled( fs );
439 }
440 try
441 {
442 moduleXmlTask.execute();
443 }
444 catch ( BuildException e )
445 {
446 getLog().error( "Cannot generate config file." );
447 throw new MojoExecutionException( e.getMessage(), e );
448 }
449 MakeListOfNBM makeTask = (MakeListOfNBM) antProject.createTask( "genlist" );
450 antProject.setNewProperty( "module.name", finalName );
451 antProject.setProperty( "cluster.dir", cluster );
452 FileSet set = makeTask.createFileSet();
453 set.setDir( clusterDir );
454 PatternSet pattern = set.createPatternSet();
455 pattern.setIncludes( "**" );
456 makeTask.setModule( "modules" + File.separator + moduleJarName + ".jar" );
457 makeTask.setOutputfiledir( clusterDir );
458 try
459 {
460 makeTask.execute();
461 }
462 catch ( BuildException e )
463 {
464 getLog().error( "Cannot Generate nbm list" );
465 throw new MojoExecutionException( e.getMessage(), e );
466 }
467
468 }
469
470 private void copyDeprecatedNbmResources()
471 throws BuildException, MojoExecutionException
472 {
473
474 List<NbmResource> ress = module.getNbmResources();
475 if ( ress.size() > 0 )
476 {
477 getLog().warn( "NBM resources defined in module descriptor are deprecated. Please configure NBM resources in plugin configuration." );
478 Copy cp = (Copy) antProject.createTask( "copy" );
479 cp.setTodir( clusterDir );
480 HashMap<File, Collection<FileSet>> customPaths = new HashMap<File, Collection<FileSet>>();
481 boolean hasStandard = false;
482 for ( NbmResource res : ress )
483 {
484 if ( res.getBaseDirectory() != null )
485 {
486 File base = new File( project.getBasedir(), res.getBaseDirectory() );
487 FileSet set = new FileSet();
488 set.setDir( base );
489 for ( String inc : res.getIncludes() )
490 {
491 set.createInclude().setName( inc );
492 }
493 for ( String exc : res.getExcludes() )
494 {
495 set.createExclude().setName( exc );
496 }
497
498 if ( res.getRelativeClusterPath() != null )
499 {
500 File path = new File( clusterDir, res.getRelativeClusterPath() );
501 Collection<FileSet> col = customPaths.get( path );
502 if ( col == null )
503 {
504 col = new ArrayList<FileSet>();
505 customPaths.put( path, col );
506 }
507 col.add( set );
508 }
509 else
510 {
511 cp.addFileset( set );
512 hasStandard = true;
513 }
514 }
515 }
516 try
517 {
518 if ( hasStandard )
519 {
520 cp.execute();
521 }
522 if ( customPaths.size() > 0 )
523 {
524 for ( Map.Entry<File, Collection<FileSet>> ent : customPaths.entrySet() )
525 {
526 cp = (Copy) antProject.createTask( "copy" );
527 cp.setTodir( ent.getKey() );
528 for ( FileSet set : ent.getValue() )
529 {
530 cp.addFileset( set );
531 }
532 cp.execute();
533 }
534 }
535 }
536 catch ( BuildException e )
537 {
538 getLog().error( "Cannot copy additional resources into the nbm file" );
539 throw new MojoExecutionException( e.getMessage(), e );
540 }
541 }
542 }
543
544
545
546
547
548
549 private void clearStaticFieldsInJavaHelpIndexer()
550 {
551 try
552 {
553 Class clazz = Class.forName( "com.sun.java.help.search.Indexer" );
554 Field fld = clazz.getDeclaredField( "kitRegistry" );
555 fld.setAccessible( true );
556 Hashtable hash = (Hashtable) fld.get( null );
557 hash.clear();
558
559 clazz = Class.forName( "com.sun.java.help.search.HTMLIndexerKit" );
560 fld = clazz.getDeclaredField( "defaultParser" );
561 fld.setAccessible( true );
562 fld.set( null, null);
563
564 fld = clazz.getDeclaredField( "defaultCallback" );
565 fld.setAccessible( true );
566 fld.set( null, null);
567
568 }
569 catch ( IllegalArgumentException ex )
570 {
571 Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
572 }
573 catch ( IllegalAccessException ex )
574 {
575 Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
576 }
577 catch ( NoSuchFieldException ex )
578 {
579 Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
580 }
581 catch ( SecurityException ex )
582 {
583 Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
584 }
585 catch ( ClassNotFoundException ex )
586 {
587 Logger.getLogger( CreateNetBeansFileStructure.class.getName() ).log( Level.SEVERE, null, ex );
588 }
589 }
590
591 private void copyNbmResources()
592 throws MojoExecutionException
593 {
594 try
595 {
596 if ( StringUtils.isEmpty( encoding ) && isFilteringEnabled( nbmResources ) )
597 {
598 getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
599 + ", i.e. build is platform dependent!" );
600 }
601 MavenResourcesExecution mavenResourcesExecution =
602 new MavenResourcesExecution( Arrays.asList( nbmResources ), clusterDir, project, encoding,
603 Collections.EMPTY_LIST, Collections.EMPTY_LIST, session );
604 mavenResourcesExecution.setEscapeWindowsPaths( true );
605 mavenResourcesFiltering.filterResources( mavenResourcesExecution );
606 }
607 catch ( MavenFilteringException ex )
608 {
609 throw new MojoExecutionException( ex.getMessage(), ex );
610 }
611 }
612
613
614
615
616
617
618
619 private boolean isFilteringEnabled( Resource[] resources )
620 {
621 for ( Resource resource : resources )
622 {
623 if ( resource.isFiltering() )
624 {
625 return true;
626 }
627 }
628 return false;
629 }
630
631 static void writeExternal( PrintWriter w, Artifact artifact )
632 throws IOException
633 {
634 w.write( "CRC:" );
635 File file = artifact.getFile();
636 w.write( Long.toString( CreateClusterAppMojo.crcForFile( file ).getValue() ) );
637 w.write( "\nSIZE:" );
638 w.write( Long.toString( file.length() ) );
639 w.write( "\nURL:m2:/" );
640 w.write( artifact.getGroupId() );
641 w.write( ':' );
642 w.write( artifact.getArtifactId() );
643 w.write( ':' );
644 w.write( artifact.getVersion() );
645 w.write( ':' );
646 w.write( artifact.getType() );
647 if ( artifact.getClassifier() != null )
648 {
649 w.write( ':' );
650 w.write( artifact.getClassifier() );
651 }
652 w.write( "\nURL:" );
653
654 w.write(
655 w.write( new DefaultRepositoryLayout().pathOf( artifact ) );
656 w.write( '\n' );
657 w.flush();
658 }
659
660 }