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        _outgoingReferences = references;
202    }
203    
204    // ------------------- Tags management -------------------- //
205    @Override
206    public void tag(String tag) throws AmetysRepositoryException
207    {
208        TaggableAmetysObjectHelper.tag(this, tag);
209    }
210    
211    @Override
212    public void untag(String tag) throws AmetysRepositoryException
213    {
214        TaggableAmetysObjectHelper.untag(this, tag);
215    }
216    
217    // Lock management. //
218    
219    @Override
220    public void lock() throws AmetysRepositoryException
221    {
222        _getFactory().getLockComponent().lock(this);
223        
224        // the lock component immediately detached the lock token, so we have to check it again at next usage
225        _lockAlreadyChecked = false;
226    }
227    
228    @Override
229    public void unlock() throws AmetysRepositoryException
230    {
231        _getFactory().getLockComponent().unlock(this);
232        
233        // the lock component removed the lock token on unlock
234        _lockAlreadyChecked = true;
235    }
236    
237    @Override
238    public void setLockInfoOnCurrentContext() throws AmetysRepositoryException
239    {
240        if (!_lockAlreadyChecked)
241        {
242            _getFactory().getLockComponent().setLockTokenOnCurrentSession(this);
243            _lockAlreadyChecked = true;
244        }
245    }
246    
247    @Override
248    public boolean isLocked() throws AmetysRepositoryException
249    {
250        return _getFactory().getLockComponent().isLocked(this);
251    }
252    
253    @Override
254    public UserIdentity getLockOwner() throws AmetysRepositoryException
255    {
256        return _getFactory().getLockComponent().getLockOwner(this);
257    }
258        
259    // Dublin Core metadata. //
260    
261    @Override
262    public void setDCTitle(String title) throws AmetysRepositoryException
263    {
264        DublinCoreHelper.setDCTitle(this, title);
265    }
266
267    @Override
268    public void setDCCreator(String creator) throws AmetysRepositoryException
269    {
270        DublinCoreHelper.setDCCreator(this, creator);
271    }
272
273    @Override
274    public void setDCSubject(String[] subject) throws AmetysRepositoryException
275    {
276        DublinCoreHelper.setDCSubject(this, subject);
277    }
278
279    @Override
280    public void setDCDescription(String description) throws AmetysRepositoryException
281    {
282        DublinCoreHelper.setDCDescription(this, description);
283    }
284
285    @Override
286    public void setDCPublisher(String publisher) throws AmetysRepositoryException
287    {
288        DublinCoreHelper.setDCPublisher(this, publisher);
289    }
290
291    @Override
292    public void setDCContributor(String contributor) throws AmetysRepositoryException
293    {
294        DublinCoreHelper.setDCContributor(this, contributor);
295    }
296
297    @Override
298    public void setDCDate(Date date) throws AmetysRepositoryException
299    {
300        DublinCoreHelper.setDCDate(this, date);
301    }
302
303    @Override
304    public void setDCType(String type) throws AmetysRepositoryException
305    {
306        DublinCoreHelper.setDCType(this, type);
307    }
308
309    @Override
310    public void setDCFormat(String format) throws AmetysRepositoryException
311    {
312        DublinCoreHelper.setDCFormat(this, format);
313    }
314
315    @Override
316    public void setDCIdentifier(String identifier) throws AmetysRepositoryException
317    {
318        DublinCoreHelper.setDCIdentifier(this, identifier);
319    }
320
321    @Override
322    public void setDCSource(String source) throws AmetysRepositoryException
323    {
324        DublinCoreHelper.setDCSource(this, source);
325    }
326
327    @Override
328    public void setDCLanguage(String language) throws AmetysRepositoryException
329    {
330        DublinCoreHelper.setDCLanguage(this, language);
331    }
332
333    @Override
334    public void setDCRelation(String relation) throws AmetysRepositoryException
335    {
336        DublinCoreHelper.setDCRelation(this, relation);
337    }
338    
339    @Override
340    public void setDCCoverage(String coverage) throws AmetysRepositoryException
341    {
342        DublinCoreHelper.setDCCoverage(this, coverage);
343    }
344    
345    @Override
346    public void setDCRights(String rights) throws AmetysRepositoryException
347    {
348        DublinCoreHelper.setDCRights(this, rights);
349    }
350    
351    @Override
352    public Comment createComment()
353    {
354        return new Comment(_getFactory().getModifiableContentHelper().getCommentsDataHolder(this, true));
355    }
356    
357    public Comment createComment(String commentId, ZonedDateTime creationDate)
358    {
359        return new Comment(_getFactory().getModifiableContentHelper().getCommentsDataHolder(this, true), commentId, creationDate);
360    }
361    
362    @Override
363    public Comment getComment(String commentId) throws AmetysRepositoryException
364    {
365        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getCommentsDataHolder(this, false);
366        return commentsDataHolder != null ? Comment.getComment(commentsDataHolder, commentId) : null;
367    }
368    
369    @Override
370    public List<Comment> getComments(boolean includeNotValidatedComments, boolean includeValidatedComments) throws AmetysRepositoryException
371    {
372        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getCommentsDataHolder(this, false);
373        return commentsDataHolder != null ? Comment.getComments(commentsDataHolder, includeNotValidatedComments, includeValidatedComments) : List.of();
374    }
375    
376    @Override
377    public Comment createContributorComment()
378    {
379        return new Comment(_getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, true));
380    }
381    
382    public Comment createContributorComment(String commentId, ZonedDateTime creationDate)
383    {
384        return new Comment(_getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, true), commentId, creationDate);
385    }
386    
387    @Override
388    public Comment getContributorComment(String commentId) throws AmetysRepositoryException
389    {
390        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, false);
391        return commentsDataHolder != null ? Comment.getComment(commentsDataHolder, commentId) : null;
392    }
393    
394    @Override
395    public List<Comment> getContributorComments() throws AmetysRepositoryException
396    {
397        ModifiableModelLessDataHolder commentsDataHolder = _getFactory().getModifiableContentHelper().getContributorCommentsDataHolder(this, false);
398        return commentsDataHolder != null ? Comment.getComments(commentsDataHolder, false, true) : List.of();
399    }
400    
401    @Override
402    public ModifiableIndexableDataHolder getDataHolder()
403    {
404        // It is necessary to instantiate the repository data because of locks:
405        // when the content is locked, the lock token is released to be taken by anyone
406        // in repository data there is a lock checked boolean that need to be reset in order to take the token
407        // this boolean is only reset at instantiation
408        Collection<ContentType> contentTypes = _getFactory().getContentHelper().getContentTypes(this);
409        return new ModifiableContentDataHolder(this, _getFactory().getContentDataHelper(), new JCRRepositoryData(getNode()), contentTypes);
410    }
411    
412    public void fillContent(org.w3c.dom.Node node, XMLValuesExtractorAdditionalDataGetter additionalDataGetter) throws Exception
413    {
414        _getFactory().getContentExtractor().fillContent(this, node, additionalDataGetter);
415    }
416}