1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.util;
35
36 import java.util.Collection;
37 import java.util.Comparator;
38 import java.util.LinkedHashMap;
39 import java.util.SortedMap;
40 import java.util.TreeMap;
41
42 import javax.jcr.RepositoryException;
43 import org.apache.commons.lang.StringUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import info.magnolia.cms.core.AbstractContent;
48 import info.magnolia.cms.core.Content;
49 import info.magnolia.cms.core.DefaultNodeData;
50 import info.magnolia.cms.core.NodeData;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public class ExtendingContentWrapper extends ContentWrapper {
74
75 private static final String EXTENDING_NODE_DATA = "extends";
76 private static final String EXTENDING_NODE_DATA_OVERRIDE = "override";
77
78 private boolean extending;
79
80 private Content extendedContent;
81
82 private static final Logger log = LoggerFactory.getLogger(ExtendingContentWrapper.class);
83
84
85 ExtendingContentWrapper(Content wrappedContent, boolean failOnError) {
86 super(wrappedContent);
87 try {
88 extending = getWrappedContent().hasNodeData(EXTENDING_NODE_DATA);
89 if (extending) {
90 NodeData extendingNodeData = getWrappedContent().getNodeData(EXTENDING_NODE_DATA);
91
92
93 String extendedNode = extendingNodeData.getString();
94
95 Content parent = extendingNodeData.getParent();
96 boolean absolute = true;
97
98 if(!extendedNode.isEmpty()){
99 if(!extendedNode.startsWith("/")){
100 if(parent.hasContent(extendedNode)){
101 extendedNode = parent.getContent(extendedNode).getHandle();
102 }else{
103 absolute = false;
104 }
105 }
106 }
107
108 if (StringUtils.isBlank(extendedNode)) {
109
110 extending = false;
111 } else if (absolute && !getWrappedContent().getHierarchyManager().isExist(extendedNode)){
112 String message = "Can't find referenced node for value: " + wrappedContent;
113 log.error(message);
114 if (failOnError){
115 throw new RuntimeException(message);
116 }
117 extending = false;
118 } else if (!absolute && !parent.hasContent(extendedNode)){
119 String message = "Can't find referenced node for value: " + wrappedContent;
120 log.error(message);
121 if (failOnError){
122 throw new RuntimeException(message);
123 }
124 extending = false;
125 } else if (EXTENDING_NODE_DATA_OVERRIDE.equals(extendedNode)) {
126 extending = false;
127 } else {
128
129 extendedContent = wrapIfNeeded(extendingNodeData.getReferencedContent());
130 }
131 }
132 }
133 catch (RepositoryException e) {
134 throw new RuntimeException("Can't wrap node [" + wrappedContent + "]", e);
135 }
136 }
137
138 public ExtendingContentWrapper(Content wrappedContent) {
139 this(wrappedContent, false);
140 }
141
142
143
144
145
146 protected ExtendingContentWrapper(Content wrappedContent, Content extendedContent) {
147 super(wrapIfNeeded(wrappedContent));
148 extending = true;
149 try {
150 if (getWrappedContent().hasNodeData(EXTENDING_NODE_DATA)) {
151 NodeData extendingNodeData = getWrappedContent().getNodeData(EXTENDING_NODE_DATA);
152
153
154 extending = !EXTENDING_NODE_DATA_OVERRIDE.equals(extendingNodeData.getString());
155 }
156 }
157 catch (RepositoryException e) {
158 throw new RuntimeException("Can't determine extends point for node [" + wrappedContent + "]", e);
159 }
160
161 this.extendedContent = wrapIfNeeded(extendedContent);
162 }
163
164 private static Content wrapIfNeeded(Content content) {
165 if (content instanceof ExtendingContentWrapper) {
166 return content;
167 }
168 return new ExtendingContentWrapper(content);
169 }
170
171 public boolean isExtending() {
172 return this.extending;
173 }
174
175 @Override
176 public Content getWrappedContent() {
177 Content wrapped = super.getWrappedContent();
178 if (wrapped instanceof ExtendingContentWrapper) {
179 ExtendingContentWrapper wrappedECW = (ExtendingContentWrapper) wrapped;
180 if (!wrappedECW.extending) {
181
182 return ((ExtendingContentWrapper) wrapped).getWrappedContent();
183 }
184 }
185 return super.getWrappedContent();
186 }
187 @Override
188 public boolean hasContent(String name) throws RepositoryException {
189 if (getWrappedContent().hasContent(name)) {
190 return true;
191 }
192 else if (extending && extendedContent.hasContent(name)) {
193 return true;
194 }
195 return false;
196 }
197
198 @Override
199 public Content getContent(String name) throws RepositoryException {
200 Content content;
201 if (getWrappedContent().hasContent(name)) {
202 content = getWrappedContent().getContent(name);
203 }
204 else if (extending && extendedContent.hasContent(name)) {
205 content = extendedContent.getContent(name);
206 }
207 else {
208
209 content = getWrappedContent().getContent(name);
210 }
211 return wrap(content);
212 }
213
214 @Override
215 public Collection<Content> getChildren(ContentFilter filter, String namePattern, Comparator<Content> orderCriteria) {
216 Collection<Content> directChildren = ((AbstractContent)getWrappedContent()).getChildren(filter, namePattern, orderCriteria);
217 if (extending) {
218 Collection<Content> inheritedChildren = ((AbstractContent)extendedContent).getChildren(filter, namePattern, orderCriteria);
219
220 LinkedHashMap<String, Content> merged = new LinkedHashMap<String, Content>();
221 for (Content content : inheritedChildren) {
222 merged.put(content.getName(), content);
223 }
224 for (Content content : directChildren) {
225 merged.put(content.getName(), content);
226 }
227 return wrapContentNodes(merged.values());
228 }
229 else {
230 return wrapContentNodes(directChildren);
231 }
232 }
233
234 @Override
235 public NodeData getNodeData(String name) {
236 if (EXTENDING_NODE_DATA.equals(name)) {
237 return new DefaultNodeData(extendedContent, name) {
238 @Override
239 public boolean isExist() {
240 return false;
241 }
242
243 @Override
244 public void save() throws RepositoryException {
245
246 }
247 };
248 }
249 try {
250 if (getWrappedContent().hasNodeData(name)) {
251 return wrap(getWrappedContent().getNodeData(name));
252 }
253 else if (extending && extendedContent.hasNodeData(name)) {
254 return wrap(extendedContent.getNodeData(name));
255 }
256 else {
257 return wrap(getWrappedContent().getNodeData(name));
258 }
259 }
260 catch (RepositoryException e) {
261 throw new RuntimeException("Can't read nodedata from extended node [" + extendedContent + "]", e);
262 }
263 }
264
265 @Override
266 public boolean hasNodeData(String name) throws RepositoryException {
267 if (EXTENDING_NODE_DATA.equals(name)) {
268 return false;
269 }
270 return super.hasNodeData(name);
271 }
272
273 @Override
274 public Collection<NodeData> getNodeDataCollection() {
275 final Content wrapped = getWrappedContent();
276 Collection<NodeData> directChildren = wrapped.getNodeDataCollection();
277 try {
278 if (wrapped.hasNodeData(EXTENDING_NODE_DATA)) {
279 for (NodeData child : directChildren) {
280 if (EXTENDING_NODE_DATA.equals(child.getName())) {
281 directChildren.remove(child);
282 break;
283 }
284 }
285 }
286 } catch (RepositoryException e) {
287 throw new RuntimeException("Can't read nodedata collection from node [" + wrapped.getHandle() + "]", e);
288 }
289 if (extending) {
290 Collection<NodeData> inheritedChildren = extendedContent.getNodeDataCollection();
291
292 SortedMap<String, NodeData> merged = new TreeMap<String, NodeData>();
293 for (NodeData nodeData : inheritedChildren) {
294 merged.put(nodeData.getName(), nodeData);
295 }
296 for (NodeData nodeData : directChildren) {
297 merged.put(nodeData.getName(), nodeData);
298 }
299 return wrapNodeDatas(merged.values());
300 }
301 else {
302 return wrapNodeDatas(directChildren);
303 }
304 }
305
306 @Override
307 protected Content wrap(Content node) {
308
309 try {
310 if (extending && extendedContent.hasContent(node.getName())) {
311
312 Content extendedSubContent = extendedContent.getContent(node.getName());
313 return new ExtendingContentWrapper(node, extendedSubContent);
314 }
315 }
316 catch (RepositoryException e) {
317 throw new RuntimeException("Can't wrap " + node, e);
318 }
319 return wrapIfNeeded(node);
320 }
321
322 }