001/*
002 *  Copyright 2015 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.survey.repository;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.time.ZonedDateTime;
021
022import javax.jcr.Node;
023import javax.jcr.PathNotFoundException;
024import javax.jcr.RepositoryException;
025
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.cms.data.Binary;
029import org.ametys.cms.data.type.ModelItemTypeConstants;
030import org.ametys.plugins.repository.AmetysObject;
031import org.ametys.plugins.repository.AmetysRepositoryException;
032import org.ametys.plugins.repository.CopiableAmetysObject;
033import org.ametys.plugins.repository.RepositoryConstants;
034import org.ametys.plugins.repository.data.ametysobject.ModifiableModelLessDataAwareAmetysObject;
035import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
036import org.ametys.plugins.repository.data.holder.impl.DefaultModifiableModelLessDataHolder;
037import org.ametys.plugins.repository.data.repositorydata.impl.JCRRepositoryData;
038import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject;
039import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObjectFactory;
040
041/**
042 * Abstract {@link AmetysObject} for storing elements of a survey
043 * @param <F> the actual type of factory.
044 */
045public abstract class AbstractSurveyElement<F extends SurveyElementFactory> extends DefaultTraversableAmetysObject<F> implements CopiableAmetysObject, ModifiableModelLessDataAwareAmetysObject
046{
047    /** Constant for picture data property. */
048    public static final String PROPERTY_PICTURE = "picture";
049    /** Constant for picture type property. */
050    public static final String PROPERTY_PICTURE_TYPE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-type";
051    /** Constant for picture id property. */
052    public static final String PROPERTY_PICTURE_ID = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-id";
053    /** Constant for picture alternative property. */
054    public static final String PROPERTY_PICTURE_ALTERNATIVE = RepositoryConstants.NAMESPACE_PREFIX_INTERNAL + ":picture-alternative";
055    
056    /**
057     * Constructor
058     * @param node the node backing this {@link AmetysObject}.
059     * @param parentPath the parent path in the Ametys hierarchy.
060     * @param factory the {@link DefaultTraversableAmetysObjectFactory} which creates the AmetysObject.
061     */
062    public AbstractSurveyElement(Node node, String parentPath, F factory)
063    {
064        super(node, parentPath, factory);
065    }
066
067    /**
068     * Get the picture as a binary metadata.
069     * @return the picture as a binary metadata.
070     * @throws AmetysRepositoryException if an error occurs.
071     */
072    public Binary getExternalPicture() throws AmetysRepositoryException
073    {
074        return getValue(PROPERTY_PICTURE);
075    }
076    
077    /**
078     * Set the picture from an external file.
079     * @param mimeType the file MIME type.
080     * @param filename the file name.
081     * @param stream an input stream on the file bytes.
082     * @throws AmetysRepositoryException if an error occurs.
083     */
084    public void setExternalPicture(String mimeType, String filename, InputStream stream) throws AmetysRepositoryException
085    {
086        try
087        {
088            removePictureMetas();
089            
090            setPictureType("external");
091            
092            Binary pic = new Binary();
093            
094            pic.setLastModificationDate(ZonedDateTime.now());
095            pic.setInputStream(stream);
096            pic.setMimeType(mimeType);
097            pic.setFilename(filename);
098            
099            setValue(PROPERTY_PICTURE, pic, ModelItemTypeConstants.BINARY_ELEMENT_TYPE_ID);
100        }
101        catch (IOException | RepositoryException e)
102        {
103            throw new AmetysRepositoryException("Error setting the external picture property.", e);
104        }
105    }
106    
107    /**
108     * Get the picture resource ID.
109     * @return the resource ID.
110     * @throws AmetysRepositoryException if an error occurs.
111     */
112    public String getResourcePictureId() throws AmetysRepositoryException
113    {
114        try
115        {
116            return getNode().getProperty(PROPERTY_PICTURE_ID).getString();
117        }
118        catch (PathNotFoundException e)
119        {
120            return null;
121        }
122        catch (RepositoryException e)
123        {
124            throw new AmetysRepositoryException("Error getting the picture ID property.", e);
125        }
126    }
127        
128    /**
129     * Set the picture from an explorer resource.
130     * @param resourceId the resource ID.
131     * @throws AmetysRepositoryException if an error occurs.
132     */
133    public void setResourcePicture(String resourceId) throws AmetysRepositoryException
134    {
135        try
136        {
137            removePictureMetas();
138            
139            setPictureType("resource");
140            
141            getNode().setProperty(PROPERTY_PICTURE_ID, resourceId);
142        }
143        catch (RepositoryException e)
144        {
145            throw new AmetysRepositoryException("Error setting the alternative property.", e);
146        }
147    }
148    
149    /**
150     * Removes any picture currently assigned.
151     * @throws AmetysRepositoryException if an error occurs.
152     */
153    public void setNoPicture() throws AmetysRepositoryException
154    {
155        try
156        {
157            setPictureType("");
158            
159            removePictureMetas();
160        }
161        catch (RepositoryException e)
162        {
163            throw new AmetysRepositoryException("Error setting the alternative property.", e);
164        }
165    }
166
167    /**
168     * Get the picture type.
169     * @return the picture type.
170     * @throws AmetysRepositoryException if an error occurs.
171     */
172    public String getPictureType() throws AmetysRepositoryException
173    {
174        try
175        {
176            return getNode().getProperty(PROPERTY_PICTURE_TYPE).getString();
177        }
178        catch (PathNotFoundException e)
179        {
180            return null;
181        }
182        catch (RepositoryException e)
183        {
184            throw new AmetysRepositoryException("Error getting the type property.", e);
185        }
186    }
187    
188    /**
189     * Set the picture type.
190     * @param type the picture type to set.
191     * @throws AmetysRepositoryException if an error occurs.
192     */
193    public void setPictureType(String type) throws AmetysRepositoryException
194    {
195        try
196        {
197            getNode().setProperty(PROPERTY_PICTURE_TYPE, type);
198        }
199        catch (RepositoryException e)
200        {
201            throw new AmetysRepositoryException("Error setting the type property.", e);
202        }
203    }
204    
205    /**
206     * Get the picture alternative.
207     * @return the picture alternative.
208     * @throws AmetysRepositoryException if an error occurs.
209     */
210    public String getPictureAlternative() throws AmetysRepositoryException
211    {
212        try
213        {
214            return getNode().getProperty(PROPERTY_PICTURE_ALTERNATIVE).getString();
215        }
216        catch (PathNotFoundException e)
217        {
218            return null;
219        }
220        catch (RepositoryException e)
221        {
222            throw new AmetysRepositoryException("Error getting the alternative property.", e);
223        }
224    }
225    
226    /**
227     * Set the picture alternative.
228     * @param alternative the picture alternative to set.
229     * @throws AmetysRepositoryException if an error occurs.
230     */
231    public void setPictureAlternative(String alternative) throws AmetysRepositoryException
232    {
233        try
234        {
235            getNode().setProperty(PROPERTY_PICTURE_ALTERNATIVE, alternative);
236        }
237        catch (RepositoryException e)
238        {
239            throw new AmetysRepositoryException("Error setting the alternative property.", e);
240        }
241    }
242    
243    /**
244     * Remove all picture metas (picture ID and picture binary).
245     * @throws RepositoryException if an error occurs.
246     */
247    protected void removePictureMetas() throws RepositoryException
248    {
249        getNode().setProperty(PROPERTY_PICTURE_ID, StringUtils.EMPTY);
250        
251        if (hasValue(PROPERTY_PICTURE))
252        {
253            removeValue(PROPERTY_PICTURE);
254        }
255    }
256    
257    /**
258     * Copy the picture of this {@link AbstractSurveyElement} to the element in arguments
259     * @param elmt The element
260     */
261    protected void copyPictureTo (AbstractSurveyElement elmt)
262    {
263        String pictureType = getPictureType();
264        if (StringUtils.isBlank(pictureType))
265        {
266            elmt.setNoPicture();
267        }
268        else if (pictureType.equals("resource"))
269        {
270            String pictureId = getResourcePictureId();
271            if (StringUtils.isNotBlank(pictureId))
272            {
273                elmt.setResourcePicture(pictureId);
274            }
275            else
276            {
277                elmt.setNoPicture();
278            }
279        }
280        else if (pictureType.equals("external"))
281        {
282            Binary externalPicture = getExternalPicture();
283            elmt.setExternalPicture(externalPicture.getMimeType(), externalPicture.getFilename(), externalPicture.getInputStream());
284        }
285        
286        String pictureAlternative = getPictureAlternative();
287        if (pictureAlternative != null)
288        {
289            elmt.setPictureAlternative(pictureAlternative);
290        }
291    }
292    
293    public ModifiableModelLessDataHolder getDataHolder()
294    {
295        JCRRepositoryData repositoryData = new JCRRepositoryData(getNode());
296        return new DefaultModifiableModelLessDataHolder(_getFactory().getSurveyElementDataTypeExtensionPoint(), repositoryData);
297    }
298}