1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.tools;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.io.File;
26 import java.io.IOException;
27 import java.io.Reader;
28 import java.io.StringReader;
29 import java.io.StringWriter;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.nio.file.Files;
33 import java.util.AbstractMap;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Properties;
42 import java.util.StringTokenizer;
43
44 import org.apache.commons.io.FilenameUtils;
45 import org.apache.maven.RepositoryUtils;
46 import org.apache.maven.artifact.Artifact;
47 import org.apache.maven.artifact.DefaultArtifact;
48 import org.apache.maven.artifact.handler.ArtifactHandler;
49 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
50 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
51 import org.apache.maven.artifact.versioning.VersionRange;
52 import org.apache.maven.doxia.site.Banner;
53 import org.apache.maven.doxia.site.Body;
54 import org.apache.maven.doxia.site.Image;
55 import org.apache.maven.doxia.site.LinkItem;
56 import org.apache.maven.doxia.site.Logo;
57 import org.apache.maven.doxia.site.Menu;
58 import org.apache.maven.doxia.site.MenuItem;
59 import org.apache.maven.doxia.site.PublishDate;
60 import org.apache.maven.doxia.site.SiteModel;
61 import org.apache.maven.doxia.site.Skin;
62 import org.apache.maven.doxia.site.Version;
63 import org.apache.maven.doxia.site.decoration.DecorationModel;
64 import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Reader;
65 import org.apache.maven.doxia.site.inheritance.SiteModelInheritanceAssembler;
66 import org.apache.maven.doxia.site.io.xpp3.SiteXpp3Reader;
67 import org.apache.maven.doxia.site.io.xpp3.SiteXpp3Writer;
68 import org.apache.maven.execution.DefaultMavenExecutionRequest;
69 import org.apache.maven.execution.MavenExecutionRequest;
70 import org.apache.maven.model.DistributionManagement;
71 import org.apache.maven.model.Plugin;
72 import org.apache.maven.project.MavenProject;
73 import org.apache.maven.reporting.MavenReport;
74 import org.codehaus.plexus.i18n.I18N;
75 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
76 import org.codehaus.plexus.interpolation.InterpolationException;
77 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
78 import org.codehaus.plexus.interpolation.MapBasedValueSource;
79 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
80 import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
81 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
82 import org.codehaus.plexus.util.IOUtil;
83 import org.codehaus.plexus.util.ReaderFactory;
84 import org.codehaus.plexus.util.StringUtils;
85 import org.codehaus.plexus.util.xml.Xpp3Dom;
86 import org.codehaus.plexus.util.xml.pull.MXParser;
87 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
88 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
89 import org.eclipse.aether.RepositorySystem;
90 import org.eclipse.aether.RepositorySystemSession;
91 import org.eclipse.aether.repository.LocalArtifactRequest;
92 import org.eclipse.aether.repository.LocalArtifactResult;
93 import org.eclipse.aether.repository.LocalRepositoryManager;
94 import org.eclipse.aether.repository.RemoteRepository;
95 import org.eclipse.aether.resolution.ArtifactRequest;
96 import org.eclipse.aether.resolution.ArtifactResolutionException;
97 import org.eclipse.aether.resolution.ArtifactResult;
98 import org.eclipse.aether.transfer.ArtifactNotFoundException;
99 import org.slf4j.Logger;
100 import org.slf4j.LoggerFactory;
101
102
103
104
105
106
107 @Singleton
108 @Named
109 public class DefaultSiteTool implements SiteTool {
110 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSiteTool.class);
111
112
113
114
115
116
117
118
119 @Inject
120 protected RepositorySystem repositorySystem;
121
122
123
124
125 @Inject
126 private ArtifactHandlerManager artifactHandlerManager;
127
128
129
130
131 @Inject
132 protected I18N i18n;
133
134
135
136
137 @Inject
138 protected SiteModelInheritanceAssembler assembler;
139
140
141
142
143
144
145 public Artifact getSkinArtifactFromRepository(
146 RepositorySystemSession repoSession, List<RemoteRepository> remoteProjectRepositories, Skin skin)
147 throws SiteToolException {
148 Objects.requireNonNull(repoSession, "repoSession cannot be null");
149 Objects.requireNonNull(remoteProjectRepositories, "remoteProjectRepositories cannot be null");
150 Objects.requireNonNull(skin, "skin cannot be null");
151
152 String version = skin.getVersion();
153 try {
154 if (version == null) {
155 version = Artifact.RELEASE_VERSION;
156 }
157 VersionRange versionSpec = VersionRange.createFromVersionSpec(version);
158 String type = "jar";
159 Artifact artifact = new DefaultArtifact(
160 skin.getGroupId(),
161 skin.getArtifactId(),
162 versionSpec,
163 Artifact.SCOPE_RUNTIME,
164 type,
165 null,
166 artifactHandlerManager.getArtifactHandler(type));
167 ArtifactRequest request =
168 new ArtifactRequest(RepositoryUtils.toArtifact(artifact), remoteProjectRepositories, "remote-skin");
169 ArtifactResult result = repositorySystem.resolveArtifact(repoSession, request);
170
171 return RepositoryUtils.toArtifact(result.getArtifact());
172 } catch (InvalidVersionSpecificationException e) {
173 throw new SiteToolException("The skin version '" + version + "' is not valid", e);
174 } catch (ArtifactResolutionException e) {
175 if (e.getCause() instanceof ArtifactNotFoundException) {
176 throw new SiteToolException("The skin does not exist", e.getCause());
177 }
178
179 throw new SiteToolException("Unable to find skin", e);
180 }
181 }
182
183
184
185
186
187
188 @Deprecated
189 public String getRelativePath(String to, String from) {
190 Objects.requireNonNull(to, "to cannot be null");
191 Objects.requireNonNull(from, "from cannot be null");
192
193 if (to.contains(":") && from.contains(":")) {
194 String toScheme = to.substring(0, to.lastIndexOf(':'));
195 String fromScheme = from.substring(0, from.lastIndexOf(':'));
196 if (!toScheme.equals(fromScheme)) {
197 return to;
198 }
199 }
200
201 URL toUrl = null;
202 URL fromUrl = null;
203
204 String toPath = to;
205 String fromPath = from;
206
207 try {
208 toUrl = new URL(to);
209 } catch (MalformedURLException e) {
210 try {
211 toUrl = new File(getNormalizedPath(to)).toURI().toURL();
212 } catch (MalformedURLException e1) {
213 LOGGER.warn("Unable to load a URL for '" + to + "'", e);
214 return to;
215 }
216 }
217
218 try {
219 fromUrl = new URL(from);
220 } catch (MalformedURLException e) {
221 try {
222 fromUrl = new File(getNormalizedPath(from)).toURI().toURL();
223 } catch (MalformedURLException e1) {
224 LOGGER.warn("Unable to load a URL for '" + from + "'", e);
225 return to;
226 }
227 }
228
229 if (toUrl != null && fromUrl != null) {
230
231
232 if ((toUrl.getProtocol().equalsIgnoreCase(fromUrl.getProtocol()))
233 && (toUrl.getHost().equalsIgnoreCase(fromUrl.getHost()))
234 && (toUrl.getPort() == fromUrl.getPort())) {
235
236
237 toPath = toUrl.getFile();
238 fromPath = fromUrl.getFile();
239 } else {
240
241
242 return to;
243 }
244 } else if ((toUrl != null && fromUrl == null) || (toUrl == null && fromUrl != null)) {
245
246
247 return to;
248 }
249
250
251
252
253
254 String relativePath = getRelativeFilePath(fromPath, toPath);
255
256 if (relativePath == null) {
257 relativePath = to;
258 }
259
260 if (LOGGER.isDebugEnabled() && !relativePath.toString().equals(to)) {
261 LOGGER.debug("Mapped url: " + to + " to relative path: " + relativePath);
262 }
263
264 return relativePath;
265 }
266
267 private static String getRelativeFilePath(final String oldPath, final String newPath) {
268
269
270 String fromPath = new File(oldPath).getPath();
271 String toPath = new File(newPath).getPath();
272
273
274 if (toPath.matches("^\\[a-zA-Z]:")) {
275 toPath = toPath.substring(1);
276 }
277 if (fromPath.matches("^\\[a-zA-Z]:")) {
278 fromPath = fromPath.substring(1);
279 }
280
281
282 if (fromPath.startsWith(":", 1)) {
283 fromPath = Character.toLowerCase(fromPath.charAt(0)) + fromPath.substring(1);
284 }
285 if (toPath.startsWith(":", 1)) {
286 toPath = Character.toLowerCase(toPath.charAt(0)) + toPath.substring(1);
287 }
288
289
290
291
292 if ((toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))
293 && (!toPath.substring(0, 1).equals(fromPath.substring(0, 1)))) {
294
295
296
297 return null;
298 }
299
300 if ((toPath.startsWith(":", 1) && !fromPath.startsWith(":", 1))
301 || (!toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))) {
302
303
304
305
306 return null;
307 }
308
309 final String relativePath = buildRelativePath(toPath, fromPath, File.separatorChar);
310
311 return relativePath.toString();
312 }
313
314
315 public File getSiteDescriptor(File siteDirectory, Locale locale) {
316 Objects.requireNonNull(siteDirectory, "siteDirectory cannot be null");
317 Objects.requireNonNull(locale, "locale cannot be null");
318
319 String variant = locale.getVariant();
320 String country = locale.getCountry();
321 String language = locale.getLanguage();
322
323 File siteDescriptor = null;
324
325 if (!variant.isEmpty()) {
326 siteDescriptor = new File(siteDirectory, "site_" + language + "_" + country + "_" + variant + ".xml");
327 }
328
329 if ((siteDescriptor == null || !siteDescriptor.isFile()) && !country.isEmpty()) {
330 siteDescriptor = new File(siteDirectory, "site_" + language + "_" + country + ".xml");
331 }
332
333 if ((siteDescriptor == null || !siteDescriptor.isFile()) && !language.isEmpty()) {
334 siteDescriptor = new File(siteDirectory, "site_" + language + ".xml");
335 }
336
337 if (siteDescriptor == null || !siteDescriptor.isFile()) {
338 siteDescriptor = new File(siteDirectory, "site.xml");
339 }
340
341 return siteDescriptor;
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356 File getSiteDescriptorFromRepository(
357 MavenProject project,
358 RepositorySystemSession repoSession,
359 List<RemoteRepository> remoteProjectRepositories,
360 Locale locale)
361 throws SiteToolException {
362 Objects.requireNonNull(project, "project cannot be null");
363 Objects.requireNonNull(repoSession, "repoSession cannot be null");
364 Objects.requireNonNull(remoteProjectRepositories, "remoteProjectRepositories cannot be null");
365 Objects.requireNonNull(locale, "locale cannot be null");
366
367 try {
368 File siteDescriptor = resolveSiteDescriptor(project, repoSession, remoteProjectRepositories, locale);
369 if (siteDescriptor == null) {
370 LOGGER.debug("Site descriptor not found");
371 return null;
372 } else {
373 return siteDescriptor;
374 }
375 } catch (ArtifactResolutionException e) {
376 throw new SiteToolException("Unable to locate site descriptor", e);
377 }
378 }
379
380 @Override
381 @Deprecated
382 public SiteModel getSiteModel(
383 File siteDirectory,
384 Locale locale,
385 MavenProject project,
386 List<MavenProject> reactorProjects,
387 RepositorySystemSession repoSession,
388 List<RemoteRepository> remoteProjectRepositories)
389 throws SiteToolException {
390 return getSiteModel(
391 siteDirectory,
392 locale,
393 new DefaultMavenExecutionRequest(),
394 project,
395 reactorProjects,
396 repoSession,
397 remoteProjectRepositories);
398 }
399
400 @Override
401 public SiteModel getSiteModel(
402 File siteDirectory,
403 Locale locale,
404 MavenExecutionRequest request,
405 MavenProject project,
406 List<MavenProject> reactorProjects,
407 RepositorySystemSession repoSession,
408 List<RemoteRepository> remoteProjectRepositories)
409 throws SiteToolException {
410 Objects.requireNonNull(locale, "locale cannot be null");
411 Objects.requireNonNull(locale, "request cannot be null");
412 Objects.requireNonNull(project, "project cannot be null");
413 Objects.requireNonNull(reactorProjects, "reactorProjects cannot be null");
414 Objects.requireNonNull(repoSession, "repoSession cannot be null");
415 Objects.requireNonNull(remoteProjectRepositories, "remoteProjectRepositories cannot be null");
416
417 LOGGER.debug("Computing site model of '" + project.getId() + "' for "
418 + (locale.equals(SiteTool.DEFAULT_LOCALE) ? "default locale" : "locale '" + locale + "'"));
419
420 Map.Entry<SiteModel, MavenProject> result =
421 getSiteModel(0, siteDirectory, locale, request, project, repoSession, remoteProjectRepositories);
422 SiteModel siteModel = result.getKey();
423 MavenProject parentProject = result.getValue();
424
425 if (siteModel == null) {
426 LOGGER.debug("Using default site descriptor");
427 siteModel = getDefaultSiteModel();
428 }
429
430
431 String siteDescriptorContent = siteModelToString(siteModel);
432
433
434 siteDescriptorContent = getInterpolatedSiteDescriptorContent(request, project, siteDescriptorContent, false);
435
436 siteModel = readSiteModel(siteDescriptorContent, project, locale);
437
438 if (parentProject != null) {
439 populateParentMenu(siteModel, locale, project, parentProject, true);
440 }
441
442 try {
443 populateModulesMenu(siteModel, locale, project, reactorProjects, true);
444 } catch (IOException e) {
445 throw new SiteToolException("Error while populating modules menu", e);
446 }
447
448 return siteModel;
449 }
450
451 @Override
452 @Deprecated
453 public String getInterpolatedSiteDescriptorContent(
454 Map<String, String> props, MavenProject aProject, String siteDescriptorContent) throws SiteToolException {
455 Objects.requireNonNull(props, "props cannot be null");
456
457
458 return getInterpolatedSiteDescriptorContent(
459 new DefaultMavenExecutionRequest(), aProject, siteDescriptorContent, false);
460 }
461
462
463
464
465
466
467
468
469
470
471
472 private String getInterpolatedSiteDescriptorContent(
473 MavenExecutionRequest request, MavenProject aProject, String siteDescriptorContent, boolean isEarly)
474 throws SiteToolException {
475 Objects.requireNonNull(request, "request cannot be null");
476 Objects.requireNonNull(aProject, "aProject cannot be null");
477 Objects.requireNonNull(siteDescriptorContent, "siteDescriptorContent cannot be null");
478
479 RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
480
481 if (isEarly) {
482 interpolator.addValueSource(new PrefixedObjectValueSource("this.", aProject));
483 interpolator.addValueSource(new PrefixedPropertiesValueSource("this.", aProject.getProperties()));
484
485 } else {
486 interpolator.addValueSource(new PrefixedObjectValueSource("project.", aProject));
487 interpolator.addValueSource(new MapBasedValueSource(mergeProperties(request, aProject)));
488
489 try {
490 interpolator.addValueSource(new EnvarBasedValueSource());
491 } catch (IOException e) {
492
493 throw new SiteToolException("Cannot interpolate environment properties", e);
494 }
495 }
496
497 interpolator.addPostProcessor(new InterpolationPostProcessor() {
498 @Override
499 public Object execute(String expression, Object value) {
500 if (value != null) {
501
502 return value.toString()
503 .replace("&", "&")
504 .replace("<", "<")
505 .replace(">", ">")
506 .replace("\"", """)
507 .replace("'", "'");
508 }
509 return null;
510 }
511 });
512
513 try {
514 return interpolator.interpolate(siteDescriptorContent);
515 } catch (InterpolationException e) {
516 throw new SiteToolException("Cannot interpolate site descriptor", e);
517 }
518 }
519
520
521
522
523
524
525
526
527
528
529
530
531 private static Properties mergeProperties(MavenExecutionRequest request, MavenProject aProject) {
532 Properties merged = new Properties();
533 merged.putAll(request.getSystemProperties());
534 merged.putAll(aProject.getProperties());
535 merged.putAll(request.getUserProperties());
536 return merged;
537 }
538
539
540
541
542
543
544
545
546
547
548
549 private void populateParentMenu(
550 SiteModel siteModel,
551 Locale locale,
552 MavenProject project,
553 MavenProject parentProject,
554 boolean keepInheritedRefs) {
555 Objects.requireNonNull(siteModel, "siteModel cannot be null");
556 Objects.requireNonNull(locale, "locale cannot be null");
557 Objects.requireNonNull(project, "project cannot be null");
558 Objects.requireNonNull(parentProject, "parentProject cannot be null");
559
560 Menu menu = siteModel.getMenuRef("parent");
561
562 if (menu == null) {
563 return;
564 }
565
566 if (keepInheritedRefs && menu.isInheritAsRef()) {
567 return;
568 }
569
570 String parentUrl = getDistMgmntSiteUrl(parentProject);
571
572 if (parentUrl != null) {
573 if (parentUrl.endsWith("/")) {
574 parentUrl += "index.html";
575 } else {
576 parentUrl += "/index.html";
577 }
578
579 parentUrl = getRelativePath(parentUrl, getDistMgmntSiteUrl(project));
580 } else {
581
582 File parentBasedir = parentProject.getBasedir();
583
584 if (parentBasedir != null) {
585
586 String parentPath = parentBasedir.getAbsolutePath();
587 String projectPath = project.getBasedir().getAbsolutePath();
588 parentUrl = getRelativePath(parentPath, projectPath) + "/index.html";
589 }
590 }
591
592
593 if (parentUrl == null) {
594 LOGGER.warn("Unable to find a URL to the parent project. The parent menu will NOT be added.");
595 } else {
596 if (menu.getName() == null) {
597 menu.setName(i18n.getString("site-tool", locale, "siteModel.menu.parentproject"));
598 }
599
600 MenuItem item = new MenuItem();
601 item.setName(parentProject.getName());
602 item.setHref(parentUrl);
603 menu.addItem(item);
604 }
605 }
606
607
608
609
610
611
612
613
614
615
616
617
618
619 private void populateModulesMenu(
620 SiteModel siteModel,
621 Locale locale,
622 MavenProject project,
623 List<MavenProject> reactorProjects,
624 boolean keepInheritedRefs)
625 throws SiteToolException, IOException {
626 Objects.requireNonNull(siteModel, "siteModel cannot be null");
627 Objects.requireNonNull(locale, "locale cannot be null");
628 Objects.requireNonNull(project, "project cannot be null");
629 Objects.requireNonNull(reactorProjects, "reactorProjects cannot be null");
630
631 Menu menu = siteModel.getMenuRef("modules");
632
633 if (menu == null) {
634 return;
635 }
636
637 if (keepInheritedRefs && menu.isInheritAsRef()) {
638 return;
639 }
640
641
642 if (!project.getModules().isEmpty()) {
643 if (menu.getName() == null) {
644 menu.setName(i18n.getString("site-tool", locale, "siteModel.menu.projectmodules"));
645 }
646
647 for (String module : project.getModules()) {
648 MavenProject moduleProject = getModuleFromReactor(project, reactorProjects, module);
649
650 if (moduleProject == null) {
651 LOGGER.debug("Module " + module + " not found in reactor");
652 continue;
653 }
654
655 final String pluginId = "org.apache.maven.plugins:maven-site-plugin";
656 String skipFlag = getPluginParameter(moduleProject, pluginId, "skip");
657 if (skipFlag == null) {
658 skipFlag = moduleProject.getProperties().getProperty("maven.site.skip");
659 }
660
661 String siteUrl = "true".equalsIgnoreCase(skipFlag) ? null : getDistMgmntSiteUrl(moduleProject);
662 String itemName =
663 (moduleProject.getName() == null) ? moduleProject.getArtifactId() : moduleProject.getName();
664 String defaultSiteUrl = "true".equalsIgnoreCase(skipFlag) ? null : moduleProject.getArtifactId();
665
666 appendMenuItem(project, menu, itemName, siteUrl, defaultSiteUrl);
667 }
668 } else if (siteModel.getMenuRef("modules").getInherit() == null) {
669
670 siteModel.removeMenuRef("modules");
671 }
672 }
673
674 private MavenProject getModuleFromReactor(MavenProject project, List<MavenProject> reactorProjects, String module)
675 throws IOException {
676 File moduleBasedir = new File(project.getBasedir(), module).getCanonicalFile();
677
678 for (MavenProject reactorProject : reactorProjects) {
679 if (moduleBasedir.equals(reactorProject.getBasedir())) {
680 return reactorProject;
681 }
682 }
683
684
685 return null;
686 }
687
688
689 public void populateReportsMenu(SiteModel siteModel, Locale locale, Map<String, List<MavenReport>> categories) {
690 Objects.requireNonNull(siteModel, "siteModel cannot be null");
691 Objects.requireNonNull(locale, "locale cannot be null");
692 Objects.requireNonNull(categories, "categories cannot be null");
693
694 Menu menu = siteModel.getMenuRef("reports");
695
696 if (menu == null) {
697 return;
698 }
699
700 if (menu.getName() == null) {
701 menu.setName(i18n.getString("site-tool", locale, "siteModel.menu.projectdocumentation"));
702 }
703
704 boolean found = false;
705 if (menu.getItems().isEmpty()) {
706 List<MavenReport> categoryReports = categories.get(MavenReport.CATEGORY_PROJECT_INFORMATION);
707 if (!isEmptyList(categoryReports)) {
708 MenuItem item = createCategoryMenu(
709 i18n.getString("site-tool", locale, "siteModel.menu.projectinformation"),
710 "/project-info.html",
711 categoryReports,
712 locale);
713 menu.getItems().add(item);
714 found = true;
715 }
716
717 categoryReports = categories.get(MavenReport.CATEGORY_PROJECT_REPORTS);
718 if (!isEmptyList(categoryReports)) {
719 MenuItem item = createCategoryMenu(
720 i18n.getString("site-tool", locale, "siteModel.menu.projectreports"),
721 "/project-reports.html",
722 categoryReports,
723 locale);
724 menu.getItems().add(item);
725 found = true;
726 }
727 }
728 if (!found) {
729 siteModel.removeMenuRef("reports");
730 }
731 }
732
733
734 public List<Locale> getSiteLocales(String locales) {
735 if (locales == null) {
736 return Collections.singletonList(DEFAULT_LOCALE);
737 }
738
739 String[] localesArray = StringUtils.split(locales, ",");
740 List<Locale> localesList = new ArrayList<>(localesArray.length);
741 List<Locale> availableLocales = Arrays.asList(Locale.getAvailableLocales());
742
743 for (String localeString : localesArray) {
744 Locale locale = codeToLocale(localeString);
745
746 if (locale == null) {
747 continue;
748 }
749
750 if (!availableLocales.contains(locale)) {
751 if (LOGGER.isWarnEnabled()) {
752 LOGGER.warn("The locale defined by '" + locale
753 + "' is not available in this Java Virtual Machine ("
754 + System.getProperty("java.version")
755 + " from " + System.getProperty("java.vendor") + ") - IGNORING");
756 }
757 continue;
758 }
759
760 Locale bundleLocale = i18n.getBundle("site-tool", locale).getLocale();
761 if (!(bundleLocale.equals(locale) || bundleLocale.getLanguage().equals(locale.getLanguage()))) {
762 if (LOGGER.isWarnEnabled()) {
763 LOGGER.warn("The locale '" + locale + "' (" + locale.getDisplayName(Locale.ENGLISH)
764 + ") is not currently supported by Maven Site - IGNORING."
765 + System.lineSeparator() + "Contributions are welcome and greatly appreciated!"
766 + System.lineSeparator() + "If you want to contribute a new translation, please visit "
767 + "https://maven.apache.org/plugins/localization.html for detailed instructions.");
768 }
769
770 continue;
771 }
772
773 localesList.add(locale);
774 }
775
776 if (localesList.isEmpty()) {
777 localesList = Collections.singletonList(DEFAULT_LOCALE);
778 }
779
780 return localesList;
781 }
782
783
784
785
786
787
788
789
790
791
792
793
794
795 private Locale codeToLocale(String localeCode) {
796 if (localeCode == null) {
797 return null;
798 }
799
800 if ("system".equalsIgnoreCase(localeCode)) {
801 return Locale.getDefault();
802 }
803
804 if ("default".equalsIgnoreCase(localeCode)) {
805 return SiteTool.DEFAULT_LOCALE;
806 }
807
808 String language = "";
809 String country = "";
810 String variant = "";
811
812 StringTokenizer tokenizer = new StringTokenizer(localeCode, "_");
813 final int maxTokens = 3;
814 if (tokenizer.countTokens() > maxTokens) {
815 if (LOGGER.isWarnEnabled()) {
816 LOGGER.warn("Invalid java.util.Locale format for '" + localeCode + "' entry - IGNORING");
817 }
818 return null;
819 }
820
821 if (tokenizer.hasMoreTokens()) {
822 language = tokenizer.nextToken();
823 if (tokenizer.hasMoreTokens()) {
824 country = tokenizer.nextToken();
825 if (tokenizer.hasMoreTokens()) {
826 variant = tokenizer.nextToken();
827 }
828 }
829 }
830
831 return new Locale(language, country, variant);
832 }
833
834
835
836
837
838
839
840
841
842
843 protected static String getNormalizedPath(String path) {
844 String normalized = FilenameUtils.normalize(path);
845 if (normalized == null) {
846 normalized = path;
847 }
848 return (normalized == null) ? null : normalized.replace('\\', '/');
849 }
850
851
852
853
854
855
856
857
858
859
860
861 private ArtifactRequest createSiteDescriptorArtifactRequest(
862 MavenProject project, String localeStr, List<RemoteRepository> remoteProjectRepositories) {
863 String type = "xml";
864 ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler(type);
865 Artifact artifact = new DefaultArtifact(
866 project.getGroupId(),
867 project.getArtifactId(),
868 project.getVersion(),
869 Artifact.SCOPE_RUNTIME,
870 type,
871 "site" + (localeStr.isEmpty() ? "" : "_" + localeStr),
872 artifactHandler);
873 return new ArtifactRequest(
874 RepositoryUtils.toArtifact(artifact), remoteProjectRepositories, "remote-site-descriptor");
875 }
876
877
878
879
880
881
882
883
884
885 private File resolveSiteDescriptor(
886 MavenProject project,
887 RepositorySystemSession repoSession,
888 List<RemoteRepository> remoteProjectRepositories,
889 Locale locale)
890 throws ArtifactResolutionException {
891 String variant = locale.getVariant();
892 String country = locale.getCountry();
893 String language = locale.getLanguage();
894
895 String localeStr = null;
896 File siteDescriptor = null;
897 boolean found = false;
898
899 if (!variant.isEmpty()) {
900 localeStr = language + "_" + country + "_" + variant;
901 ArtifactRequest request =
902 createSiteDescriptorArtifactRequest(project, localeStr, remoteProjectRepositories);
903
904 deletePseudoSiteDescriptorMarkerFile(repoSession, request);
905
906 try {
907 ArtifactResult result = repositorySystem.resolveArtifact(repoSession, request);
908
909 siteDescriptor = result.getArtifact().getFile();
910 found = true;
911 } catch (ArtifactResolutionException e) {
912
913 if (e.getResult().getExceptions().stream().anyMatch(re -> re instanceof ArtifactNotFoundException)) {
914 LOGGER.debug("No site descriptor found for '" + project.getId() + "' for locale '" + localeStr
915 + "', trying without variant...");
916 } else {
917 throw e;
918 }
919 }
920 }
921
922 if (!found && !country.isEmpty()) {
923 localeStr = language + "_" + country;
924 ArtifactRequest request =
925 createSiteDescriptorArtifactRequest(project, localeStr, remoteProjectRepositories);
926
927 deletePseudoSiteDescriptorMarkerFile(repoSession, request);
928
929 try {
930 ArtifactResult result = repositorySystem.resolveArtifact(repoSession, request);
931
932 siteDescriptor = result.getArtifact().getFile();
933 found = true;
934 } catch (ArtifactResolutionException e) {
935
936 if (e.getResult().getExceptions().stream().anyMatch(re -> re instanceof ArtifactNotFoundException)) {
937 LOGGER.debug("No site descriptor found for '" + project.getId() + "' for locale '" + localeStr
938 + "', trying without country...");
939 } else {
940 throw e;
941 }
942 }
943 }
944
945 if (!found && !language.isEmpty()) {
946 localeStr = language;
947 ArtifactRequest request =
948 createSiteDescriptorArtifactRequest(project, localeStr, remoteProjectRepositories);
949
950 deletePseudoSiteDescriptorMarkerFile(repoSession, request);
951
952 try {
953 ArtifactResult result = repositorySystem.resolveArtifact(repoSession, request);
954
955 siteDescriptor = result.getArtifact().getFile();
956 found = true;
957 } catch (ArtifactResolutionException e) {
958
959 if (e.getResult().getExceptions().stream().anyMatch(re -> re instanceof ArtifactNotFoundException)) {
960 LOGGER.debug("No site descriptor found for '" + project.getId() + "' for locale '" + localeStr
961 + "', trying without language (default locale)...");
962 } else {
963 throw e;
964 }
965 }
966 }
967
968 if (!found) {
969 localeStr = SiteTool.DEFAULT_LOCALE.toString();
970 ArtifactRequest request =
971 createSiteDescriptorArtifactRequest(project, localeStr, remoteProjectRepositories);
972
973 deletePseudoSiteDescriptorMarkerFile(repoSession, request);
974
975 try {
976 ArtifactResult result = repositorySystem.resolveArtifact(repoSession, request);
977
978 siteDescriptor = result.getArtifact().getFile();
979 } catch (ArtifactResolutionException e) {
980
981 if (e.getResult().getExceptions().stream().anyMatch(re -> re instanceof ArtifactNotFoundException)) {
982 LOGGER.debug("No site descriptor found for '" + project.getId() + "' with default locale");
983 return null;
984 }
985
986 throw e;
987 }
988 }
989
990 return siteDescriptor;
991 }
992
993
994 private void deletePseudoSiteDescriptorMarkerFile(RepositorySystemSession repoSession, ArtifactRequest request) {
995 LocalRepositoryManager lrm = repoSession.getLocalRepositoryManager();
996
997 LocalArtifactRequest localRequest =
998 new LocalArtifactRequest(request.getArtifact(), request.getRepositories(), request.getRequestContext());
999
1000 LocalArtifactResult localResult = lrm.find(repoSession, localRequest);
1001 File localArtifactFile = localResult.getFile();
1002
1003 try {
1004 if (localResult.isAvailable() && Files.size(localArtifactFile.toPath()) == 0L) {
1005 LOGGER.debug(
1006 "Deleting 0-byte pseudo marker file for artifact '{}' at '{}'",
1007 localRequest.getArtifact(),
1008 localArtifactFile);
1009 Files.delete(localArtifactFile.toPath());
1010 }
1011 } catch (IOException e) {
1012 LOGGER.debug("Failed to delete 0-byte pseudo marker file for artifact '{}'", localRequest.getArtifact(), e);
1013 }
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 private Map.Entry<SiteModel, MavenProject> getSiteModel(
1027 int depth,
1028 File siteDirectory,
1029 Locale locale,
1030 MavenExecutionRequest request,
1031 MavenProject project,
1032 RepositorySystemSession repoSession,
1033 List<RemoteRepository> remoteProjectRepositories)
1034 throws SiteToolException {
1035
1036 File siteDescriptor;
1037 if (project.getBasedir() == null) {
1038
1039 try {
1040 siteDescriptor =
1041 getSiteDescriptorFromRepository(project, repoSession, remoteProjectRepositories, locale);
1042 } catch (SiteToolException e) {
1043 throw new SiteToolException("The site descriptor cannot be resolved from the repository", e);
1044 }
1045 } else {
1046
1047 siteDescriptor = getSiteDescriptor(siteDirectory, locale);
1048 }
1049
1050
1051 SiteModel siteModel = null;
1052 Reader siteDescriptorReader = null;
1053 try {
1054 if (siteDescriptor != null && siteDescriptor.exists()) {
1055 LOGGER.debug("Reading" + (depth == 0 ? "" : (" parent level " + depth)) + " site descriptor from "
1056 + siteDescriptor);
1057
1058 siteDescriptorReader = ReaderFactory.newXmlReader(siteDescriptor);
1059
1060 String siteDescriptorContent = IOUtil.toString(siteDescriptorReader);
1061
1062
1063 siteDescriptorContent =
1064 getInterpolatedSiteDescriptorContent(request, project, siteDescriptorContent, true);
1065
1066 siteModel = readSiteModel(siteDescriptorContent, project, locale);
1067 siteModel.setLastModified(siteDescriptor.lastModified());
1068 } else {
1069 LOGGER.debug("No" + (depth == 0 ? "" : (" parent level " + depth)) + " site descriptor");
1070 }
1071 } catch (IOException e) {
1072 throw new SiteToolException(
1073 "The site descriptor for '" + project.getId() + "' cannot be read from " + siteDescriptor, e);
1074 } finally {
1075 IOUtil.close(siteDescriptorReader);
1076 }
1077
1078
1079 MavenProject parentProject = project.getParent();
1080
1081
1082 if (parentProject != null && (siteModel == null || siteModel.isMergeParent() || siteModel.isRequireParent())) {
1083 depth++;
1084 LOGGER.debug("Looking for site descriptor of level " + depth + " parent project: " + parentProject.getId());
1085
1086 File parentSiteDirectory = null;
1087 if (parentProject.getBasedir() != null) {
1088
1089 String siteRelativePath = getRelativeFilePath(
1090 project.getBasedir().getAbsolutePath(),
1091 siteDescriptor.getParentFile().getAbsolutePath());
1092
1093 parentSiteDirectory = new File(parentProject.getBasedir(), siteRelativePath);
1094
1095
1096 }
1097
1098 SiteModel parentSiteModel = getSiteModel(
1099 depth,
1100 parentSiteDirectory,
1101 locale,
1102 request,
1103 parentProject,
1104 repoSession,
1105 remoteProjectRepositories)
1106 .getKey();
1107
1108 if (siteModel != null) {
1109 if (siteModel.isRequireParent() && parentSiteModel == null) {
1110 throw new SiteToolException(
1111 "The site descriptor for '" + project.getId() + "' requires a parent site descriptor for '"
1112 + parentProject.getId() + "' or any of its parents but none could be found!");
1113 }
1114 }
1115
1116
1117 if (siteModel == null && parentSiteModel != null) {
1118
1119
1120 siteModel = new SiteModel();
1121 }
1122
1123 String name = project.getName();
1124 if (siteModel != null && StringUtils.isNotEmpty(siteModel.getName())) {
1125 name = siteModel.getName();
1126 }
1127
1128
1129 String projectDistMgmnt = getDistMgmntSiteUrl(project);
1130 String parentDistMgmnt = getDistMgmntSiteUrl(parentProject);
1131 if (LOGGER.isDebugEnabled()) {
1132 LOGGER.debug("Site model inheritance: assembling child with level " + depth
1133 + " parent: distributionManagement.site.url child = " + projectDistMgmnt + " and parent = "
1134 + parentDistMgmnt);
1135 }
1136 assembler.assembleModelInheritance(
1137 name,
1138 siteModel,
1139 parentSiteModel,
1140 projectDistMgmnt,
1141 parentDistMgmnt == null ? projectDistMgmnt : parentDistMgmnt);
1142 } else if (parentProject == null && siteModel != null && siteModel.isRequireParent()) {
1143 throw new SiteToolException("The site descriptor for '" + project.getId()
1144 + "' requires a parent site descriptor but no parent is defined in the POM.");
1145 }
1146
1147 return new AbstractMap.SimpleEntry<>(siteModel, parentProject);
1148 }
1149
1150
1151
1152
1153
1154
1155 private SiteModel readSiteModel(String siteDescriptorContent, MavenProject project, Locale locale)
1156 throws SiteToolException {
1157 try {
1158 if (project != null && isOldSiteModel(siteDescriptorContent)) {
1159 LOGGER.warn(
1160 "Site model of '" + project.getId() + "' for "
1161 + (locale.equals(SiteTool.DEFAULT_LOCALE)
1162 ? "default locale"
1163 : "locale '" + locale + "'")
1164 + " is still using the old pre-version 2.0.0 model. You MUST migrate to the new model as soon as possible otherwise your build will break in the future!");
1165 return convertOldToNewSiteModel(
1166 new DecorationXpp3Reader().read(new StringReader(siteDescriptorContent)));
1167 } else {
1168 return new SiteXpp3Reader().read(new StringReader(siteDescriptorContent));
1169 }
1170 } catch (XmlPullParserException e) {
1171 throw new SiteToolException("Error parsing site descriptor", e);
1172 } catch (IOException e) {
1173 throw new SiteToolException("Error reading site descriptor", e);
1174 }
1175 }
1176
1177 private SiteModel convertOldToNewSiteModel(DecorationModel oldModel) {
1178 SiteModel newModel = new SiteModel();
1179 newModel.setName(oldModel.getName());
1180 newModel.setCombineSelf(oldModel.getCombineSelf());
1181 if (oldModel.getBannerLeft() != null) {
1182 newModel.setBannerLeft(convertBanner(oldModel.getBannerLeft()));
1183 }
1184 if (oldModel.getBannerRight() != null) {
1185 newModel.setBannerRight(convertBanner(oldModel.getBannerRight()));
1186 }
1187 if (!oldModel.isDefaultPublishDate()) {
1188 PublishDate newPublishDate = new PublishDate();
1189 newPublishDate.setFormat(oldModel.getPublishDate().getFormat());
1190 newPublishDate.setPosition(oldModel.getPublishDate().getPosition());
1191 newPublishDate.setTimezone(oldModel.getPublishDate().getTimezone());
1192 newModel.setPublishDate(newPublishDate);
1193 }
1194 if (!oldModel.isDefaultVersion()) {
1195 Version newVersion = new Version();
1196 newVersion.setPosition(oldModel.getVersion().getPosition());
1197 newModel.setVersion(newVersion);
1198 }
1199 newModel.setEdit(oldModel.getEdit());
1200 if (oldModel.getSkin() != null) {
1201 Skin newSkin = new Skin();
1202 newSkin.setGroupId(oldModel.getSkin().getGroupId());
1203 newSkin.setArtifactId(oldModel.getSkin().getArtifactId());
1204 newSkin.setVersion(oldModel.getSkin().getVersion());
1205 newModel.setSkin(newSkin);
1206 }
1207
1208 for (org.apache.maven.doxia.site.decoration.Logo oldLogo : oldModel.getPoweredBy()) {
1209 Logo newLogo = new Logo();
1210 newLogo.setName(oldLogo.getName());
1211 newLogo.setHref(oldLogo.getHref());
1212 newLogo.setTarget(oldLogo.getTarget());
1213 if (oldLogo.getImg() != null) {
1214 newLogo.setImage(convertImage(
1215 oldLogo.getImg(),
1216 oldLogo.getPosition(),
1217 oldLogo.getHeight(),
1218 oldLogo.getWidth(),
1219 oldLogo.getBorder(),
1220 oldLogo.getAlt()));
1221 }
1222 newModel.addPoweredBy(newLogo);
1223 }
1224 newModel.setLastModified(oldModel.getLastModified());
1225 if (oldModel.getBody() != null) {
1226 Body newBody = new Body();
1227 newBody.setHead(oldModel.getBody().getHead());
1228 for (org.apache.maven.doxia.site.decoration.LinkItem oldLink :
1229 oldModel.getBody().getLinks()) {
1230 newBody.addLink(convertLinkItem(oldLink));
1231 }
1232 for (org.apache.maven.doxia.site.decoration.LinkItem oldBreadcrumb :
1233 oldModel.getBody().getBreadcrumbs()) {
1234 newBody.addBreadcrumb(convertLinkItem(oldBreadcrumb));
1235 }
1236
1237 for (org.apache.maven.doxia.site.decoration.Menu oldMenu :
1238 oldModel.getBody().getMenus()) {
1239 Menu newMenu = new Menu();
1240 newMenu.setName(oldMenu.getName());
1241 newMenu.setInherit(oldMenu.getInherit());
1242 newMenu.setInheritAsRef(oldMenu.isInheritAsRef());
1243 newMenu.setRef(oldMenu.getRef());
1244 if (oldMenu.getImg() != null) {
1245 newMenu.setImage(convertImage(
1246 oldMenu.getImg(),
1247 oldMenu.getPosition(),
1248 oldMenu.getHeight(),
1249 oldMenu.getWidth(),
1250 oldMenu.getBorder(),
1251 oldMenu.getAlt()));
1252 }
1253 newMenu.setItems(convertMenuItems(oldMenu.getItems()));
1254 newBody.addMenu(newMenu);
1255 }
1256
1257 newBody.setFooter(oldModel.getBody().getFooter());
1258 newModel.setBody(newBody);
1259 }
1260 newModel.setCustom(oldModel.getCustom());
1261
1262 return newModel;
1263 }
1264
1265 private Banner convertBanner(org.apache.maven.doxia.site.decoration.Banner oldBanner) {
1266 Banner newBanner = new Banner();
1267 newBanner.setName(oldBanner.getName());
1268 newBanner.setHref(oldBanner.getHref());
1269 if (oldBanner.getSrc() != null) {
1270 newBanner.setImage(convertImage(
1271 oldBanner.getSrc(),
1272 null,
1273 oldBanner.getHeight(),
1274 oldBanner.getWidth(),
1275 oldBanner.getBorder(),
1276 oldBanner.getAlt()));
1277 }
1278
1279 return newBanner;
1280 }
1281
1282 private Image convertImage(String src, String position, String height, String width, String border, String alt) {
1283 Image newImage = new Image();
1284 newImage.setSrc(src);
1285 newImage.setPosition(position);
1286 newImage.setHeight(height);
1287 newImage.setWidth(width);
1288 if (border != null) {
1289 newImage.setStyle("border: " + border + ";");
1290 }
1291 newImage.setAlt(alt);
1292
1293 return newImage;
1294 }
1295
1296 private LinkItem convertLinkItem(org.apache.maven.doxia.site.decoration.LinkItem oldLinkItem) {
1297 LinkItem newLinkItem = new LinkItem();
1298 newLinkItem.setName(oldLinkItem.getName());
1299 newLinkItem.setHref(oldLinkItem.getHref());
1300 newLinkItem.setTarget(oldLinkItem.getTarget());
1301 if (oldLinkItem.getImg() != null) {
1302 newLinkItem.setImage(convertImage(
1303 oldLinkItem.getImg(),
1304 oldLinkItem.getPosition(),
1305 oldLinkItem.getHeight(),
1306 oldLinkItem.getWidth(),
1307 oldLinkItem.getBorder(),
1308 oldLinkItem.getAlt()));
1309 }
1310
1311 return newLinkItem;
1312 }
1313
1314 private List<MenuItem> convertMenuItems(List<org.apache.maven.doxia.site.decoration.MenuItem> oldMenuItems) {
1315 List<MenuItem> newMenuItems = new ArrayList<>();
1316 for (org.apache.maven.doxia.site.decoration.MenuItem oldMenuItem : oldMenuItems) {
1317 MenuItem newMenuItem = new MenuItem();
1318 newMenuItem.setName(oldMenuItem.getName());
1319 newMenuItem.setHref(oldMenuItem.getHref());
1320 newMenuItem.setTarget(oldMenuItem.getTarget());
1321 newMenuItem.setCollapse(oldMenuItem.isCollapse());
1322 newMenuItem.setRef(oldMenuItem.getRef());
1323 newMenuItem.setItems(convertMenuItems(oldMenuItem.getItems()));
1324 if (oldMenuItem.getImg() != null) {
1325 newMenuItem.setImage(convertImage(
1326 oldMenuItem.getImg(),
1327 oldMenuItem.getPosition(),
1328 oldMenuItem.getHeight(),
1329 oldMenuItem.getWidth(),
1330 oldMenuItem.getBorder(),
1331 oldMenuItem.getAlt()));
1332 }
1333 newMenuItems.add(newMenuItem);
1334 }
1335
1336 return newMenuItems;
1337 }
1338
1339 private boolean isOldSiteModel(String siteDescriptorContent) throws XmlPullParserException, IOException {
1340 XmlPullParser parser = new MXParser();
1341 parser.setInput(new StringReader(siteDescriptorContent));
1342
1343 if (!(parser.getEventType() == XmlPullParser.START_DOCUMENT && parser.next() == XmlPullParser.START_TAG)) {
1344 return false;
1345 }
1346 if ("project".equals(parser.getName())) {
1347 return true;
1348 }
1349
1350 return false;
1351 }
1352
1353 private SiteModel getDefaultSiteModel() throws SiteToolException {
1354 String siteDescriptorContent;
1355
1356 Reader reader = null;
1357 try {
1358 reader = ReaderFactory.newXmlReader(getClass().getResourceAsStream("/default-site.xml"));
1359 siteDescriptorContent = IOUtil.toString(reader);
1360 } catch (IOException e) {
1361 throw new SiteToolException("Error reading default site descriptor", e);
1362 } finally {
1363 IOUtil.close(reader);
1364 }
1365
1366 return readSiteModel(siteDescriptorContent, null, SiteTool.DEFAULT_LOCALE);
1367 }
1368
1369 private String siteModelToString(SiteModel siteModel) throws SiteToolException {
1370 StringWriter writer = new StringWriter();
1371
1372 try {
1373 new SiteXpp3Writer().write(writer, siteModel);
1374 return writer.toString();
1375 } catch (IOException e) {
1376 throw new SiteToolException("Error reading site descriptor", e);
1377 } finally {
1378 IOUtil.close(writer);
1379 }
1380 }
1381
1382 private static String buildRelativePath(final String toPath, final String fromPath, final char separatorChar) {
1383
1384 StringTokenizer toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar));
1385 StringTokenizer fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar));
1386
1387 int count = 0;
1388
1389
1390 while (toTokeniser.hasMoreTokens() && fromTokeniser.hasMoreTokens()) {
1391 if (separatorChar == '\\') {
1392 if (!fromTokeniser.nextToken().equalsIgnoreCase(toTokeniser.nextToken())) {
1393 break;
1394 }
1395 } else {
1396 if (!fromTokeniser.nextToken().equals(toTokeniser.nextToken())) {
1397 break;
1398 }
1399 }
1400
1401 count++;
1402 }
1403
1404
1405
1406
1407 toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar));
1408 fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar));
1409
1410 while (count-- > 0) {
1411 fromTokeniser.nextToken();
1412 toTokeniser.nextToken();
1413 }
1414
1415 StringBuilder relativePath = new StringBuilder();
1416
1417
1418 while (fromTokeniser.hasMoreTokens()) {
1419 fromTokeniser.nextToken();
1420
1421 relativePath.append("..");
1422
1423 if (fromTokeniser.hasMoreTokens()) {
1424 relativePath.append(separatorChar);
1425 }
1426 }
1427
1428 if (relativePath.length() != 0 && toTokeniser.hasMoreTokens()) {
1429 relativePath.append(separatorChar);
1430 }
1431
1432
1433 while (toTokeniser.hasMoreTokens()) {
1434 relativePath.append(toTokeniser.nextToken());
1435
1436 if (toTokeniser.hasMoreTokens()) {
1437 relativePath.append(separatorChar);
1438 }
1439 }
1440 return relativePath.toString();
1441 }
1442
1443
1444
1445
1446
1447
1448
1449
1450 private void appendMenuItem(MavenProject project, Menu menu, String name, String href, String defaultHref) {
1451 String selectedHref = href;
1452
1453 if (selectedHref == null) {
1454 selectedHref = defaultHref;
1455 }
1456
1457 MenuItem item = new MenuItem();
1458 item.setName(name);
1459
1460 if (selectedHref != null) {
1461 String baseUrl = getDistMgmntSiteUrl(project);
1462 if (baseUrl != null) {
1463 selectedHref = getRelativePath(selectedHref, baseUrl);
1464 }
1465
1466 if (selectedHref.endsWith("/")) {
1467 item.setHref(selectedHref + "index.html");
1468 } else {
1469 item.setHref(selectedHref + "/index.html");
1470 }
1471 }
1472 menu.addItem(item);
1473 }
1474
1475
1476
1477
1478
1479
1480
1481
1482 private MenuItem createCategoryMenu(String name, String href, List<MavenReport> categoryReports, Locale locale) {
1483 MenuItem item = new MenuItem();
1484 item.setName(name);
1485 item.setCollapse(true);
1486 item.setHref(href);
1487
1488
1489
1490
1491 for (MavenReport report : categoryReports) {
1492 MenuItem subitem = new MenuItem();
1493 subitem.setName(report.getName(locale));
1494 subitem.setHref(report.getOutputName() + ".html");
1495 item.getItems().add(subitem);
1496 }
1497
1498 return item;
1499 }
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 private static boolean isEmptyList(List<?> list) {
1512 return list == null || list.isEmpty();
1513 }
1514
1515
1516
1517
1518
1519
1520
1521 private static String getDistMgmntSiteUrl(MavenProject project) {
1522 return getDistMgmntSiteUrl(project.getDistributionManagement());
1523 }
1524
1525 private static String getDistMgmntSiteUrl(DistributionManagement distMgmnt) {
1526 if (distMgmnt != null
1527 && distMgmnt.getSite() != null
1528 && distMgmnt.getSite().getUrl() != null) {
1529
1530 return urlEncode(distMgmnt.getSite().getUrl());
1531 }
1532
1533 return null;
1534 }
1535
1536
1537
1538
1539
1540
1541 private static Plugin getPlugin(MavenProject project, String pluginId) {
1542 if ((project.getBuild() == null) || (project.getBuild().getPluginsAsMap() == null)) {
1543 return null;
1544 }
1545
1546 Plugin plugin = project.getBuild().getPluginsAsMap().get(pluginId);
1547
1548 if ((plugin == null)
1549 && (project.getBuild().getPluginManagement() != null)
1550 && (project.getBuild().getPluginManagement().getPluginsAsMap() != null)) {
1551 plugin = project.getBuild().getPluginManagement().getPluginsAsMap().get(pluginId);
1552 }
1553
1554 return plugin;
1555 }
1556
1557
1558
1559
1560
1561
1562
1563 private static String getPluginParameter(MavenProject project, String pluginId, String param) {
1564 Plugin plugin = getPlugin(project, pluginId);
1565 if (plugin != null) {
1566 Xpp3Dom xpp3Dom = (Xpp3Dom) plugin.getConfiguration();
1567 if (xpp3Dom != null
1568 && xpp3Dom.getChild(param) != null
1569 && StringUtils.isNotEmpty(xpp3Dom.getChild(param).getValue())) {
1570 return xpp3Dom.getChild(param).getValue();
1571 }
1572 }
1573
1574 return null;
1575 }
1576
1577 private static String urlEncode(final String url) {
1578 if (url == null) {
1579 return null;
1580 }
1581
1582 try {
1583 return new File(url).toURI().toURL().toExternalForm();
1584 } catch (MalformedURLException ex) {
1585 return url;
1586 }
1587 }
1588 }