Skip to content

Package: DefaultLayout$CloneVisitor

DefaultLayout$CloneVisitor

nameinstructionbranchcomplexitylinemethod
DefaultLayout.CloneVisitor()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getValue()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
postVisit(Layout)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
preVisit(Layout)
M: 28 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * #%L
3: * *********************************************************************************************************************
4: *
5: * NorthernWind - lightweight CMS
6: * http://northernwind.tidalwave.it - git clone https://bitbucket.org/tidalwave/northernwind-src.git
7: * %%
8: * Copyright (C) 2011 - 2023 Tidalwave s.a.s. (http://tidalwave.it)
9: * %%
10: * *********************************************************************************************************************
11: *
12: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
13: * the License. You may obtain a copy of the License at
14: *
15: * http://www.apache.org/licenses/LICENSE-2.0
16: *
17: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
18: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
19: * specific language governing permissions and limitations under the License.
20: *
21: * *********************************************************************************************************************
22: *
23: *
24: * *********************************************************************************************************************
25: * #L%
26: */
27: package it.tidalwave.northernwind.frontend.impl.ui;
28:
29: import javax.annotation.Nonnull;
30: import javax.inject.Inject;
31: import java.util.ArrayDeque;
32: import java.util.ArrayList;
33: import java.util.Deque;
34: import java.util.HashMap;
35: import java.util.List;
36: import java.util.Map;
37: import java.util.Optional;
38: import org.springframework.beans.factory.annotation.Configurable;
39: import it.tidalwave.util.As;
40: import it.tidalwave.util.Id;
41: import it.tidalwave.util.NotFoundException;
42: import it.tidalwave.northernwind.core.model.HttpStatusException;
43: import it.tidalwave.northernwind.core.model.SiteNode;
44: import it.tidalwave.northernwind.frontend.ui.Layout;
45: import it.tidalwave.northernwind.frontend.ui.LayoutFinder;
46: import it.tidalwave.northernwind.frontend.ui.ViewFactory;
47: import it.tidalwave.northernwind.frontend.ui.ViewFactory.ViewAndController;
48: import lombok.Getter;
49: import lombok.experimental.Delegate;
50:
51: /***********************************************************************************************************************
52: *
53: * @author Fabrizio Giudici
54: *
55: **********************************************************************************************************************/
56: @Configurable @Getter
57: public class DefaultLayout implements Layout, Cloneable
58: {
59: @Inject
60: private ViewFactory viewFactory;
61:
62: @Nonnull
63: private final Id id;
64:
65: @Nonnull
66: private /* final FIXME */ String typeUri;
67:
68: private final List<Layout> children = new ArrayList<>();
69:
70: private final Map<Id, Layout> childrenMapById = new HashMap<>();
71:
72: @Delegate
73: private final As asSupport = As.forObject(this);
74:
75: // FIXME: make it Immutable
76:
77: /*******************************************************************************************************************
78: *
79: *
80: *
81: ******************************************************************************************************************/
82: static class CloneVisitor implements Visitor<Layout, DefaultLayout>
83: {
84: private DefaultLayout rootLayout;
85:
86: private final Deque<DefaultLayout> layoutStack = new ArrayDeque<>();
87:
88: @Override
89: public void preVisit (@Nonnull final Layout layout)
90: {
91: final var clone = new DefaultLayout(((DefaultLayout)layout).id,
92: ((DefaultLayout)layout).typeUri);
93:
94:• if (rootLayout == null)
95: {
96: rootLayout = clone;
97: }
98: else
99: {
100: layoutStack.peek().add(clone);
101: }
102:
103: layoutStack.push(clone);
104: }
105:
106: @Override
107: public void postVisit (@Nonnull final Layout layout)
108: {
109: layoutStack.pop();
110: }
111:
112: @Override @Nonnull
113: public Optional<DefaultLayout> getValue()
114: {
115: return Optional.of(rootLayout);
116: }
117: }
118:
119: /*******************************************************************************************************************
120: *
121: *
122: *
123: ******************************************************************************************************************/
124: public DefaultLayout()
125: {
126: this.id = new Id("");
127: this.typeUri = "";
128: }
129:
130: /** Clone - FIXME: public only for InfoglueImporter */
131: /*******************************************************************************************************************
132: *
133: *
134: *
135: ******************************************************************************************************************/
136: public DefaultLayout (@Nonnull final Id id, @Nonnull final String typeUri)
137: {
138: this.id = id;
139: this.typeUri = typeUri;
140: }
141:
142: /*******************************************************************************************************************
143: *
144: *
145: *
146: ******************************************************************************************************************/
147: public DefaultLayout (@Nonnull final Builder builder)
148: {
149: this.id = builder.getId();
150: this.typeUri = builder.getType();
151: }
152:
153: /*******************************************************************************************************************
154: *
155: * {@inheritDoc}
156: *
157: ******************************************************************************************************************/
158: @Override @Nonnull
159: public DefaultLayout clone()
160: {
161: return accept(new CloneVisitor()).orElseThrow(RuntimeException::new);
162: }
163:
164: /*******************************************************************************************************************
165: *
166: * {@inheritDoc}
167: *
168: ******************************************************************************************************************/
169: @Override @Nonnull
170: public Layout withOverride (@Nonnull final Layout override)
171: {
172: final var result = clone();
173: result.applyOverride(((DefaultLayout)override).clone());
174: return result;
175: }
176:
177: /*******************************************************************************************************************
178: *
179: * {@inheritDoc}
180: *
181: ******************************************************************************************************************/
182: @Override @Nonnull
183: public Layout withChild (@Nonnull final Layout layout)
184: {
185: final var clone = clone();
186: clone.children.add(layout);
187: clone.childrenMapById.put(layout.getId(), layout);
188:
189: return clone;
190: }
191:
192: /*******************************************************************************************************************
193: *
194: * {@inheritDoc}
195: *
196: ******************************************************************************************************************/
197: @Override @Nonnull
198: public LayoutFinder findChildren()
199: {
200: return new DefaultLayoutFinder(children, childrenMapById);
201: }
202:
203: /*******************************************************************************************************************
204: *
205: * {@inheritDoc}
206: *
207: ******************************************************************************************************************/
208: public void add (@Nonnull final Layout layout) // FIXME: drop this - used only by the CloneVisitor and Infoglue converter
209: {
210: children.add(layout); // FIXME: clone
211: childrenMapById.put(layout.getId(), layout);// FIXME: clone
212: }
213:
214: /*******************************************************************************************************************
215: *
216: * {@inheritDoc}
217: *
218: ******************************************************************************************************************/
219: @Override @Nonnull
220: public ViewAndController createViewAndController (@Nonnull final SiteNode siteNode)
221: throws NotFoundException, HttpStatusException
222: {
223: return viewFactory.createViewAndController(typeUri, id, siteNode);
224: }
225:
226: /*******************************************************************************************************************
227: *
228: * {@inheritDoc}
229: *
230: ******************************************************************************************************************/
231: @Override @Nonnull // TODO: push up to CompositeSupport
232: public <T> Optional<T> accept (@Nonnull final Visitor<? super Layout, T> visitor)
233: {
234: visitor.preVisit(this);
235: visitor.visit(this);
236:
237: for (final var child : children)
238: {
239: child.accept(visitor);
240: }
241:
242: visitor.postVisit(this);
243: return visitor.getValue();
244: }
245:
246: /*******************************************************************************************************************
247: *
248: * {@inheritDoc}
249: *
250: ******************************************************************************************************************/
251: @Override @Nonnull
252: public String toString()
253: {
254: return String.format("DefaultLayout(id=%s, typeUri=%s, children.count=%d)", id, typeUri, children.size());
255: }
256:
257: /*******************************************************************************************************************
258: *
259: *
260: *
261: ******************************************************************************************************************/
262: // Here everything is already cloned
263: private void applyOverride (@Nonnull final Layout override)
264: {
265: final var sameType = this.getTypeUri().equals(override.getTypeUri());
266: this.typeUri = override.getTypeUri(); // FIXME: don't like this approach, as it requires typeUri non final
267:
268: // Complex rule, but it's to keep compatibility with Infoglue.
269: if (sameType)
270: {
271: for (final var overridingChild : override.findChildren().results())
272: {
273: final var overriddenChild = childrenMapById.get(overridingChild.getId());
274:
275: if (overriddenChild == null)
276: {
277: add(overridingChild);
278: }
279: else
280: {
281: childrenMapById.put(overridingChild.getId(), overridingChild);
282: final var i = children.indexOf(overriddenChild);
283:
284: if (i < 0)
285: {
286: throw new IllegalArgumentException();
287: }
288:
289: children.set(i, overridingChild);
290: // ((DefaultLayout)overriddenChild).applyOverride(overridingChild);
291: }
292: }
293: }
294: else
295: {
296: this.children.clear();
297: this.childrenMapById.clear();
298:
299: for (final var overridingChild : override.findChildren().results())
300: {
301: add(overridingChild);
302: }
303: }
304: }
305: }