001/*
002 *  Copyright 2010 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.web.repository.content.jcr;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Set;
021
022import javax.jcr.Node;
023import javax.jcr.PropertyIterator;
024import javax.jcr.RepositoryException;
025
026import org.ametys.cms.repository.DefaultContent;
027import org.ametys.cms.repository.DefaultWorkflowAwareContent;
028import org.ametys.cms.repository.ModifiableContent;
029import org.ametys.plugins.explorer.resources.ResourceCollection;
030import org.ametys.plugins.repository.AmetysObject;
031import org.ametys.plugins.repository.AmetysObjectIterable;
032import org.ametys.plugins.repository.AmetysRepositoryException;
033import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
034import org.ametys.plugins.repository.RepositoryIntegrityViolationException;
035import org.ametys.plugins.repository.UnknownAmetysObjectException;
036import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
037import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
038import org.ametys.plugins.repository.jcr.NodeTypeHelper;
039import org.ametys.plugins.repository.tag.TagAwareAmetysObject;
040import org.ametys.plugins.repository.version.VersionableAmetysObject;
041import org.ametys.web.repository.content.ModifiableWebContent;
042import org.ametys.web.repository.content.WebContent;
043import org.ametys.web.repository.page.Page;
044import org.ametys.web.repository.page.ZoneItem;
045import org.ametys.web.repository.site.Site;
046
047/**
048 * {@link DefaultContent} which is {@link TagAwareAmetysObject}.
049 * @param <F> the actual type of factory.
050 */
051public class DefaultWebContent<F extends DefaultWebContentFactory> extends DefaultContent<F> implements WebContent
052{
053    /**
054     * Creates a {@link DefaultWebContent}.
055     * @param node the node backing this {@link DefaultWebContent}.
056     * @param parentPath the parent path in the Ametys hierarchy.
057     * @param factory the {@link DefaultWebContentFactory} which creates the AmetysObject.
058     */
059    public DefaultWebContent(Node node, String parentPath, F factory)
060    {
061        super(node, parentPath, factory);
062    }
063
064    @Override
065    public ModifiableContent copyTo(ModifiableTraversableAmetysObject parent, String name) throws AmetysRepositoryException
066    {
067        return copyTo(parent, name, 0, false);
068    }
069    
070    /**
071     * Copy the current {@link DefaultWorkflowAwareContent} to the given object. Be careful, this method save changes, but do not create a new version (checkpoint)
072     * @param parent The parent of the new object. Can not be null.
073     * @param name Name of the new object. Can be null. If null, the new name will be get from the copied object.
074     * @param initWorkflowActionId The initial workflow action id
075     * @param checkpoint true to check the content in if it is versionable
076     * @return the created object
077     * @throws AmetysRepositoryException if an error occurs.
078     */
079    public ModifiableContent copyTo(ModifiableTraversableAmetysObject parent, String name, int initWorkflowActionId, boolean checkpoint) throws AmetysRepositoryException
080    {
081        ModifiableContent cContent = super.copyTo(parent, name, 0, false, false);
082        
083        if (cContent instanceof ModifiableWebContent modifiableContent)
084        {
085            modifiableContent.setSiteName(getSiteName());
086            
087            // Copy tags
088            Set<String> tags = getTags();
089            for (String tag : tags)
090            {
091                modifiableContent.tag(tag);
092            }
093            
094            cContent.saveChanges();
095            
096            // Create a new version
097            if (checkpoint && modifiableContent instanceof VersionableAmetysObject versionableContent)
098            {
099                versionableContent.checkpoint();
100            }
101        }
102        
103        return cContent;
104    }
105
106    @Override
107    public Collection<Page> getReferencingPages()
108    {
109        ArrayList<Page> pages = new ArrayList<>();
110        try
111        {
112            PropertyIterator itReferences = getNode().getReferences();
113            
114            while (itReferences.hasNext())
115            {
116                Node refererNode = itReferences.nextProperty().getParent();
117                
118                if (NodeTypeHelper.isNodeType(refererNode, "ametys:zoneItem"))
119                {
120                    // /page/ametys-internal:zones/default/ametys-internal:zoneItems/ametys:zoneItem
121                    Node pageNode = refererNode.getParent().getParent().getParent().getParent();
122                    Page page = _getFactory().resolveAmetysObject(pageNode);
123                    pages.add(page);
124                }
125            }
126        }
127        catch (RepositoryException e)
128        {
129            throw new AmetysRepositoryException("Unable to resolve references for content " + getId(), e);
130        }
131        
132        return pages;
133    }
134    
135    @Override
136    public Collection<ZoneItem> getReferencingZoneItems()
137    {
138        ArrayList<ZoneItem> zoneItems = new ArrayList<>();
139        try
140        {
141            PropertyIterator itReferences = getNode().getReferences();
142            
143            while (itReferences.hasNext())
144            {
145                Node refererNode = itReferences.nextProperty().getParent();
146                
147                if (NodeTypeHelper.isNodeType(refererNode, "ametys:zoneItem"))
148                {
149                    ZoneItem zoneItem = _getFactory().resolveAmetysObject(refererNode);
150                    zoneItems.add(zoneItem);
151                }
152            }
153        }
154        catch (RepositoryException e)
155        {
156            throw new AmetysRepositoryException("Unable to resolve references for content " + getId(), e);
157        }
158        
159        return zoneItems;
160    }
161    
162    @Override
163    public ResourceCollection getRootAttachments() throws AmetysRepositoryException
164    {
165        ResourceCollection attachments = null;
166        
167        if (hasChild(ATTACHMENTS_NODE_NAME))
168        {
169            attachments = getChild(ATTACHMENTS_NODE_NAME);
170        }
171        
172        return attachments;
173    }
174    
175    @Override
176    public Site getSite()
177    {
178        return _getFactory().getSite(getSiteName());
179    }
180    
181    @Override
182    public String getSiteName()
183    {
184        // TODO CMS-9336 this metadata should be stored as internal using data holders
185        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
186        return repositoryData.getString(METADATA_SITE);
187    }
188    
189    @Override
190    public boolean hasChild(String name) throws AmetysRepositoryException
191    {
192        return _getFactory().hasChild(this, name);
193    }
194    
195    @SuppressWarnings("unchecked")
196    @Override
197    public <A extends AmetysObject> A createChild(String name, String type) throws AmetysRepositoryException, RepositoryIntegrityViolationException
198    {
199        return (A) _getFactory().createChild(this, name, type);
200    }
201    
202    @SuppressWarnings("unchecked")
203    @Override
204    public <A extends AmetysObject> A getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
205    {
206        return (A) _getFactory().getChild(this, path);
207    }
208    
209    @Override
210    public <A extends AmetysObject> AmetysObjectIterable<A> getChildren() throws AmetysRepositoryException
211    {
212        return _getFactory().getChildren(this);
213    }
214    
215    public String getPrivacyLevel()
216    {
217        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
218        if (repositoryData.hasValue(PROPERTY_PRIVACY))
219        {
220            return repositoryData.getString(PROPERTY_PRIVACY);
221        }
222        else
223        {
224            Site site = getSite();
225            return site.getValue("content-privacy", true, null);
226        }
227    }
228}