Package: DefaultSiteNode
DefaultSiteNode
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DefaultSiteNode(ModelFactory, InternalSite, ResourceFile) |
|
|
|
|
|
||||||||||||||||||||
findChildren() |
|
|
|
|
|
||||||||||||||||||||
getLayout() |
|
|
|
|
|
||||||||||||||||||||
getParent() |
|
|
|
|
|
||||||||||||||||||||
getRelativeUri() |
|
|
|
|
|
||||||||||||||||||||
getSite() |
|
|
|
|
|
||||||||||||||||||||
loadLayout(ResourceFile) |
|
|
|
|
|
||||||||||||||||||||
loadLayouts() |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
||||||||||||||||||||
toString() |
|
|
|
|
|
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.core.impl.model;
28:
29: import javax.annotation.CheckForNull;
30: import javax.annotation.Nonnull;
31: import javax.inject.Inject;
32: import java.util.HashMap;
33: import java.util.Locale;
34: import java.util.Map;
35: import java.io.IOException;
36: import org.springframework.beans.factory.annotation.Configurable;
37: import it.tidalwave.util.Finder;
38: import it.tidalwave.util.Id;
39: import it.tidalwave.util.NotFoundException;
40: import it.tidalwave.northernwind.core.model.ModelFactory;
41: import it.tidalwave.northernwind.core.model.RequestLocaleManager;
42: import it.tidalwave.northernwind.core.model.ResourceFile;
43: import it.tidalwave.northernwind.core.model.ResourcePath;
44: import it.tidalwave.northernwind.core.model.SiteNode;
45: import it.tidalwave.northernwind.core.model.spi.SiteNodeSupport;
46: import it.tidalwave.northernwind.frontend.ui.Layout;
47: import it.tidalwave.northernwind.frontend.impl.ui.DefaultLayout;
48: import it.tidalwave.northernwind.frontend.impl.ui.LayoutLoggerVisitor;
49: import lombok.Cleanup;
50: import lombok.Getter;
51: import lombok.ToString;
52: import lombok.extern.slf4j.Slf4j;
53: import static it.tidalwave.role.io.Unmarshallable._Unmarshallable_;
54: import static it.tidalwave.northernwind.util.UrlEncoding.decodedUtf8;
55:
56: /***********************************************************************************************************************
57: *
58: * A node of the site, mapped to a given URL.
59: *
60: * @author Fabrizio Giudici
61: *
62: **********************************************************************************************************************/
63: @Configurable(preConstruction = true) @Slf4j @ToString(callSuper = false, of = "relativeUri")
64: /* package */ class DefaultSiteNode extends SiteNodeSupport
65: {
66: @Nonnull
67: private final Map<Locale, Layout> layoutMapByLocale = new HashMap<>();
68:
69: @Getter @Nonnull
70: final /* package */ InternalSite site;
71:
72: @Inject
73: private InheritanceHelper inheritanceHelper;
74:
75: @Inject
76: private RequestLocaleManager localeRequestManager;
77:
78: @CheckForNull
79: private ResourcePath relativeUri;
80:
81: /* package */ int uriComputationCounter;
82:
83: /*******************************************************************************************************************
84: *
85: * Creates a new instance with the given configuration file and mapped to the given URI.
86: *
87: * @param file the file with the configuration
88: * @param relativeUri the bound URI
89: *
90: ******************************************************************************************************************/
91: public DefaultSiteNode (@Nonnull final ModelFactory modelFactory,
92: @Nonnull final InternalSite site,
93: @Nonnull final ResourceFile file)
94: {
95:• super(modelFactory, file);
96: this.site = site;
97: try
98: {
99: loadLayouts();
100: }
101: catch (IOException e)
102: {
103: throw new RuntimeException(e);
104: }
105:• }
106:
107: /*******************************************************************************************************************
108: *
109: * {@inheritDoc}
110: *
111: ******************************************************************************************************************/
112: @Nonnull @Override
113: public synchronized ResourcePath getRelativeUri()
114: {
115:• if (relativeUri == null) // FIXME: is lazy evaluation really needed?
116: {
117: uriComputationCounter++;
118:
119: relativeUri = ResourcePath.EMPTY;
120: final var file = getResource().getFile();
121:
122:• if (!file.equals(site.getNodeFolder()))
123: {
124: try
125: {
126: final var segment = getResource().getProperty(P_EXPOSED_URI).orElse(decodedUtf8(file.getName()));
127: relativeUri = relativeUri.appendedWith(getParent().getRelativeUri()).appendedWith(segment);
128: }
129: catch (NotFoundException e) // FIXME: for getParent()
130: {
131: log.error("", e); // should never occur
132: throw new RuntimeException(e);
133: }
134: }
135: }
136:
137: log.trace(">>>> relativeUri: {}", relativeUri);
138:
139: return relativeUri;
140: }
141:
142: /*******************************************************************************************************************
143: *
144: * {@inheritDoc}
145: *
146: ******************************************************************************************************************/
147: @Override @Nonnull
148: public Layout getLayout()
149: {
150: return layoutMapByLocale.get(localeRequestManager.getLocales().get(0));
151: }
152:
153: /*******************************************************************************************************************
154: *
155: * {@inheritDoc}
156: *
157: ******************************************************************************************************************/
158: @Override @Nonnull
159: public Finder<SiteNode> findChildren()
160: {
161: throw new UnsupportedOperationException("Not supported yet.");
162: }
163:
164: /*******************************************************************************************************************
165: *
166: * {@inheritDoc}
167: *
168: ******************************************************************************************************************/
169: private void loadLayouts()
170: throws IOException
171: {
172:• for (final var locale : localeRequestManager.getLocales())
173: {
174: Layout layout = null;
175: // Cannot be implemented by recursion, since each SiteNode could have a local override for its Layout -
176: // local overrides are not inherited. Perhaps you could do if you keep two layouts per Node, one without the override.
177: // On the other hand, inheritanceHelper encapsulates the local override policy, which applies also to Properties...
178: final var layoutFiles = inheritanceHelper.getInheritedPropertyFiles(getResource().getFile(),
179: locale,
180: "Components");
181:• for (final var layoutFile : layoutFiles)
182: {
183: final var overridingLayout = loadLayout(layoutFile);
184:• layout = (layout == null) ? overridingLayout : layout.withOverride(overridingLayout);
185:
186:• if (log.isDebugEnabled())
187: {
188: overridingLayout.accept(new LayoutLoggerVisitor(LayoutLoggerVisitor.Level.DEBUG));
189: }
190: }
191:
192:• layout = (layout != null) ? layout : modelFactory.createLayout()
193: .withId(new Id(""))
194: .withType("emptyPlaceholder")
195: .build();
196:
197:• if (site.isLogConfigurationEnabled() || log.isDebugEnabled())
198: {
199: log.debug(">>>> layout for {} {}:", getResource().getFile().getPath().asString(), locale);
200: layout.accept(new LayoutLoggerVisitor(LayoutLoggerVisitor.Level.INFO));
201: }
202:
203: layoutMapByLocale.put(locale, layout);
204: }
205: }
206:
207: /*******************************************************************************************************************
208: *
209: * Returns the parent {@code SiteNode}.
210: *
211: * @return the parent node
212: * @throws NotFoundException if the parent doesn't exist
213: *
214: ******************************************************************************************************************/
215: @Nonnull
216: private SiteNode getParent()
217: throws NotFoundException
218: {
219: final var parentRelativePath = getResource().getFile().getParent().getPath().urlDecoded()
220: .relativeTo(site.getNodeFolder().getPath());
221:
222: return site.find(_SiteNode_).withRelativePath(parentRelativePath).result();
223: }
224:
225: /*******************************************************************************************************************
226: *
227: ******************************************************************************************************************/
228: @Nonnull
229: private DefaultLayout loadLayout (@Nonnull final ResourceFile layoutFile)
230: throws IOException
231: {
232: log.trace(">>>> reading layout from {}...", layoutFile.getPath().asString());
233:• @Cleanup final var is = layoutFile.getInputStream();
234: return modelFactory.createLayout().build().as(_Unmarshallable_).unmarshal(is);
235: }
236: }