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