001/*
002 *  Copyright 2018 Anyware Services
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 */
016package org.ametys.plugins.ugc.page;
017
018import java.util.ArrayList;
019import java.util.Collections;
020import java.util.List;
021import java.util.Set;
022import java.util.stream.Collectors;
023
024import org.ametys.cms.repository.Content;
025import org.ametys.plugins.explorer.resources.ResourceCollection;
026import org.ametys.plugins.repository.AmetysObject;
027import org.ametys.plugins.repository.AmetysObjectIterable;
028import org.ametys.plugins.repository.AmetysObjectResolver;
029import org.ametys.plugins.repository.AmetysRepositoryException;
030import org.ametys.plugins.repository.CollectionIterable;
031import org.ametys.plugins.repository.UnknownAmetysObjectException;
032import org.ametys.plugins.repository.data.holder.ModelLessDataHolder;
033import org.ametys.plugins.repository.data.holder.impl.DefaultModelLessDataHolder;
034import org.ametys.plugins.repository.data.repositorydata.RepositoryData;
035import org.ametys.plugins.repository.data.repositorydata.impl.MemoryRepositoryData;
036import org.ametys.plugins.repository.data.type.RepositoryModelItemType;
037import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint;
038import org.ametys.web.repository.page.Page;
039import org.ametys.web.repository.page.UnknownZoneException;
040import org.ametys.web.repository.page.Zone;
041import org.ametys.web.repository.site.Site;
042import org.ametys.web.repository.sitemap.Sitemap;
043import org.ametys.web.service.ServiceExtensionPoint;
044import org.ametys.web.skin.Skin;
045import org.ametys.web.skin.SkinsManager;
046
047
048/**
049 * Page representing a transitional page.
050 */
051public class UGCTransitionalPage implements Page
052{
053    private static final String __UGC_TRANSITIONAL_PAGE_TEMPLATE = "ugc-transitional-page";
054    
055    private Page _root;
056    private String _path;
057    private String _title;
058    private String _metadataValue;
059    private AmetysObjectResolver _resolver;
060    private UGCPageHandler _ugcPageHandler;
061    private SkinsManager _skinsManager;
062
063    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _pageDataTypeExtensionPoint;
064    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneDataTypeExtensionPoint;
065    private ServiceExtensionPoint _serviceExtensionPoint;
066    private AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> _zoneItemDataTypeExtensionPoint;
067    
068    /**
069     * Constructor.
070     * @param root the user directory root page.
071     * @param title the page's title.
072     * @param metadataValue the metadata value
073     * @param resolver the {@link AmetysObjectResolver}.
074     * @param path the path
075     * @param userDirectoryPageHandler the user directory page handler component
076     * @param skinsManager the skins manager
077     * @param pageDataTypeExtensionPoint the extension point with available data types for pages
078     * @param zoneDataTypeExtensionPoint the extension point with available data types for zones
079     * @param serviceExtensionPoint the service extension point
080     * @param zoneItemDataTypeExtensionPoint the extension point with available data types for zone items
081     */
082    public UGCTransitionalPage(Page root, String title, String metadataValue, String path, AmetysObjectResolver resolver, UGCPageHandler userDirectoryPageHandler, SkinsManager skinsManager, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> pageDataTypeExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneDataTypeExtensionPoint, ServiceExtensionPoint serviceExtensionPoint, AbstractThreadSafeComponentExtensionPoint<RepositoryModelItemType> zoneItemDataTypeExtensionPoint)
083    {
084        _root = root;
085        _title = title;
086        _metadataValue = metadataValue;
087        _path = path;
088        _resolver = resolver;
089        _ugcPageHandler = userDirectoryPageHandler;
090        _skinsManager = skinsManager;
091        
092        _pageDataTypeExtensionPoint = pageDataTypeExtensionPoint;
093        _zoneDataTypeExtensionPoint = zoneDataTypeExtensionPoint;
094        _serviceExtensionPoint = serviceExtensionPoint;
095        _zoneItemDataTypeExtensionPoint = zoneItemDataTypeExtensionPoint;
096    }
097    
098    @Override
099    public int getDepth() throws AmetysRepositoryException
100    {
101        return _root.getDepth() + 1;
102    }
103
104    @Override
105    public Set<String> getReferers() throws AmetysRepositoryException
106    {
107        return null;
108    }
109
110    @Override
111    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
112    {
113        return null;
114    }
115
116    @Override
117    public String getTemplate() throws AmetysRepositoryException
118    {
119        Skin skin = _skinsManager.getSkin(getSite().getSkinId());
120        
121        if (skin.getTemplate(__UGC_TRANSITIONAL_PAGE_TEMPLATE) != null)
122        {
123            return __UGC_TRANSITIONAL_PAGE_TEMPLATE;
124        }
125        
126        return "page"; 
127    }
128
129    @Override
130    public String getTitle() throws AmetysRepositoryException
131    {
132        return _title;
133    }
134    
135    @Override
136    public String getLongTitle() throws AmetysRepositoryException
137    {
138        return _title;
139    }
140
141    @Override
142    public PageType getType() throws AmetysRepositoryException
143    {
144        return PageType.CONTAINER;
145    }
146
147    @Override
148    public String getURL() throws AmetysRepositoryException
149    {
150        throw new UnsupportedOperationException("getURL not supported on virtual ugc transitional pages");
151    }
152
153    @Override
154    public LinkType getURLType() throws AmetysRepositoryException
155    {
156        throw new UnsupportedOperationException("getURLType not supported on virtual ugc transitional pages");
157    }
158
159    @Override
160    public Zone getZone(String name) throws UnknownZoneException, AmetysRepositoryException
161    {
162        if (!"default".equals(name))
163        {
164            throw new IllegalArgumentException("Only the zone named 'default' is actually supported on virtual ugc transitional pages.");
165        }
166        
167        return new UGCTransitionalZone(this, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint);
168    }
169
170    @Override
171    public AmetysObjectIterable< ? extends Zone> getZones() throws AmetysRepositoryException
172    {
173        List<Zone> zones = new ArrayList<>();
174        zones.add(new UGCTransitionalZone(this, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint));
175        return new CollectionIterable<>(zones);
176    }
177
178    @Override
179    public boolean hasZone(String name) throws AmetysRepositoryException
180    {
181        return "default".equals(name);
182    }
183
184    @Override
185    public AmetysObjectIterable<? extends Page> getChildrenPages() throws AmetysRepositoryException
186    {
187        ArrayList<Page> children = new ArrayList<>();
188        
189        AmetysObjectIterable<Content> contentsForTransitionalPage = _ugcPageHandler.getContentsForTransitionalPage(_root, _metadataValue);
190        for (Content content : contentsForTransitionalPage)
191        {
192            children.add(new UGCPage(_root, content, _path, _resolver, _ugcPageHandler, _skinsManager, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint));
193        }
194        
195        return new CollectionIterable<>(children);
196    }
197
198    @Override
199    public AmetysObjectIterable< ? extends Page> getChildrenPages(boolean includeInvisiblePage) throws AmetysRepositoryException
200    {
201        if (includeInvisiblePage)
202        {
203            return getChildrenPages();
204        }
205        else
206        {
207            ArrayList<Page> children = new ArrayList<>();
208            return new CollectionIterable<>(children);
209        }
210    }
211    
212    @Override
213    public String getPathInSitemap() throws AmetysRepositoryException
214    {
215        return _root.getPathInSitemap() + "/" + _path;
216    }
217
218    @Override
219    public Site getSite() throws AmetysRepositoryException
220    {
221        return _root.getSite();
222    }
223
224    @Override
225    public String getSiteName() throws AmetysRepositoryException
226    {
227        return _root.getSiteName();
228    }
229
230    @Override
231    public Sitemap getSitemap() throws AmetysRepositoryException
232    {
233        return _root.getSitemap();
234    }
235
236    @Override
237    public String getSitemapName() throws AmetysRepositoryException
238    {
239        return _root.getSitemapName();
240    }
241
242    @SuppressWarnings("unchecked")
243    @Override
244    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
245    {
246        if (path.isEmpty())
247        {
248            throw new AmetysRepositoryException("path must be non empty");
249        }
250        
251        String name = path;
252        AmetysObjectIterable<Content> contentsForTransitionalPage = _ugcPageHandler.getContentsForTransitionalPage(_root, _metadataValue);
253        List<Content> contentFilters = contentsForTransitionalPage.stream().filter(c -> c.getName().equals(name)).collect(Collectors.toList());
254        if (!contentFilters.isEmpty())
255        {
256            Content content = contentFilters.get(0);
257            return (A) new UGCPage(_root, content, _path, _resolver, _ugcPageHandler, _skinsManager, _pageDataTypeExtensionPoint, _zoneDataTypeExtensionPoint, _serviceExtensionPoint, _zoneItemDataTypeExtensionPoint);
258        }
259        else
260        {
261            throw new UnknownAmetysObjectException("No ugc page for path " + path);
262        }
263    }
264
265    @SuppressWarnings("unchecked")
266    @Override
267    public AmetysObjectIterable<? extends AmetysObject> getChildren() throws AmetysRepositoryException
268    {
269        return getChildrenPages();
270    }
271
272    @Override
273    public boolean hasChild(String name) throws AmetysRepositoryException
274    {
275        AmetysObjectIterable<Content> contentsForTransitionalPage = _ugcPageHandler.getContentsForTransitionalPage(_root, _metadataValue);
276        List<Content> contentFilters = contentsForTransitionalPage.stream().filter(c -> c.getName().equals(name)).collect(Collectors.toList());
277        return !contentFilters.isEmpty();
278    }
279    
280    @Override
281    public String getId() throws AmetysRepositoryException
282    {
283        // E.g: ugctransitional://path?rootId=...
284        return "ugctransitional://" + _path + "?rootId=" + _root.getId();
285    }
286
287    @Override
288    public String getName() throws AmetysRepositoryException
289    {
290        return _path;
291    }
292    
293    @SuppressWarnings("unchecked")
294    @Override
295    public Page getParent() throws AmetysRepositoryException
296    {
297        return _root;
298    }
299
300    @Override
301    public String getParentPath() throws AmetysRepositoryException
302    {
303        return _root.getPath();
304    }
305
306    @Override
307    public String getPath() throws AmetysRepositoryException
308    {
309        return getParentPath() + "/" + getName();
310    }
311
312    public ModelLessDataHolder getDataHolder()
313    {
314        RepositoryData repositoryData = new MemoryRepositoryData(getName());
315        return new DefaultModelLessDataHolder(_pageDataTypeExtensionPoint, repositoryData);
316    }
317
318    @Override
319    public Set<String> getTags() throws AmetysRepositoryException
320    {
321        return Collections.emptySet();
322    }
323
324    @Override
325    public boolean isVisible() throws AmetysRepositoryException
326    {
327        return false;
328    }
329
330    @Override
331    public Page getChildPageAt(int index) throws UnknownAmetysObjectException, AmetysRepositoryException
332    {
333        return getChildrenPages().stream().collect(Collectors.toList()).get(index);
334    }
335}