1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.site.inheritance;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.maven.doxia.site.Body;
28 import org.apache.maven.doxia.site.LinkItem;
29 import org.apache.maven.doxia.site.Logo;
30 import org.apache.maven.doxia.site.Menu;
31 import org.apache.maven.doxia.site.MenuItem;
32 import org.apache.maven.doxia.site.SiteModel;
33 import org.codehaus.plexus.util.xml.Xpp3Dom;
34
35
36
37
38
39
40
41 @Singleton
42 @Named
43 public class DefaultSiteModelInheritanceAssembler implements SiteModelInheritanceAssembler {
44
45 public void assembleModelInheritance(
46 String name, SiteModel child, SiteModel parent, String childBaseUrl, String parentBaseUrl) {
47 if (parent == null || !child.isMergeParent()) {
48 return;
49 }
50
51 child.setCombineSelf(parent.getCombineSelf());
52
53 URLRebaser urlContainer = new URLRebaser(parentBaseUrl, childBaseUrl);
54
55 if (child.getBannerLeft() == null && parent.getBannerLeft() != null) {
56 child.setBannerLeft(parent.getBannerLeft().clone());
57 rebaseLinkItemPaths(child.getBannerLeft(), urlContainer);
58 }
59
60 if (child.getBannerRight() == null && parent.getBannerRight() != null) {
61 child.setBannerRight(parent.getBannerRight().clone());
62 rebaseLinkItemPaths(child.getBannerRight(), urlContainer);
63 }
64
65 if (child.isDefaultPublishDate() && parent.getPublishDate() != null) {
66 child.setPublishDate(parent.getPublishDate().clone());
67 }
68
69 if (child.isDefaultVersion() && parent.getVersion() != null) {
70 child.setVersion(parent.getVersion().clone());
71 }
72
73 if (child.getEdit() == null && parent.getEdit() != null) {
74 child.setEdit(parent.getEdit());
75 }
76
77 if (child.getSkin() == null && parent.getSkin() != null) {
78 child.setSkin(parent.getSkin().clone());
79 }
80
81 child.setPoweredBy(mergePoweredByLists(child.getPoweredBy(), parent.getPoweredBy(), urlContainer));
82
83 if (parent.getLastModified() > child.getLastModified()) {
84 child.setLastModified(parent.getLastModified());
85 }
86
87 assembleBodyInheritance(name, child, parent, urlContainer);
88
89 assembleCustomInheritance(child, parent);
90 }
91
92
93 public void resolvePaths(final SiteModel siteModel, final String baseUrl) {
94 if (baseUrl == null) {
95 return;
96 }
97
98 if (siteModel.getBannerLeft() != null) {
99 relativizeLinkItemPaths(siteModel.getBannerLeft(), baseUrl);
100 }
101
102 if (siteModel.getBannerRight() != null) {
103 relativizeLinkItemPaths(siteModel.getBannerRight(), baseUrl);
104 }
105
106 for (Logo logo : siteModel.getPoweredBy()) {
107 relativizeLinkItemPaths(logo, baseUrl);
108 }
109
110 if (siteModel.getBody() != null) {
111 for (LinkItem linkItem : siteModel.getBody().getLinks()) {
112 relativizeLinkItemPaths(linkItem, baseUrl);
113 }
114
115 for (LinkItem linkItem : siteModel.getBody().getBreadcrumbs()) {
116 relativizeLinkItemPaths(linkItem, baseUrl);
117 }
118
119 for (Menu menu : siteModel.getBody().getMenus()) {
120 relativizeMenuPaths(menu.getItems(), baseUrl);
121 if (menu.getImage() != null) {
122 menu.getImage().setSrc(relativizeLink(menu.getImage().getSrc(), baseUrl));
123 }
124 }
125 }
126 }
127
128 private void assembleCustomInheritance(final SiteModel child, final SiteModel parent) {
129 if (child.getCustom() == null) {
130 child.setCustom(parent.getCustom());
131 } else {
132 child.setCustom(Xpp3Dom.mergeXpp3Dom((Xpp3Dom) child.getCustom(), (Xpp3Dom) parent.getCustom()));
133 }
134 }
135
136 private void assembleBodyInheritance(
137 final String name, final SiteModel child, final SiteModel parent, final URLRebaser urlContainer) {
138 Body cBody = child.getBody();
139 Body pBody = parent.getBody();
140
141 if (cBody != null || pBody != null) {
142 if (cBody == null) {
143 cBody = new Body();
144 child.setBody(cBody);
145 }
146
147 if (pBody == null) {
148 pBody = new Body();
149 }
150
151 if (cBody.getHead() == null && pBody.getHead() != null) {
152 cBody.setHead(pBody.getHead());
153 }
154
155 cBody.setLinks(mergeLinkItemLists(cBody.getLinks(), pBody.getLinks(), urlContainer, false));
156
157 if (cBody.getBreadcrumbs().isEmpty() && !pBody.getBreadcrumbs().isEmpty()) {
158 LinkItem breadcrumb = new LinkItem();
159 breadcrumb.setName(name);
160 breadcrumb.setHref("index.html");
161 cBody.getBreadcrumbs().add(breadcrumb);
162 }
163 cBody.setBreadcrumbs(
164 mergeLinkItemLists(cBody.getBreadcrumbs(), pBody.getBreadcrumbs(), urlContainer, true));
165
166 cBody.setMenus(mergeMenus(cBody.getMenus(), pBody.getMenus(), urlContainer));
167
168 if (cBody.getFooter() == null && pBody.getFooter() != null) {
169 cBody.setFooter(pBody.getFooter());
170 }
171 }
172 }
173
174 private List<Menu> mergeMenus(
175 final List<Menu> childMenus, final List<Menu> parentMenus, final URLRebaser urlContainer) {
176 List<Menu> menus = new ArrayList<>(childMenus.size() + parentMenus.size());
177
178 for (Menu menu : childMenus) {
179 menus.add(menu);
180 }
181
182 int topCounter = 0;
183 for (Menu menu : parentMenus) {
184 if ("top".equals(menu.getInherit())) {
185 final Menu clone = menu.clone();
186
187 rebaseMenuPaths(clone.getItems(), urlContainer);
188 if (clone.getImage() != null) {
189 clone.getImage()
190 .setSrc(urlContainer.rebaseLink(clone.getImage().getSrc()));
191 }
192
193 menus.add(topCounter, clone);
194 topCounter++;
195 } else if ("bottom".equals(menu.getInherit())) {
196 final Menu clone = menu.clone();
197
198 rebaseMenuPaths(clone.getItems(), urlContainer);
199 if (clone.getImage() != null) {
200 clone.getImage()
201 .setSrc(urlContainer.rebaseLink(clone.getImage().getSrc()));
202 }
203
204 menus.add(clone);
205 }
206 }
207
208 return menus;
209 }
210
211 private void relativizeMenuPaths(final List<MenuItem> items, final String baseUrl) {
212 for (MenuItem item : items) {
213 relativizeLinkItemPaths(item, baseUrl);
214 relativizeMenuPaths(item.getItems(), baseUrl);
215 }
216 }
217
218 private void rebaseMenuPaths(final List<MenuItem> items, final URLRebaser urlContainer) {
219 for (MenuItem item : items) {
220 rebaseLinkItemPaths(item, urlContainer);
221 rebaseMenuPaths(item.getItems(), urlContainer);
222 }
223 }
224
225 private void relativizeLinkItemPaths(final LinkItem item, final String baseUrl) {
226 item.setHref(relativizeLink(item.getHref(), baseUrl));
227 if (item.getImage() != null) {
228 item.getImage().setSrc(relativizeLink(item.getImage().getSrc(), baseUrl));
229 }
230 }
231
232 private void rebaseLinkItemPaths(final LinkItem item, final URLRebaser urlContainer) {
233 item.setHref(urlContainer.rebaseLink(item.getHref()));
234 if (item.getImage() != null) {
235 item.getImage().setSrc(urlContainer.rebaseLink(item.getImage().getSrc()));
236 }
237 }
238
239 private List<LinkItem> mergeLinkItemLists(
240 final List<LinkItem> childList,
241 final List<LinkItem> parentList,
242 final URLRebaser urlContainer,
243 boolean cutParentAfterDuplicate) {
244 List<LinkItem> items = new ArrayList<>(childList.size() + parentList.size());
245
246 for (LinkItem item : parentList) {
247 if (!items.contains(item) && !childList.contains(item)) {
248 final LinkItem clone = item.clone();
249
250 rebaseLinkItemPaths(clone, urlContainer);
251
252 items.add(clone);
253 } else if (cutParentAfterDuplicate) {
254
255
256
257 break;
258 }
259 }
260
261 for (LinkItem item : childList) {
262 if (!items.contains(item)) {
263 items.add(item);
264 }
265 }
266
267 return items;
268 }
269
270 private List<Logo> mergePoweredByLists(
271 final List<Logo> childList, final List<Logo> parentList, final URLRebaser urlContainer) {
272 List<Logo> logos = new ArrayList<>(childList.size() + parentList.size());
273
274 for (Logo logo : parentList) {
275 if (!logos.contains(logo)) {
276 final Logo clone = logo.clone();
277
278 rebaseLinkItemPaths(clone, urlContainer);
279
280 logos.add(clone);
281 }
282 }
283
284 for (Logo logo : childList) {
285 if (!logos.contains(logo)) {
286 logos.add(logo);
287 }
288 }
289
290 return logos;
291 }
292
293
294
295 private String relativizeLink(final String link, final String baseUri) {
296 if (link == null || baseUri == null) {
297 return link;
298 }
299
300
301 try {
302 final URIPathDescriptor path = new URIPathDescriptor(baseUri, link);
303
304 return path.relativizeLink().toString();
305 } catch (IllegalArgumentException e) {
306 return link;
307 }
308 }
309
310
311
312
313
314 private static class URLRebaser {
315
316 private final String oldPath;
317
318 private final String newPath;
319
320
321
322
323
324
325
326 URLRebaser(final String oldPath, final String newPath) {
327 this.oldPath = oldPath;
328 this.newPath = newPath;
329 }
330
331
332
333
334
335
336 public String getNewPath() {
337 return this.newPath;
338 }
339
340
341
342
343
344
345 public String getOldPath() {
346 return this.oldPath;
347 }
348
349
350
351
352
353 public String rebaseLink(final String link) {
354 if (link == null || getOldPath() == null) {
355 return link;
356 }
357
358 if (link.contains("${project.")) {
359 throw new IllegalArgumentException("site.xml late interpolation ${project.*} expression found"
360 + " in link: '" + link + "'. Use early interpolation ${this.*}");
361 }
362
363 final URIPathDescriptor oldPath = new URIPathDescriptor(getOldPath(), link);
364
365 return oldPath.rebaseLink(getNewPath()).toString();
366 }
367 }
368 }