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.cms.repository;
017
018import java.util.Date;
019import java.util.GregorianCalendar;
020import java.util.List;
021import java.util.Locale;
022import java.util.Map;
023
024import javax.jcr.Node;
025import javax.jcr.RepositoryException;
026
027import org.apache.avalon.framework.component.Component;
028
029import org.ametys.cms.content.references.OutgoingReferences;
030import org.ametys.cms.data.type.ModelItemTypeConstants;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.plugins.repository.AmetysRepositoryException;
033import org.ametys.plugins.repository.RepositoryConstants;
034import org.ametys.plugins.repository.data.repositorydata.ModifiableRepositoryData;
035import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
036import org.ametys.runtime.model.ElementDefinition;
037import org.ametys.runtime.model.ModelItem;
038
039
040/**
041 * Provides helper methods to use the {@link ModifiableContent} API on {@link DefaultContent}s.
042 */
043public class ModifiableContentHelper implements Component
044{
045    /** The Avalon role */
046    public static final String ROLE = ModifiableContentHelper.class.getName();
047
048    /**
049     * Set a {@link DefaultContent} title for the given locale. 
050     * @param content the {@link DefaultContent} to set.
051     * @param title the title to set.
052     * @param locale The locale. Can be null if the content is not a multilingual content.
053     * @throws AmetysRepositoryException if an error occurs.
054     */
055    public void setTitle(DefaultContent content, String title, Locale locale) throws AmetysRepositoryException
056    {
057        ModelItem titleDefinition = content.getDefinition(Content.ATTRIBUTE_TITLE);
058        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
059        if (titleDefinition instanceof ElementDefinition && ModelItemTypeConstants.MULTILINGUAL_STRING_ELEMENT_TYPE_ID.equals(((ElementDefinition) titleDefinition).getType().getId()))
060        {
061            if (locale == null)
062            {
063                throw new IllegalArgumentException("Cannot set a title with null locale on a multilingual title");
064            }
065            
066            ModifiableRepositoryData titleRepositoryData;
067            if (repositoryData.hasValue(Content.ATTRIBUTE_TITLE))
068            {
069                titleRepositoryData = repositoryData.getRepositoryData(Content.ATTRIBUTE_TITLE);
070            }
071            else
072            {
073                titleRepositoryData = repositoryData.addRepositoryData(Content.ATTRIBUTE_TITLE, RepositoryConstants.MULTILINGUAL_STRING_METADATA_NODETYPE);
074            }
075            titleRepositoryData.setValue(locale.toString(), title);
076        }
077        else
078        {
079            repositoryData.setValue(Content.ATTRIBUTE_TITLE, title);
080        }
081    }
082    
083    /**
084     * Set the title of non-multilingual {@link DefaultContent}.
085     * Be careful! Use only if content's title is not a multilingual string. If not sure use {@link #setTitle(DefaultContent, String, Locale)} instead.
086     * @param content the {@link DefaultContent} to set.
087     * @param title the title to set.
088     * @throws AmetysRepositoryException if an error occurs.
089     */
090    public void setTitle(DefaultContent content, String title) throws AmetysRepositoryException
091    {
092        setTitle(content, title, null);
093    }
094    
095    /**
096     * Copy the title of the source content to the target content
097     * @param srcContent The source content
098     * @param targetContent The target content
099     * @throws AmetysRepositoryException if an error occurs.
100     */
101    public void copyTitle(Content srcContent, ModifiableContent targetContent) throws AmetysRepositoryException
102    {
103        targetContent.setValue(Content.ATTRIBUTE_TITLE, srcContent.getValue(Content.ATTRIBUTE_TITLE));
104    }
105    
106    /**
107     * Set a {@link DefaultContent} user.
108     * @param content the {@link DefaultContent} to set.
109     * @param user the user to set.
110     * @throws AmetysRepositoryException if an error occurs.
111     */
112    public void setCreator(DefaultContent content, UserIdentity user) throws AmetysRepositoryException
113    {
114        try
115        {
116            // TODO CMS-9336 All the metatadata here should be store using types
117            ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
118            ModifiableRepositoryData creatorRepositoryData;
119            if (repositoryData.hasValue(DefaultContent.METADATA_CREATOR))
120            {
121                creatorRepositoryData = repositoryData.getRepositoryData(DefaultContent.METADATA_CREATOR);
122            }
123            else
124            {
125                creatorRepositoryData = repositoryData.addRepositoryData(DefaultContent.METADATA_CREATOR, RepositoryConstants.USER_NODETYPE);
126            }
127            creatorRepositoryData.setValue("login", user.getLogin());
128            creatorRepositoryData.setValue("population", user.getPopulationId());
129        }
130        catch (AmetysRepositoryException e)
131        {
132            throw new AmetysRepositoryException("Error setting the creator property.", e);
133        }
134    }
135    
136    /**
137     * Set a {@link DefaultContent} creation date.
138     * @param content the {@link DefaultContent} to set.
139     * @param creationDate the creation date to set.
140     * @throws AmetysRepositoryException if an error occurs.
141     */
142    public void setCreationDate(DefaultContent content, Date creationDate) throws AmetysRepositoryException
143    {
144        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
145        GregorianCalendar calendar = new GregorianCalendar();
146        calendar.setTime(creationDate);
147        repositoryData.setValue(DefaultContent.METADATA_CREATION, calendar);
148    }
149    
150    /**
151     * Set a {@link DefaultContent} contributor.
152     * @param content the {@link DefaultContent} to set.
153     * @param user the contributor to set.
154     * @throws AmetysRepositoryException if an error occurs.
155     */
156    public void setLastContributor(DefaultContent content, UserIdentity user) throws AmetysRepositoryException
157    {
158        try
159        {
160            ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
161            ModifiableRepositoryData contributorRepositoryData;
162            if (repositoryData.hasValue(DefaultContent.METADATA_CONTRIBUTOR))
163            {
164                contributorRepositoryData = repositoryData.getRepositoryData(DefaultContent.METADATA_CONTRIBUTOR);
165            }
166            else
167            {
168                contributorRepositoryData = repositoryData.addRepositoryData(DefaultContent.METADATA_CONTRIBUTOR, RepositoryConstants.USER_NODETYPE);
169            }
170            contributorRepositoryData.setValue("login", user.getLogin());
171            contributorRepositoryData.setValue("population", user.getPopulationId());
172        }
173        catch (AmetysRepositoryException e)
174        {
175            throw new AmetysRepositoryException("Error setting the last contributor property.", e);
176        }
177    }
178    
179    /**
180     * Set a {@link DefaultContent} last modification date.
181     * @param content the {@link DefaultContent} to set.
182     * @param lastModified the last modification date to set.
183     * @throws AmetysRepositoryException if an error occurs.
184     */
185    public void setLastModified(DefaultContent content, Date lastModified) throws AmetysRepositoryException
186    {
187        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
188        GregorianCalendar calendar = new GregorianCalendar();
189        calendar.setTime(lastModified);
190        repositoryData.setValue(DefaultContent.METADATA_MODIFIED, calendar);
191    }
192    
193    /**
194     * Set a {@link DefaultContent} first validation date.
195     * @param content the {@link DefaultContent} to set.
196     * @param validationDate the first validation date.
197     * @throws AmetysRepositoryException if an error occurs.
198     */
199    public void setFirstValidationDate(DefaultContent content, Date validationDate) throws AmetysRepositoryException
200    {
201        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
202        GregorianCalendar calendar = new GregorianCalendar();
203        calendar.setTime(validationDate);
204        repositoryData.setValue(DefaultContent.METADATA_FIRST_VALIDATION, calendar);
205    }
206    
207    /**
208     * Set a {@link DefaultContent} last validation date.
209     * @param content the {@link DefaultContent} to set.
210     * @param validationDate the last validation date.
211     * @throws AmetysRepositoryException if an error occurs.
212     */
213    public void setLastValidationDate(DefaultContent content, Date validationDate) throws AmetysRepositoryException
214    {
215        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
216        GregorianCalendar calendar = new GregorianCalendar();
217        calendar.setTime(validationDate);
218        repositoryData.setValue(DefaultContent.METADATA_LAST_VALIDATION, calendar);
219    }
220    
221    /**
222     * Set a {@link DefaultContent} last major validation date.
223     * @param content the {@link DefaultContent} to set.
224     * @param validationDate the last major validation date.
225     * @throws AmetysRepositoryException if an error occurs.
226     */
227    public void setLastMajorValidationDate(DefaultContent content, Date validationDate) throws AmetysRepositoryException
228    {
229        ModifiableRepositoryData repositoryData = new JCRRepositoryData(content.getNode());
230        GregorianCalendar calendar = new GregorianCalendar();
231        calendar.setTime(validationDate);
232        repositoryData.setValue(DefaultContent.METADATA_LAST_MAJORVALIDATION, calendar);
233    }
234    
235    /**
236     * Store the outgoing references on the content.
237     * @param content The content concerned by these outgoing references.
238     * @param references A non null map of outgoing references grouped by metadata (key are metadata path)
239     * @throws AmetysRepositoryException if an error occurs.
240     */
241    public void setOutgoingReferences(DefaultContent content, Map<String, OutgoingReferences> references) throws AmetysRepositoryException
242    {
243        try
244        {
245            Node contentNode = content.getNode();
246            if (contentNode.hasNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES))
247            {
248                contentNode.getNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES).remove();
249            }
250            
251            if (references.size() != 0)
252            {
253                Node rootOutgoingRefsNode = contentNode.addNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES);
254                for (String path : references.keySet())
255                {
256                    // Outgoing references node creation (for the given path)
257                    Node outgoingRefsNode = rootOutgoingRefsNode.addNode(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_OUTGOING_REFERENCES);
258                    outgoingRefsNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ':' + DefaultContent.METADATA_OUTGOING_REFERENCES_PATH_PROPERTY, path);
259                    
260                    // Reference nodes per type
261                    OutgoingReferences outgoingReferences = references.get(path);
262                    
263                    for (String type : outgoingReferences.keySet())
264                    {
265                        List<String> referenceValues = outgoingReferences.get(type);
266                        if (referenceValues != null && !referenceValues.isEmpty())
267                        {
268                            Node outgoingReferenceNode = outgoingRefsNode.addNode(type, RepositoryConstants.NAMESPACE_PREFIX + ':' + DefaultContent.METADATA_OUTGOING_REFERENCE_NODETYPE);
269                            outgoingReferenceNode.setProperty(RepositoryConstants.NAMESPACE_PREFIX + ':' + DefaultContent.METADATA_OUTGOING_REFERENCE_PROPERTY, referenceValues.toArray(new String[referenceValues.size()]));
270                        }
271                    }
272                }
273            }
274        }
275        catch (RepositoryException e)
276        {
277            throw new AmetysRepositoryException(e);
278        }
279    }
280}