001/*
002 *  Copyright 2012 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.time.ZonedDateTime;
019import java.util.Collection;
020import java.util.Date;
021import java.util.List;
022import java.util.Locale;
023import java.util.Map;
024
025import javax.jcr.Node;
026
027import org.ametys.cms.content.references.OutgoingReferences;
028import org.ametys.cms.contenttype.ContentType;
029import org.ametys.cms.data.holder.ModifiableIndexableDataHolder;
030import org.ametys.cms.repository.ModifiableContentDataHolder;
031import org.ametys.cms.repository.ModifiableWorkflowAwareContent;
032import org.ametys.cms.repository.WorkflowAwareContentHelper;
033import org.ametys.cms.repository.comment.Comment;
034import org.ametys.cms.repository.comment.CommentableContent;
035import org.ametys.cms.repository.comment.contributor.ContributorCommentableContent;
036import org.ametys.core.user.UserIdentity;
037import org.ametys.plugins.repository.AmetysRepositoryException;
038import org.ametys.plugins.repository.RepositoryIntegrityViolationException;
039import org.ametys.plugins.repository.data.extractor.xml.XMLValuesExtractorAdditionalDataGetter;
040import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
041import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
042import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
043import org.ametys.plugins.repository.jcr.DublinCoreHelper;
044import org.ametys.plugins.repository.lock.LockableAmetysObject;
045import org.ametys.plugins.repository.tag.TaggableAmetysObjectHelper;
046import org.ametys.web.repository.content.ModifiableWebContent;
047
048/**
049 * Modifiable version of {@link DefaultWebContent}.
050 * @param <F> the actual type of factory.
051 */
052public class ModifiableDefaultWebContent<F extends ModifiableDefaultWebContentFactory> extends DefaultWebContent<F> implements ModifiableWebContent, ModifiableWorkflowAwareContent, LockableAmetysObject, CommentableContent, ContributorCommentableContent//, CopiableAmetysObject, JCRTraversableAmetysObject
053{
054    private boolean _lockAlreadyChecked;
055    
056    /**
057     * Creates a {@link ModifiableDefaultWebContent}.
058     * @param node the node backing this {@link ModifiableDefaultWebContent}.
059     * @param parentPath the parent path in the Ametys hierarchy.
060     * @param factory the {@link DefaultWebContentFactory} which creates the AmetysObject.
061     */
062    public ModifiableDefaultWebContent(Node node, String parentPath, F factory)
063    {
064        super(node, parentPath, factory);
065    }
066    
067    // Workflow management.
068    
069    @Override
070    public long getWorkflowId() throws AmetysRepositoryException
071    {
072        return WorkflowAwareContentHelper.getWorkflowId(this);
073    }
074    
075    @Override
076    public void setWorkflowId(long workflowId) throws AmetysRepositoryException
077    {
078        WorkflowAwareContentHelper.setWorkflowId(this, workflowId);
079    }
080    
081    @Override
082    public long getCurrentStepId() throws AmetysRepositoryException
083    {
084        return WorkflowAwareContentHelper.getCurrentStepId(this);
085    }
086    
087    @Override
088    public void setCurrentStepId (long stepId) throws AmetysRepositoryException
089    {
090        WorkflowAwareContentHelper.setCurrentStepId(this, stepId);
091    }
092    
093    @Override
094    public ZonedDateTime getProposalDate() throws AmetysRepositoryException
095    {
096        return WorkflowAwareContentHelper.getProposalDate(this);
097    }
098    
099    @Override
100    public void setProposalDate(ZonedDateTime proposalDate) throws AmetysRepositoryException
101    {
102        WorkflowAwareContentHelper.setProposalDate(this, proposalDate);
103    }
104    
105    @Override
106    public void remove() throws AmetysRepositoryException, RepositoryIntegrityViolationException
107    {
108        _getFactory().getSharedContentManager().switchSharedContentReferences(this);
109        super.remove();
110    }
111
112    @Override
113    public void setSiteName(String siteName)
114    {
115        setLockInfoOnCurrentContext();
116        
117        // TODO CMS-9336 this metadata should be stored as internal using data holders
118        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
119        repositoryData.setValue(METADATA_SITE, siteName);
120    }
121    
122    @Override
123    public void setPrivacyLevel(String privacy)
124    {
125        setLockInfoOnCurrentContext();
126        
127        ModifiableRepositoryData repositoryData = new JCRRepositoryData(getNode());
128        repositoryData.setValue(PROPERTY_PRIVACY, privacy);
129    }
130    
131    @Override
132    public void setTitle(String title, Locale locale) throws AmetysRepositoryException
133    {
134        _getFactory().getModifiableContentHelper().setTitle(this, title, locale);
135    }
136    
137    @Override
138    @Deprecated
139    public void setTitle(String title) throws AmetysRepositoryException
140    {
141        _getFactory().getModifiableContentHelper().setTitle(this, title);
142    }
143    
144    public void setCreator(UserIdentity user) throws AmetysRepositoryException
145    {
146        _getFactory().getModifiableContentHelper().setCreator(this, user);
147    }
148    
149    public void setCreationDate(ZonedDateTime creationDate) throws AmetysRepositoryException
150    {
151        _getFactory().getModifiableContentHelper().setCreationDate(this, creationDate);
152    }
153    
154    public void setLastContributor(UserIdentity user)
155    {
156        _getFactory().getModifiableContentHelper().setLastContributor(this, user);
157    }
158    
159    public void setLastModified(ZonedDateTime lastModified) throws AmetysRepositoryException
160    {
161        _getFactory().getModifiableContentHelper().setLastModified(this, lastModified);
162    }
163    
164    public void setFirstValidator(UserIdentity user) throws AmetysRepositoryException
165    {
166        _getFactory().getModifiableContentHelper().setFirstValidator(this, user);
167    }
168    
169    @Override
170    public void setFirstValidationDate(ZonedDateTime validationDate) throws AmetysRepositoryException
171    {
172        _getFactory().getModifiableContentHelper().setFirstValidationDate(this, validationDate);
173    }
174    
175    public void setLastValidator(UserIdentity user) throws AmetysRepositoryException
176    {
177        _getFactory().getModifiableContentHelper().setLastValidator(this, user);
178    }
179    
180    @Override
181    public void setLastValidationDate(ZonedDateTime validationDate) throws AmetysRepositoryException
182    {
183        _getFactory().getModifiableContentHelper().setLastValidationDate(this, validationDate);
184    }
185    
186    public void setLastMajorValidator(UserIdentity user) throws AmetysRepositoryException
187    {
188        _getFactory().getModifiableContentHelper().setLastMajorValidator(this, user);
189    }
190    
191    @Override
192    public void setLastMajorValidationDate(ZonedDateTime validationDate) throws AmetysRepositoryException
193    {
194        _getFactory().getModifiableContentHelper().setLastMajorValidationDate(this, validationDate);
195    }
196    
197    @Override
198    public void setOutgoingReferences(Map<String, OutgoingReferences> references) throws AmetysRepositoryException
199    {
200        _getFactory().getModifiableContentHelper().setOutgoingReferences(this, references);
201    }
202    
203    // ------------------- Tags management -------------------- //
204    @Override
205    public void tag(String tag) throws AmetysRepositoryException
206    {
207        TaggableAmetysObjectHelper.tag(this, tag);
208    }
209    
210    @Override
211    public void untag(String tag) throws AmetysRepositoryException
212    {
213        TaggableAmetysObjectHelper.untag(this, tag);
214    }
215    
216    // Lock management. //
217    
218    @Override
219    public void lock() throws AmetysRepositoryException
220    {
221        _getFactory().getLockComponent().lock(this);
222        
223        // the lock component immediately detached the lock token, so we have to check it again at next usage 
224        _lockAlreadyChecked = false;
225    }
226    
227    @Override
228    public void unlock() throws AmetysRepositoryException
229    {
230        _getFactory().getLockComponent().unlock(this);
231        
232        // the lock component removed the lock token on unlock
233        _lockAlreadyChecked = true;
234    }
235    
236    @Override
237    public void setLockInfoOnCurrentContext() throws AmetysRepositoryException
238    {
239        if (!_lockAlreadyChecked)
240        {
241            _getFactory().getLockComponent().setLockTokenOnCurrentSession(this);
242            _lockAlreadyChecked = true;
243        }
244    }
245    
246    @Override
247    public boolean isLocked() throws AmetysRepositoryException
248    {
249        return _getFactory().getLockComponent().isLocked(this);
250    }
251    
252    @Override
253    public UserIdentity getLockOwner() throws AmetysRepositoryException
254    {
255        return _getFactory().getLockComponent().getLockOwner(this);
256    }
257        
258    // Dublin Core metadata. //
259    
260    @Override
261    public void setDCTitle(String title) throws AmetysRepositoryException
262    {
263        DublinCoreHelper.setDCTitle(this, title);
264    }
265
266    @Override
267    public void setDCCreator(String creator) throws AmetysRepositoryException
268    {
269        DublinCoreHelper.setDCCreator(this, creator);
270    }
271
272    @Override
273    public void setDCSubject(String[] subject) throws AmetysRepositoryException
274    {
275        DublinCoreHelper.setDCSubject(this, subject);
276    }
277
278    @Override
279    public void setDCDescription(String description) throws AmetysRepositoryException
280    {
281        DublinCoreHelper.setDCDescription(this, description);
282    }
283
284    @Override
285    public void setDCPublisher(String publisher) throws AmetysRepositoryException
286    {
287        DublinCoreHelper.setDCPublisher(this, publisher);
288    }
289
290    @Override
291    public void setDCContributor(String contributor) throws AmetysRepositoryException
292    {
293        DublinCoreHelper.setDCContributor(this, contributor);
294    }
295
296    @Override
297    public void setDCDate(Date date) throws AmetysRepositoryException
298    {
299        DublinCoreHelper.setDCDate(this, date);
300    }
301
302    @Override
303    public void setDCType(String type) throws AmetysRepositoryException
304    {
305        DublinCoreHelper.setDCType(this, type);
306    }
307
308    @Override
309    public void setDCFormat(String format) throws AmetysRepositoryException
310    {
311        DublinCoreHelper.setDCFormat(this, format);
312    }
313
314    @Override
315    public void setDCIdentifier(String identifier) throws AmetysRepositoryException
316    {
317        DublinCoreHelper.setDCIdentifier(this, identifier);
318    }
319
320    @Override
321    public void setDCSource(String source) throws AmetysRepositoryException
322    {
323        DublinCoreHelper.setDCSource(this, source);
324    }
325
326    @Override
327    public void setDCLanguage(String language) throws AmetysRepositoryException
328    {
329        DublinCoreHelper.setDCLanguage(this, language);
330    }
331
332    @Override
333    public void setDCRelation(String relation) throws AmetysRepositoryException
334    {
335        DublinCoreHelper.setDCRelation(this, relation);
336    }
337    
338    @Override
339    public void setDCCoverage(String coverage) throws AmetysRepositoryException
340    {
341        DublinCoreHelper.setDCCoverage(this, coverage);
342    }
343    
344    @Override
345    public void setDCRights(String rights) throws AmetysRepositoryException
346    {
347        DublinCoreHelper.setDCRights(this, rights);
348    }
349    
350    @Override
351    public Comment createComment()
352    {
353        return new Comment(_getFactory().getModifiableContentHelper().getCommentsDataHolder(this, true));
354    }
355    
356    public Comment createComment(String commentId, ZonedDateTime creationDate)
357    {
358        return new Comment(_getFactory().getModifiableContentHelper().getCommentsDataHolder(this, true), commentId, creationDate);
359    }
360    
361    @Override
362    public Comment getComment(String commentId) throws AmetysRepositoryException
363    {
364        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getCommentsDataHolder(this, false);
365        return commentsDataHolder != null ? Comment.getComment(commentsDataHolder, commentId) : null;
366    }
367    
368    @Override
369    public List<Comment> getComments(boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException
370    {
371        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getCommentsDataHolder(this, false);
372        return commentsDataHolder != null ? Comment.getComments(commentsDataHolder, includeNotValidatedComments, includeValidatedComments) : List.of();
373    }
374    
375    @Override
376    public Comment createContributorComment()
377    {
378        return new Comment(_getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, true));
379    }
380    
381    public Comment createContributorComment(String commentId, ZonedDateTime creationDate)
382    {
383        return new Comment(_getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, true), commentId, creationDate);
384    }
385    
386    @Override
387    public Comment getContributorComment(String commentId) throws AmetysRepositoryException
388    {
389        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, false);
390        return commentsDataHolder != null ? Comment.getComment(commentsDataHolder, commentId) : null;
391    }
392    
393    @Override
394    public List<Comment> getContributorComments() throws AmetysRepositoryException
395    {
396        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, false);
397        return commentsDataHolder != null ? Comment.getComments(commentsDataHolder, false, true) : List.of();
398    }
399    
400    @Override
401    public ModifiableIndexableDataHolder getDataHolder()
402    {
403        // It is necessary to instantiate the repository data because of locks:
404        // when the content is locked, the lock token is released to be taken by anyone
405        // in repository data there is a lock checked boolean that need to be reset in order to take the token
406        // this boolean is only reset at instantiation
407        Collection<ContentType> contentTypes = _getFactory().getContentHelper().getContentTypes(this);
408        return new ModifiableContentDataHolder(this, _getFactory().getContentDataHelper(), new JCRRepositoryData(getNode()), contentTypes);
409    }
410    
411    public void fillContent(org.w3c.dom.Node node, XMLValuesExtractorAdditionalDataGetter additionalDataGetter) throws Exception
412    {
413        _getFactory().getContentExtractor().fillContent(this, node, additionalDataGetter);
414    }
415}