1 package org.apache.maven.plugin.doap;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.Writer;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.text.DateFormat;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30 import java.util.Collections;
31 import java.util.Comparator;
32 import java.util.Date;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.TimeZone;
37
38 import org.apache.maven.artifact.Artifact;
39 import org.apache.maven.artifact.factory.ArtifactFactory;
40 import org.apache.maven.artifact.repository.ArtifactRepository;
41 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
42 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
43 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
44 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
45 import org.apache.maven.model.Contributor;
46 import org.apache.maven.model.Developer;
47 import org.apache.maven.model.License;
48 import org.apache.maven.model.MailingList;
49 import org.apache.maven.model.Scm;
50 import org.apache.maven.plugin.AbstractMojo;
51 import org.apache.maven.plugin.MojoExecutionException;
52 import org.apache.maven.plugin.doap.options.ASFExtOptions;
53 import org.apache.maven.plugin.doap.options.DoapOptions;
54 import org.apache.maven.plugin.doap.options.Standard;
55 import org.apache.maven.project.MavenProject;
56 import org.apache.maven.scm.manager.NoSuchScmProviderException;
57 import org.apache.maven.scm.manager.ScmManager;
58 import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
59 import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
60 import org.apache.maven.scm.repository.ScmRepository;
61 import org.apache.maven.scm.repository.ScmRepositoryException;
62 import org.codehaus.plexus.i18n.I18N;
63 import org.codehaus.plexus.util.FileUtils;
64 import org.codehaus.plexus.util.StringUtils;
65 import org.codehaus.plexus.util.WriterFactory;
66 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
67 import org.codehaus.plexus.util.xml.XMLWriter;
68 import org.codehaus.plexus.util.xml.XmlWriterUtil;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public class DoapMojo
84 extends AbstractMojo
85 {
86
87 private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
88
89
90 private static final DateFormat REPOSITORY_DATE_FORMAT;
91
92
93 private static final DateFormat DOAP_DATE_FORMAT;
94
95 static
96 {
97 REPOSITORY_DATE_FORMAT = new SimpleDateFormat( "yyyyMMddHHmmss", Locale.ENGLISH );
98 REPOSITORY_DATE_FORMAT.setTimeZone( UTC_TIME_ZONE );
99
100 DOAP_DATE_FORMAT = new SimpleDateFormat( "yyyy-MM-dd", Locale.ENGLISH );
101 DOAP_DATE_FORMAT.setTimeZone( UTC_TIME_ZONE );
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116 private ScmManager scmManager;
117
118
119
120
121
122
123
124 private ArtifactFactory artifactFactory;
125
126
127
128
129
130
131
132 private RepositoryMetadataManager repositoryMetadataManager;
133
134
135
136
137
138
139
140 private I18N i18n;
141
142
143
144
145
146
147
148
149
150
151
152 private MavenProject project;
153
154
155
156
157
158
159
160
161 private File doapFile;
162
163
164
165
166
167
168
169
170
171 private ArtifactRepository localRepository;
172
173
174
175
176
177
178
179
180
181 private List remoteRepositories;
182
183
184
185
186
187
188
189
190
191
192
193
194 private String category;
195
196
197
198
199
200
201
202
203 private String language;
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222 private DoapOptions doapOptions;
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 private ASFExtOptions asfExtOptions;
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 private String lang;
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 private String about;
286
287
288
289
290
291
292 public void execute()
293 throws MojoExecutionException
294 {
295
296
297
298
299 Writer w;
300 try
301 {
302 if ( !doapFile.getParentFile().exists() )
303 {
304 FileUtils.mkdir( doapFile.getParentFile().getAbsolutePath() );
305 }
306
307 w = WriterFactory.newXmlWriter( doapFile );
308 }
309 catch ( IOException e )
310 {
311 throw new MojoExecutionException( "Error creating DOAP file.", e );
312 }
313
314 if ( asfExtOptions.isIncluded() )
315 {
316 getLog().info( "Generating an ASF DOAP file..." );
317 }
318 else
319 {
320 getLog().info( "Generating a pure DOAP file..." );
321 }
322
323 XMLWriter writer = new PrettyPrintXMLWriter( w, project.getModel().getModelEncoding(), null );
324
325
326
327
328
329 DoapUtil.writeHeader( writer );
330
331
332 writer.startElement( "rdf:RDF" );
333 writer.addAttribute( "xml:lang", lang );
334 writer.addAttribute( "xmlns", "http://usefulinc.com/ns/doap#" );
335 writer.addAttribute( "xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" );
336 writer.addAttribute( "xmlns:foaf", "http://xmlns.com/foaf/0.1/" );
337 if ( asfExtOptions.isIncluded() )
338 {
339 writer.addAttribute( "xmlns:asfext", ASFExtOptions.ASFEXT_NAMESPACE );
340 }
341
342
343 writer.startElement( "Project" );
344 if ( StringUtils.isNotEmpty( about ) )
345 {
346 writer.addAttribute( "rdf:about", about );
347 }
348 else
349 {
350 getLog().warn( "rdf:about should be required" );
351 }
352
353
354 writeName( writer );
355
356
357 writeDescription( writer );
358
359
360 writeCreated( writer );
361
362
363 writeHomepage( writer );
364
365
366 writeLicenses( writer );
367
368
369 writeProgrammingLanguage( writer );
370
371
372 writeCategory( writer );
373
374
375 writeOS( writer );
376
377
378 writeSourceRepositories( writer );
379
380
381 writeBugDatabase( writer );
382
383
384 writeMailingList( writer );
385
386
387 writeDownloadPage( writer );
388
389
390 writeScreenshots( writer );
391
392
393 writeWiki( writer );
394
395
396 writeReleases( writer );
397
398
399 writeDevelopersOrContributors( writer, project.getDevelopers() );
400
401
402 writeDevelopersOrContributors( writer, project.getContributors() );
403
404
405 if ( asfExtOptions.isIncluded() )
406 {
407 writeASFext( writer );
408 }
409
410 writer.endElement();
411 writer.endElement();
412
413 try
414 {
415 w.close();
416 }
417 catch ( IOException e )
418 {
419 throw new MojoExecutionException( "Error when closing the writer.", e );
420 }
421 }
422
423
424
425
426
427
428
429
430
431
432
433 private void writeName( XMLWriter writer )
434 {
435 if ( StringUtils.isEmpty( project.getName() ) )
436 {
437 return;
438 }
439
440 XmlWriterUtil.writeLineBreak( writer );
441 XmlWriterUtil.writeCommentText( writer, "A name of something.", 2 );
442
443 if ( asfExtOptions.isIncluded()
444 && !project.getName().toLowerCase( Locale.ENGLISH ).trim().startsWith( "apache" ) )
445 {
446 DoapUtil.writeRdfResourceElement( writer, "name", "Apache " + project.getName() );
447 }
448 else
449 {
450 DoapUtil.writeRdfResourceElement( writer, "name", project.getName() );
451 }
452 }
453
454
455
456
457
458
459
460
461 private void writeDescription( XMLWriter writer )
462 {
463 if ( StringUtils.isEmpty( project.getDescription() ) )
464 {
465 return;
466 }
467
468 XmlWriterUtil.writeLineBreak( writer );
469 XmlWriterUtil.writeCommentText( writer, "Plain text description of a project, of 2-4 sentences in length.", 2 );
470 DoapUtil.writeElement( writer, "description", project.getDescription(), lang );
471 if ( StringUtils.isNotEmpty( doapOptions.getShortdesc() ) )
472 {
473 DoapUtil.writeElement( writer, "shortdesc", doapOptions.getShortdesc(), lang );
474 }
475 else
476 {
477 DoapUtil.writeElement( writer, "shortdesc", project.getDescription(), lang );
478 }
479 }
480
481
482
483
484
485
486
487 private void writeCreated( XMLWriter writer )
488 {
489 if ( StringUtils.isEmpty( project.getInceptionYear() ) )
490 {
491 return;
492 }
493
494 XmlWriterUtil.writeLineBreak( writer );
495 XmlWriterUtil.writeCommentText( writer, "Date when something was created, in YYYY-MM-DD form. e.g. 2004-04-05",
496 2 );
497 DoapUtil.writeElement( writer, "created", project.getInceptionYear() + "-01-01" );
498 }
499
500
501
502
503
504
505
506
507 private void writeHomepage( XMLWriter writer )
508 {
509 if ( StringUtils.isNotEmpty( project.getUrl() ) )
510 {
511 XmlWriterUtil.writeLineBreak( writer );
512 XmlWriterUtil.writeCommentText( writer,
513 "URL of a project's homepage, associated with exactly one project.", 2 );
514 DoapUtil.writeRdfResourceElement( writer, "homepage", project.getUrl() );
515 }
516
517 if ( StringUtils.isNotEmpty( doapOptions.getOldHomepage() ) )
518 {
519 XmlWriterUtil.writeLineBreak( writer );
520 XmlWriterUtil.writeCommentText(
521 writer,
522 "URL of a project's past homepage, associated with exactly one project.",
523 2 );
524 DoapUtil.writeRdfResourceElement( writer, "old-homepage", doapOptions.getOldHomepage() );
525 }
526 }
527
528
529
530
531
532
533
534
535 private void writeProgrammingLanguage( XMLWriter writer )
536 {
537 if ( StringUtils.isEmpty( doapOptions.getProgrammingLanguage() ) && StringUtils.isEmpty( language ) )
538 {
539 return;
540 }
541
542 XmlWriterUtil.writeLineBreak( writer );
543 XmlWriterUtil.writeCommentText( writer, "Programming language.", 2 );
544
545 if ( StringUtils.isNotEmpty( language ) )
546 {
547 if ( asfExtOptions.isIncluded() && !ASFExtOptions.isProgrammingLanguageSupportedByASF( language ) )
548 {
549 getLog().warn(
550 "The programming language '" + language + "' is not supported by ASF. "
551 + "Refer you to http://projects.apache.org/languages.html" );
552 }
553
554 DoapUtil.writeRdfResourceElement( writer, "programming-language", language );
555 }
556
557 if ( StringUtils.isNotEmpty( doapOptions.getProgrammingLanguage() ) )
558 {
559 String[] languages = StringUtils.split( doapOptions.getProgrammingLanguage(), "," );
560 for ( int i = 0; i < languages.length; i++ )
561 {
562 if ( asfExtOptions.isIncluded()
563 && !ASFExtOptions.isProgrammingLanguageSupportedByASF( languages[i].trim() ) )
564 {
565 getLog().warn(
566 "The programming language '" + languages[i].trim() + "' is not supported by ASF. "
567 + "Refer you to http://projects.apache.org/languages.html" );
568 }
569
570 DoapUtil.writeRdfResourceElement( writer, "programming-language", languages[i].trim() );
571 }
572 }
573 }
574
575
576
577
578
579
580
581 private void writeCategory( XMLWriter writer )
582 {
583 if ( StringUtils.isEmpty( doapOptions.getCategory() ) && StringUtils.isEmpty( category ) )
584 {
585 return;
586 }
587
588
589 XmlWriterUtil.writeLineBreak( writer );
590 XmlWriterUtil.writeCommentText( writer, "A category of project.", 2 );
591
592 if ( StringUtils.isNotEmpty( category ) )
593 {
594 if ( asfExtOptions.isIncluded() && !ASFExtOptions.isCategorySupportedByASF( category ) )
595 {
596 getLog().warn(
597 "The given category '" + category + "' is not supported by ASF. "
598 + "Refer you to http://projects.apache.org/categories.html" );
599 }
600
601 if ( asfExtOptions.isIncluded() )
602 {
603 DoapUtil
604 .writeRdfResourceElement( writer, "category", "http://projects.apache.org/category/" + category );
605 }
606 else
607 {
608 DoapUtil.writeRdfResourceElement( writer, "category", category );
609 }
610 }
611
612 if ( StringUtils.isNotEmpty( doapOptions.getCategory() ) )
613 {
614 String[] categories = StringUtils.split( doapOptions.getCategory(), "," );
615 for ( int i = 0; i < categories.length; i++ )
616 {
617 if ( asfExtOptions.isIncluded() && !ASFExtOptions.isCategorySupportedByASF( categories[i] ) )
618 {
619 getLog().warn(
620 "The given category '" + categories[i] + "' is not supported by ASF. "
621 + "Refer you to http://projects.apache.org/categories.html" );
622 }
623
624 if ( asfExtOptions.isIncluded() )
625 {
626 DoapUtil.writeRdfResourceElement( writer, "category", "http://projects.apache.org/category/"
627 + categories[i].trim() );
628 }
629 else
630 {
631 DoapUtil.writeRdfResourceElement( writer, "category", categories[i].trim() );
632 }
633 }
634 }
635 }
636
637
638
639
640
641
642
643
644 private void writeDownloadPage( XMLWriter writer )
645 {
646 if ( StringUtils.isEmpty( doapOptions.getDownloadPage() ) )
647 {
648 if ( StringUtils.isNotEmpty( project.getUrl() ) )
649 {
650 doapOptions.setDownloadPage( composeUrl( project.getUrl(), "/download.html" ) );
651 }
652 }
653
654 if ( StringUtils.isNotEmpty( doapOptions.getDownloadPage() ) )
655 {
656 XmlWriterUtil.writeLineBreak( writer );
657 XmlWriterUtil.writeCommentText( writer, "Download page.", 2 );
658 DoapUtil.writeRdfResourceElement( writer, "download-page", doapOptions.getDownloadPage() );
659 }
660
661 if ( StringUtils.isNotEmpty( doapOptions.getDownloadMirror() ) )
662 {
663 XmlWriterUtil.writeLineBreak( writer );
664 XmlWriterUtil.writeCommentText( writer, "Mirror of software download web page.", 2 );
665 String[] downloadMirrors = StringUtils.split( doapOptions.getDownloadMirror(), "," );
666 for ( int i = 0; i < downloadMirrors.length; i++ )
667 {
668 DoapUtil.writeRdfResourceElement( writer, "download-mirror", downloadMirrors[i].trim() );
669 }
670 }
671 }
672
673
674
675
676
677
678
679 private void writeOS( XMLWriter writer )
680 {
681 if ( StringUtils.isEmpty( doapOptions.getOs() ) )
682 {
683 return;
684 }
685
686 XmlWriterUtil.writeLineBreak( writer );
687 XmlWriterUtil.writeCommentText( writer, "Operating system that a project is limited to.", 2 );
688
689 String[] oses = StringUtils.split( doapOptions.getOs(), "," );
690 for ( int i = 0; i < oses.length; i++ )
691 {
692 DoapUtil.writeRdfResourceElement( writer, "os", oses[i].trim() );
693 }
694 }
695
696
697
698
699
700
701
702 private void writeScreenshots( XMLWriter writer )
703 {
704 if ( StringUtils.isEmpty( doapOptions.getScreenshots() ) )
705 {
706 return;
707 }
708
709 XmlWriterUtil.writeLineBreak( writer );
710 XmlWriterUtil.writeCommentText( writer, "Web page with screenshots of project.", 2 );
711 DoapUtil.writeRdfResourceElement( writer, "screenshots", doapOptions.getScreenshots() );
712 }
713
714
715
716
717
718
719
720 private void writeWiki( XMLWriter writer )
721 {
722 if ( StringUtils.isEmpty( doapOptions.getWiki() ) )
723 {
724 return;
725 }
726
727 XmlWriterUtil.writeLineBreak( writer );
728 XmlWriterUtil.writeCommentText( writer, "URL of Wiki for collaborative discussion of project.", 2 );
729 DoapUtil.writeRdfResourceElement( writer, "wiki", doapOptions.getWiki() );
730 }
731
732
733
734
735
736
737
738 private void writeLicenses( XMLWriter writer )
739 {
740 if ( project.getLicenses() == null || project.getLicenses().isEmpty() )
741 {
742 return;
743 }
744
745 XmlWriterUtil.writeLineBreak( writer );
746 XmlWriterUtil.writeCommentText( writer, "The URI of the license the software is distributed under.", 2 );
747
748
749 for ( Iterator it = project.getLicenses().iterator(); it.hasNext(); )
750 {
751 License license = (License) it.next();
752
753 if ( StringUtils.isNotEmpty( license.getUrl() ) )
754 {
755 DoapUtil.writeRdfResourceElement( writer, "license", license.getUrl() );
756 }
757 else
758 {
759 getLog().warn( "No URL was specified for license " + license.getName() );
760 }
761 }
762 }
763
764
765
766
767
768
769
770 private void writeBugDatabase( XMLWriter writer )
771 {
772 if ( project.getIssueManagement() == null )
773 {
774 return;
775 }
776
777 XmlWriterUtil.writeLineBreak( writer );
778 XmlWriterUtil.writeCommentText( writer, "bug database.", 2 );
779 if ( StringUtils.isNotEmpty( project.getIssueManagement().getUrl() ) )
780 {
781 DoapUtil.writeRdfResourceElement( writer, "bug-database", project.getIssueManagement().getUrl() );
782 }
783 else
784 {
785 getLog().warn( "No URL was specified for issue management" );
786 }
787 }
788
789
790
791
792
793
794
795 private void writeMailingList( XMLWriter writer )
796 {
797 if ( project.getMailingLists() == null || project.getMailingLists().isEmpty() )
798 {
799 return;
800 }
801
802 XmlWriterUtil.writeLineBreak( writer );
803 XmlWriterUtil.writeCommentText( writer, "mailing list.", 2 );
804 for ( Iterator it = project.getMailingLists().iterator(); it.hasNext(); )
805 {
806 MailingList mailingList = (MailingList) it.next();
807
808 if ( StringUtils.isNotEmpty( mailingList.getArchive() ) )
809 {
810 DoapUtil.writeRdfResourceElement( writer, "mailing-list", mailingList.getArchive() );
811 }
812 else
813 {
814 getLog().warn( "No archive was specified for mailing list " + mailingList.getName() );
815 }
816
817 if ( mailingList.getOtherArchives() != null )
818 {
819 for ( Iterator it2 = mailingList.getOtherArchives().iterator(); it2.hasNext(); )
820 {
821 String otherArchive = (String) it2.next();
822
823 if ( StringUtils.isNotEmpty( otherArchive ) )
824 {
825 DoapUtil.writeRdfResourceElement( writer, "mailing-list", otherArchive );
826 }
827 else
828 {
829 getLog().warn( "No other archive was specified for mailing list " + mailingList.getName() );
830 }
831 }
832 }
833 }
834 }
835
836
837
838
839
840
841
842
843
844 private void writeReleases( XMLWriter writer )
845 throws MojoExecutionException
846 {
847 Artifact artifact = artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), project
848 .getVersion(), null, project.getPackaging() );
849 RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
850
851 for ( Iterator it = remoteRepositories.iterator(); it.hasNext(); )
852 {
853 ArtifactRepository repo = (ArtifactRepository) it.next();
854
855 if ( repo.isBlacklisted() )
856 {
857 continue;
858 }
859 if ( repo.getSnapshots().isEnabled() )
860 {
861 continue;
862 }
863 if ( repo.getReleases().isEnabled() )
864 {
865 try
866 {
867 repositoryMetadataManager.resolveAlways( metadata, localRepository, repo );
868 break;
869 }
870 catch ( RepositoryMetadataResolutionException e )
871 {
872 throw new MojoExecutionException( metadata
873 + " could not be retrieved from repositories due to an error: " + e.getMessage(), e );
874 }
875 }
876 }
877
878 if ( metadata.getMetadata().getVersioning() == null )
879 {
880 getLog().info( "No versioning was found - ignored writing <release/> tag." );
881 return;
882 }
883
884 List versions = metadata.getMetadata().getVersioning().getVersions();
885
886
887 Collections.reverse( versions );
888 boolean addComment = false;
889 int i = 0;
890 for ( Iterator it = versions.iterator(); it.hasNext(); )
891 {
892 String version = (String) it.next();
893
894 if ( !addComment )
895 {
896 XmlWriterUtil.writeLineBreak( writer );
897 XmlWriterUtil.writeCommentText( writer, "Project releases.", 2 );
898 addComment = true;
899 }
900
901 writer.startElement( "release" );
902 writer.startElement( "Version" );
903
904 writer.startElement( "name" );
905 if ( version.equals( metadata.getMetadata().getVersioning().getRelease() ) )
906 {
907 writer.writeText( "Latest stable release" );
908 }
909 else
910 {
911 writer.writeText( project.getName() + " - " + version );
912 }
913 writer.endElement();
914
915 writer.startElement( "revision" );
916 writer.writeText( version );
917 writer.endElement();
918
919
920 for ( Iterator it2 = remoteRepositories.iterator(); it2.hasNext(); )
921 {
922 ArtifactRepository repo = (ArtifactRepository) it2.next();
923
924 Artifact artifactRelease = artifactFactory.createArtifact( project.getGroupId(), project
925 .getArtifactId(), version, null, project.getPackaging() );
926
927 if ( artifactRelease == null )
928 {
929 continue;
930 }
931
932 String fileRelease = repo.getUrl() + "/" + repo.pathOf( artifactRelease );
933
934 try
935 {
936 URL urlRelease = new URL( fileRelease );
937 urlRelease.openStream();
938 }
939 catch ( MalformedURLException e )
940 {
941 getLog().debug( e.getMessage(), e );
942 continue;
943 }
944 catch ( IOException e )
945 {
946
947 getLog().debug( e.getMessage(), e );
948 continue;
949 }
950
951 writer.startElement( "file-release" );
952 writer.writeText( fileRelease );
953 writer.endElement();
954
955 Date releaseDate = null;
956 try
957 {
958 releaseDate =
959 REPOSITORY_DATE_FORMAT.parse( metadata.getMetadata().getVersioning().getLastUpdated() );
960 }
961 catch ( ParseException e )
962 {
963 getLog().error(
964 "Unable to parse date '"
965 + metadata.getMetadata().getVersioning().getLastUpdated() + "'" );
966 continue;
967 }
968
969
970 if ( i == 0 )
971 {
972 writer.startElement( "created" );
973 writer.writeText( DOAP_DATE_FORMAT.format( releaseDate ) );
974 writer.endElement();
975 }
976 }
977
978 writer.endElement();
979 writer.endElement();
980
981 i++;
982 }
983 }
984
985
986
987
988
989
990
991
992
993 private void writeSourceRepositories( XMLWriter writer )
994 {
995 Scm scm = project.getScm();
996 if ( scm == null )
997 {
998 return;
999 }
1000
1001 XmlWriterUtil.writeLineBreak( writer );
1002 XmlWriterUtil.writeCommentText( writer, "Anonymous Source Repository", 2 );
1003 String anonymousConnection = scm.getConnection();
1004 writeSourceRepository( writer, anonymousConnection );
1005
1006 XmlWriterUtil.writeLineBreak( writer );
1007 XmlWriterUtil.writeCommentText( writer, "Developer Source Repository", 2 );
1008 String developerConnection = scm.getDeveloperConnection();
1009 writeSourceRepository( writer, developerConnection );
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 private void writeSourceRepository( XMLWriter writer, String connection )
1030 {
1031 ScmRepository repository = getScmRepository( connection );
1032
1033 writer.startElement( "repository" );
1034
1035 if ( isScmSystem( repository, "cvs" ) )
1036 {
1037 writer.startElement( "CVSRepository" );
1038
1039 CvsScmProviderRepository cvsRepo = (CvsScmProviderRepository) repository.getProviderRepository();
1040
1041 DoapUtil.writeElement( writer, "anon-root", cvsRepo.getCvsRoot() );
1042 DoapUtil.writeElement( writer, "module", cvsRepo.getModule() );
1043 }
1044 else if ( isScmSystem( repository, "svn" ) )
1045 {
1046 writer.startElement( "SVNRepository" );
1047
1048 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) repository.getProviderRepository();
1049
1050 DoapUtil.writeRdfResourceElement( writer, "location", svnRepo.getUrl() );
1051 }
1052 else
1053 {
1054
1055
1056
1057
1058
1059
1060 writer.startElement( "Repository" );
1061
1062 if ( connection.length() < 4 )
1063 {
1064 throw new IllegalArgumentException( "The source repository connection is too short." );
1065 }
1066
1067 DoapUtil.writeRdfResourceElement( writer, "location", connection.substring( 4 ) );
1068 }
1069
1070 DoapUtil.writeRdfResourceElement( writer, "browse", project.getScm().getUrl() );
1071
1072 writer.endElement();
1073 writer.endElement();
1074 }
1075
1076
1077
1078
1079
1080
1081
1082 private void writeDevelopersOrContributors( XMLWriter writer, List developersOrContributors )
1083 {
1084 if ( developersOrContributors == null || developersOrContributors.isEmpty() )
1085 {
1086 return;
1087 }
1088
1089 boolean isDeveloper = Developer.class.isAssignableFrom( developersOrContributors.get( 0 ).getClass() );
1090 if ( isDeveloper )
1091 {
1092 XmlWriterUtil.writeLineBreak( writer );
1093 XmlWriterUtil.writeCommentText( writer, "Main committers", 2 );
1094 }
1095 else
1096 {
1097 XmlWriterUtil.writeLineBreak( writer );
1098 XmlWriterUtil.writeCommentText( writer, "Contributed persons", 2 );
1099 }
1100
1101 List maintainers = DoapUtil.getDevelopersOrContributorsWithMaintainerRole( i18n, developersOrContributors );
1102 List developers = DoapUtil.getDevelopersOrContributorsWithDeveloperRole( i18n, developersOrContributors );
1103 List documenters = DoapUtil.getDevelopersOrContributorsWithDocumenterRole( i18n, developersOrContributors );
1104 List translators = DoapUtil.getDevelopersOrContributorsWithTranslatorRole( i18n, developersOrContributors );
1105 List testers = DoapUtil.getDevelopersOrContributorsWithTesterRole( i18n, developersOrContributors );
1106 List helpers = DoapUtil.getDevelopersOrContributorsWithHelperRole( i18n, developersOrContributors );
1107 List unknowns = DoapUtil.getDevelopersOrContributorsWithUnknownRole( i18n, developersOrContributors );
1108
1109
1110 if ( isDeveloper )
1111 {
1112 maintainers.addAll( unknowns );
1113 }
1114 else
1115 {
1116 helpers.addAll( unknowns );
1117 }
1118
1119
1120 if ( developers.size() != 0 )
1121 {
1122 writeDeveloperOrContributor( writer, developers, "developer" );
1123 }
1124 if ( documenters.size() != 0 )
1125 {
1126 writeDeveloperOrContributor( writer, documenters, "documenter" );
1127 }
1128 if ( helpers.size() != 0 )
1129 {
1130 writeDeveloperOrContributor( writer, helpers, "helper" );
1131 }
1132 if ( maintainers.size() != 0 )
1133 {
1134 writeDeveloperOrContributor( writer, maintainers, "maintainer" );
1135 }
1136 if ( testers.size() != 0 )
1137 {
1138 writeDeveloperOrContributor( writer, testers, "tester" );
1139 }
1140 if ( translators.size() != 0 )
1141 {
1142 writeDeveloperOrContributor( writer, translators, "translator" );
1143 }
1144 }
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 private void writeDeveloperOrContributor( XMLWriter writer, List developersOrContributors, String doapType )
1163 {
1164 if ( developersOrContributors == null || developersOrContributors.isEmpty() )
1165 {
1166 return;
1167 }
1168
1169
1170 Collections.sort( developersOrContributors, new Comparator()
1171 {
1172
1173
1174
1175 public int compare( Object arg0, Object arg1 )
1176 {
1177 if ( Developer.class.isAssignableFrom( arg0.getClass() ) )
1178 {
1179 Developer developer0 = (Developer) arg0;
1180 Developer developer1 = (Developer) arg1;
1181
1182 if ( developer0.getName() == null )
1183 {
1184 return -1;
1185 }
1186 if ( developer1.getName() == null )
1187 {
1188 return +1;
1189 }
1190
1191 return developer0.getName().compareTo( developer1.getName() );
1192 }
1193
1194 Contributor contributor0 = (Contributor) arg0;
1195 Contributor contributor1 = (Contributor) arg1;
1196
1197 if ( contributor0.getName() == null )
1198 {
1199 return -1;
1200 }
1201 if ( contributor1.getName() == null )
1202 {
1203 return +1;
1204 }
1205
1206 return contributor0.getName().compareTo( contributor1.getName() );
1207 }
1208 } );
1209
1210 for ( Iterator it = developersOrContributors.iterator(); it.hasNext(); )
1211 {
1212 Object obj = it.next();
1213 writeDeveloperOrContributor( writer, obj, doapType );
1214 }
1215 }
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235 private void writeDeveloperOrContributor( XMLWriter writer, Object developerOrContributor, String doapType )
1236 {
1237 if ( developerOrContributor == null )
1238 {
1239 return;
1240 }
1241
1242 if ( StringUtils.isEmpty( doapType ) )
1243 {
1244 throw new IllegalArgumentException( "doapType is required." );
1245 }
1246
1247 String name;
1248 String email;
1249 String organization;
1250 String homepage;
1251
1252 if ( Developer.class.isAssignableFrom( developerOrContributor.getClass() ) )
1253 {
1254 Developer d = (Developer) developerOrContributor;
1255 name = d.getName();
1256 email = d.getEmail();
1257 organization = d.getOrganization();
1258 homepage = d.getUrl();
1259 }
1260 else
1261 {
1262 Contributor c = (Contributor) developerOrContributor;
1263 name = c.getName();
1264 email = c.getEmail();
1265 organization = c.getOrganization();
1266 homepage = c.getUrl();
1267 }
1268
1269
1270 if ( StringUtils.isEmpty( name ) )
1271 {
1272 return;
1273 }
1274
1275 writer.startElement( doapType );
1276 writer.startElement( "foaf:Person" );
1277 writer.startElement( "foaf:name" );
1278 writer.writeText( name );
1279 writer.endElement();
1280 if ( StringUtils.isNotEmpty( email ) )
1281 {
1282 DoapUtil.writeRdfResourceElement( writer, "foaf:mbox", "mailto:" + email );
1283 }
1284 if ( StringUtils.isNotEmpty( organization ) )
1285 {
1286 DoapUtil.writeRdfResourceElement( writer, "foaf:Organization", organization );
1287 }
1288 if ( StringUtils.isNotEmpty( homepage ) )
1289 {
1290 DoapUtil.writeRdfResourceElement( writer, "foaf:homepage", homepage );
1291 }
1292 writer.endElement();
1293 writer.endElement();
1294 }
1295
1296
1297
1298
1299
1300
1301
1302 private ScmRepository getScmRepository( String scmUrl )
1303 {
1304 ScmRepository repo = null;
1305 if ( !StringUtils.isEmpty( scmUrl ) )
1306 {
1307 try
1308 {
1309 repo = scmManager.makeScmRepository( scmUrl );
1310 }
1311 catch ( NoSuchScmProviderException e )
1312 {
1313 if ( getLog().isDebugEnabled() )
1314 {
1315 getLog().debug( e.getMessage(), e );
1316 }
1317 }
1318 catch ( ScmRepositoryException e )
1319 {
1320 if ( getLog().isDebugEnabled() )
1321 {
1322 getLog().debug( e.getMessage(), e );
1323 }
1324 }
1325 }
1326
1327 return repo;
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338 private void writeASFext( XMLWriter writer )
1339 {
1340 XmlWriterUtil.writeLineBreak( writer );
1341 XmlWriterUtil.writeCommentText( writer, "ASF extension", 2 );
1342
1343
1344 if ( StringUtils.isNotEmpty( asfExtOptions.getPmc() ) )
1345 {
1346 DoapUtil.writeRdfResourceElement( writer, "asfext:pmc", asfExtOptions.getPmc() );
1347 }
1348 else
1349 {
1350 if ( StringUtils.isEmpty( project.getUrl() ) )
1351 {
1352 getLog().warn(
1353 "No project url discovered! According http://projects.apache.org/docs/pmc.html, "
1354 + "asfext:pmc is required" );
1355 }
1356 else
1357 {
1358 DoapUtil.writeRdfResourceElement( writer, "asfext:pmc", project.getUrl() );
1359 }
1360 }
1361
1362
1363 if ( StringUtils.isNotEmpty( asfExtOptions.getName() ) )
1364 {
1365 DoapUtil.writeRdfResourceElement( writer, "asfext:name", asfExtOptions.getName() );
1366 }
1367 else
1368 {
1369 if ( StringUtils.isEmpty( project.getName() ) )
1370 {
1371 getLog().warn(
1372 "No project name discovered! According http://projects.apache.org/docs/pmc.html, "
1373 + "asfext:name is required" );
1374 }
1375 else
1376 {
1377
1378 if ( !project.getName().trim().startsWith( "Apache" ) )
1379 {
1380 DoapUtil.writeRdfResourceElement( writer, "asfext:name", "Apache " + project.getName().trim() );
1381 }
1382 else
1383 {
1384 DoapUtil.writeRdfResourceElement( writer, "asfext:name", project.getName().trim() );
1385 }
1386 }
1387 }
1388
1389
1390 if ( StringUtils.isEmpty( asfExtOptions.getCharter() ) )
1391 {
1392 getLog().warn(
1393 "No charter specified! According http://projects.apache.org/docs/pmc.html, "
1394 + "charter is required" );
1395 }
1396 else
1397 {
1398 DoapUtil.writeRdfResourceElement( writer, "asfext:charter", asfExtOptions.getCharter() );
1399 }
1400
1401
1402 List developers = project.getDevelopers();
1403
1404 if ( StringUtils.isNotEmpty( asfExtOptions.getChair() ) )
1405 {
1406 writer.startElement( "asfext:chair" );
1407 writer.startElement( "foaf:Person" );
1408 writer.startElement( "foaf:name" );
1409 writer.writeText( asfExtOptions.getChair() );
1410 writer.endElement();
1411 writer.endElement();
1412 writer.endElement();
1413 }
1414 else
1415 {
1416 Developer chair = ASFExtOptions.findChair( developers );
1417 if ( chair != null )
1418 {
1419 writeDeveloperOrContributor( writer, chair, "asfext:chair" );
1420 }
1421 else
1422 {
1423 getLog().warn(
1424 "No chair man discovered! According http://projects.apache.org/docs/pmc.html, "
1425 + "asfext:chair is required" );
1426 }
1427 }
1428
1429
1430 if ( developers != null && developers.size() > 0 )
1431 {
1432 List pmcMember = ASFExtOptions.findPMCMembers( developers );
1433 for ( Iterator it = pmcMember.iterator(); it.hasNext(); )
1434 {
1435 Developer developer = (Developer) it.next();
1436
1437 writeDeveloperOrContributor( writer, developer, "asfext:member" );
1438 }
1439 }
1440
1441 writeASFImplements( writer );
1442 }
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 private void writeASFImplements( XMLWriter writer )
1453 {
1454 if ( asfExtOptions.getStandards() == null || asfExtOptions.getStandards().isEmpty() )
1455 {
1456 return;
1457 }
1458
1459 for ( Iterator it = asfExtOptions.getStandards().iterator(); it.hasNext(); )
1460 {
1461 Standard standard = (Standard) it.next();
1462
1463 writer.startElement( "asfext:implements" );
1464 writer.startElement( "asfext:Standard" );
1465
1466 if ( StringUtils.isEmpty( standard.getTitle() ) )
1467 {
1468 getLog().warn(
1469 "No title specified! According http://projects.apache.org/docs/standards.html, "
1470 + "asfext:title is required" );
1471 }
1472 else
1473 {
1474 writer.startElement( "asfext:title" );
1475 writer.writeText( standard.getTitle() );
1476 writer.endElement();
1477 }
1478
1479 if ( StringUtils.isEmpty( standard.getBody() ) )
1480 {
1481 getLog().warn(
1482 "No body specified! According http://projects.apache.org/docs/standards.html, "
1483 + "asfext:body is required" );
1484 }
1485 else
1486 {
1487 writer.startElement( "asfext:body" );
1488 writer.writeText( standard.getBody() );
1489 writer.endElement();
1490 }
1491
1492 if ( StringUtils.isEmpty( standard.getId() ) )
1493 {
1494 getLog().warn(
1495 "No id specified! According http://projects.apache.org/docs/standards.html, "
1496 + "asfext:id is required" );
1497 }
1498 else
1499 {
1500 writer.startElement( "asfext:id" );
1501 writer.writeText( standard.getId() );
1502 writer.endElement();
1503 }
1504
1505 if ( StringUtils.isNotEmpty( standard.getUrl() ) )
1506 {
1507 writer.startElement( "asfext:url" );
1508 writer.writeText( standard.getUrl() );
1509 writer.endElement();
1510 }
1511
1512 writer.endElement();
1513 writer.endElement();
1514 }
1515 }
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 private static String composeUrl( String base, String path )
1531 {
1532 if ( base.endsWith( "/" ) && path.startsWith( "/" ) )
1533 {
1534 return base + path.substring( 1 );
1535 }
1536
1537 return base + path;
1538 }
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551 private static boolean isScmSystem( ScmRepository scmRepository, String scmProvider )
1552 {
1553 if ( StringUtils.isEmpty( scmProvider ) )
1554 {
1555 return false;
1556 }
1557
1558 if ( scmRepository != null && scmProvider.equalsIgnoreCase( scmRepository.getProvider() ) )
1559 {
1560 return true;
1561 }
1562
1563 return false;
1564 }
1565 }