001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Anahide Tchertchian
018 */
019package org.nuxeo.theme.styling.service.descriptors;
020
021import java.util.ArrayList;
022import java.util.List;
023
024import org.apache.commons.lang3.builder.EqualsBuilder;
025import org.nuxeo.common.xmap.annotation.XNode;
026import org.nuxeo.common.xmap.annotation.XNodeList;
027import org.nuxeo.common.xmap.annotation.XObject;
028import org.nuxeo.ecm.web.resources.api.ResourceBundle;
029import org.nuxeo.ecm.web.resources.api.ResourceType;
030import org.nuxeo.ecm.web.resources.core.ResourceBundleDescriptor;
031
032/**
033 * Descriptor to associate resources and flavors to a page.
034 *
035 * @since 7.4
036 */
037@XObject("page")
038public class PageDescriptor {
039
040    public static final String RESOURCE_BUNDLE_PREFIX = "pageResourceBundle_";
041
042    @XNode("@name")
043    String name;
044
045    /**
046     * @since 7.4
047     */
048    @XNode("@charset")
049    String charset;
050
051    @XNode("defaultFlavor")
052    String defaultFlavor;
053
054    /**
055     * @deprecated since 7.4: use resources instead
056     */
057    @Deprecated
058    @XNode("styles@append")
059    boolean appendStyles;
060
061    /**
062     * @deprecated since 7.4: use resources instead
063     */
064    @Deprecated
065    @XNodeList(value = "styles/style", type = ArrayList.class, componentType = String.class)
066    List<String> styles;
067
068    @XNode("flavors@append")
069    boolean appendFlavors;
070
071    @XNodeList(value = "flavors/flavor", type = ArrayList.class, componentType = String.class)
072    List<String> flavors;
073
074    @XNode("resources@append")
075    boolean appendResources;
076
077    @XNodeList(value = "resources/resource", type = ArrayList.class, componentType = String.class)
078    List<String> resources;
079
080    /**
081     * @since 7.4
082     */
083    @XNodeList(value = "resources/bundle", type = ArrayList.class, componentType = String.class)
084    List<String> bundles;
085
086    public String getName() {
087        return name;
088    }
089
090    public String getDefaultFlavor() {
091        return defaultFlavor;
092    }
093
094    public void setDefaultFlavor(String defaultFlavor) {
095        this.defaultFlavor = defaultFlavor;
096    }
097
098    /**
099     * @deprecated since 7.4: use resources instead
100     */
101    @Deprecated
102    public boolean getAppendStyles() {
103        return appendStyles;
104    }
105
106    /**
107     * @deprecated since 7.4: use resources instead
108     */
109    @Deprecated
110    public List<String> getStyles() {
111        return styles;
112    }
113
114    public boolean getAppendFlavors() {
115        return appendFlavors;
116    }
117
118    public List<String> getFlavors() {
119        return flavors;
120    }
121
122    public void setName(String name) {
123        this.name = name;
124    }
125
126    public void setStyles(List<String> styles) {
127        this.styles = styles;
128    }
129
130    public void setFlavors(List<String> flavors) {
131        this.flavors = flavors;
132    }
133
134    public boolean getAppendResources() {
135        return appendResources;
136    }
137
138    public boolean hasResources() {
139        return !getResources().isEmpty();
140    }
141
142    public List<String> getResources() {
143        List<String> res = new ArrayList<>();
144        // BBB
145        if (styles != null) {
146            for (String style : styles) {
147                if (style == null) {
148                    continue;
149                }
150                if (style.endsWith(ResourceType.css.name())) {
151                    res.add(style);
152                } else {
153                    res.add(style + "." + ResourceType.css.name());
154                }
155            }
156        }
157        if (resources != null) {
158            res.addAll(resources);
159        }
160        return res;
161    }
162
163    public void setResources(List<String> resources) {
164        this.resources = resources;
165    }
166
167    public String getComputedResourceBundleName() {
168        if ("*".equals(getName())) {
169            return RESOURCE_BUNDLE_PREFIX + "*";
170        }
171        return RESOURCE_BUNDLE_PREFIX + getName().replaceAll("[^a-zA-Z]+", "_");
172    }
173
174    public ResourceBundle getComputedResourceBundle() {
175        if (hasResources()) {
176            ResourceBundleDescriptor bundle = new ResourceBundleDescriptor();
177            bundle.setName(getComputedResourceBundleName());
178            bundle.setResources(getResources());
179            bundle.setAppend(getAppendResources());
180            return bundle;
181        }
182        return null;
183    }
184
185    /**
186     * @since 7.4
187     */
188    public List<String> getResourceBundles() {
189        List<String> all = new ArrayList<>();
190        if (bundles != null) {
191            all.addAll(bundles);
192        }
193        if (hasResources()) {
194            all.add(getComputedResourceBundleName());
195        }
196        return all;
197    }
198
199    /**
200     * @since 7.4
201     */
202    public void setResourceBundles(List<String> bundles) {
203        this.bundles = bundles;
204    }
205
206    public void setAppendStyles(boolean appendStyles) {
207        this.appendStyles = appendStyles;
208    }
209
210    public void setAppendFlavors(boolean appendFlavors) {
211        this.appendFlavors = appendFlavors;
212    }
213
214    public void setAppendResources(boolean appendResources) {
215        this.appendResources = appendResources;
216    }
217
218    /**
219     * @since 7.4
220     */
221    public String getCharset() {
222        return charset;
223    }
224
225    /**
226     * @since 7.4
227     */
228    public void setCharset(String charset) {
229        this.charset = charset;
230    }
231
232    public void merge(PageDescriptor src) {
233        String newFlavor = src.getDefaultFlavor();
234        if (newFlavor != null) {
235            setDefaultFlavor(newFlavor);
236        }
237
238        String newCharset = src.getCharset();
239        if (newCharset != null) {
240            setCharset(newCharset);
241        }
242
243        List<String> newStyles = src.getStyles();
244        if (newStyles != null) {
245            List<String> merged = new ArrayList<>();
246            merged.addAll(newStyles);
247            boolean keepOld = src.getAppendStyles() || (newStyles.isEmpty() && !src.getAppendStyles());
248            if (keepOld) {
249                // add back old contributions
250                List<String> oldStyles = getStyles();
251                if (oldStyles != null) {
252                    merged.addAll(0, oldStyles);
253                }
254            }
255            setStyles(merged);
256        }
257
258        List<String> newFlavors = src.getFlavors();
259        if (newFlavors != null) {
260            List<String> merged = new ArrayList<>();
261            merged.addAll(newFlavors);
262            boolean keepOld = src.getAppendFlavors() || (newFlavors.isEmpty() && !src.getAppendFlavors());
263            if (keepOld) {
264                // add back old contributions
265                List<String> oldFlavors = getFlavors();
266                if (oldFlavors != null) {
267                    merged.addAll(0, oldFlavors);
268                }
269            }
270            setFlavors(merged);
271        }
272
273        List<String> newResources = src.resources;
274        if (newResources != null) {
275            List<String> merged = new ArrayList<>();
276            merged.addAll(newResources);
277            boolean keepOld = src.getAppendResources() || (newResources.isEmpty() && !src.getAppendResources());
278            if (keepOld) {
279                // add back old contributions
280                List<String> oldResources = resources;
281                if (oldResources != null) {
282                    merged.addAll(0, oldResources);
283                }
284            }
285            setResources(merged);
286        }
287
288        List<String> newBundles = src.bundles;
289        if (newBundles != null) {
290            List<String> merged = new ArrayList<>();
291            merged.addAll(newBundles);
292            boolean keepOld = src.getAppendResources() || (newBundles.isEmpty() && !src.getAppendResources());
293            if (keepOld) {
294                // add back old contributions
295                List<String> oldBundles = bundles;
296                if (oldBundles != null) {
297                    merged.addAll(0, oldBundles);
298                }
299            }
300            setResourceBundles(merged);
301        }
302    }
303
304    @Override
305    public PageDescriptor clone() {
306        PageDescriptor clone = new PageDescriptor();
307        clone.setName(getName());
308        clone.setCharset(getCharset());
309        clone.setDefaultFlavor(getDefaultFlavor());
310        clone.setAppendStyles(getAppendStyles());
311        List<String> styles = getStyles();
312        if (styles != null) {
313            clone.setStyles(new ArrayList<>(styles));
314        }
315        clone.setAppendFlavors(getAppendFlavors());
316        List<String> flavors = getFlavors();
317        if (flavors != null) {
318            clone.setFlavors(new ArrayList<>(flavors));
319        }
320        clone.setAppendResources(getAppendResources());
321        if (resources != null) {
322            clone.setResources(new ArrayList<>(resources));
323        }
324        if (bundles != null) {
325            clone.setResourceBundles(new ArrayList<>(bundles));
326        }
327        return clone;
328    }
329
330    @Override
331    public boolean equals(Object obj) {
332        if (!(obj instanceof PageDescriptor)) {
333            return false;
334        }
335        if (obj == this) {
336            return true;
337        }
338        PageDescriptor p = (PageDescriptor) obj;
339        return new EqualsBuilder().append(name, p.name).append(charset, p.charset).append(defaultFlavor,
340                p.defaultFlavor).append(appendStyles, p.appendStyles).append(styles, p.styles).append(appendFlavors,
341                p.appendFlavors).append(flavors, p.flavors).append(appendResources, p.appendResources).append(
342                resources, p.resources).append(bundles, p.bundles).isEquals();
343    }
344
345}