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.plugins.explorer.cmis;
017
018import java.io.InputStream;
019import java.util.Calendar;
020import java.util.Collection;
021import java.util.Date;
022import java.util.List;
023import java.util.Map;
024import java.util.Optional;
025
026import org.apache.chemistry.opencmis.client.api.Document;
027import org.apache.chemistry.opencmis.client.api.Folder;
028import org.apache.chemistry.opencmis.commons.data.ContentStream;
029import org.apache.commons.lang3.Strings;
030import org.xml.sax.ContentHandler;
031import org.xml.sax.SAXException;
032
033import org.ametys.core.user.UserIdentity;
034import org.ametys.core.user.population.UserPopulationDAO;
035import org.ametys.plugins.explorer.ExplorerNode;
036import org.ametys.plugins.explorer.resources.Resource;
037import org.ametys.plugins.repository.AmetysObject;
038import org.ametys.plugins.repository.AmetysRepositoryException;
039import org.ametys.plugins.repository.data.UnknownDataException;
040import org.ametys.plugins.repository.data.holder.DataHolder;
041import org.ametys.plugins.repository.data.holder.ModifiableDataHolder;
042import org.ametys.plugins.repository.data.holder.group.Composite;
043import org.ametys.plugins.repository.data.repositorydata.RepositoryData;
044import org.ametys.plugins.repository.data.type.ModelItemTypeExtensionPoint;
045import org.ametys.runtime.model.exception.BadItemTypeException;
046import org.ametys.runtime.model.exception.NotUniqueTypeException;
047import org.ametys.runtime.model.exception.UnknownTypeException;
048import org.ametys.runtime.model.type.DataContext;
049import org.ametys.runtime.model.type.ModelItemType;
050
051/**
052 * Implementation of an {@link Resource}, backed by a server CMIS.<br>
053 */
054public class CMISResource implements Resource
055{
056    private final Document _cmisDocument;
057    private final CMISRootResourcesCollection _root;
058    private AmetysObject _parent;
059    
060    /**
061     * Creates a {@link CMISResource}
062     * @param document The CMIS document
063     * @param root The root of the virtual tree
064     * @param parent the parent {@link AmetysObject} if known
065     */
066    public CMISResource(Document document, CMISRootResourcesCollection root, AmetysObject parent)
067    {
068        _cmisDocument = document;
069        _root = root;
070        _parent = parent;
071    }
072
073    /**
074     * Retrieves the {@link CMISRootResourcesCollection}
075     * @return the {@link CMISRootResourcesCollection}
076     */
077    public CMISRootResourcesCollection getCmisRoot ()
078    {
079        return _root;
080    }
081    
082    /**
083     * Retrieves the {@link Folder}
084     * @return the {@link Folder}
085     */
086    public Document getCmisDocument ()
087    {
088        return _cmisDocument;
089    }
090    
091    @Override
092    public String getId() throws AmetysRepositoryException
093    {
094        return getCmisRoot().getId() + "/" + getCmisDocument().getId();
095    }
096
097    @Override
098    public String getName()
099    {
100        String fileName = getCmisDocument().getName();
101
102        if (fileName == null)
103        {
104            fileName = getCmisDocument().getContentStreamFileName();
105        }
106        if (fileName == null)
107        {
108            ContentStream cs = getCmisDocument().getContentStream();
109            if (cs != null)
110            {
111                fileName = cs.getFileName();
112            }
113            else
114            {
115                throw new AmetysRepositoryException("contentStream is empty on CMIS Document '" + getCmisDocument().getId() + "'");
116            }
117
118            if (fileName == null)
119            {
120                throw new AmetysRepositoryException("fileName is null on CMIS Document '" + getCmisDocument().getId() + "'");
121            }
122        }
123        return fileName;
124    }
125
126    @Override
127    @SuppressWarnings("unchecked")
128    public AmetysObject getParent() throws AmetysRepositoryException
129    {
130        if (_parent != null)
131        {
132            return _parent;
133        }
134        
135        // iterate on all parents and returns the first valid parent
136        String rootPath = _root.getRootFolder().getPath();
137        String rootId = _root.getRootFolder().getId();
138        for (Folder parent : getCmisDocument().getParents())
139        {
140            // check if the parent is valid by making sure that it is below the root folder
141            // This is necessary to unsure that the parent is included in the mount point
142            if (Strings.CS.contains(parent.getPath(), rootPath))
143            {
144                if (Strings.CS.equals(parent.getId(), rootId))
145                {
146                    _parent = getCmisRoot();
147                }
148                else
149                {
150                    _parent = new CMISResourcesCollection(parent, _root, null);
151                }
152                return _parent;
153            }
154        }
155        
156        throw new AmetysRepositoryException("Failed to retrieve the parent of folder " + getName() + ". This is most likely due to the fact that we couldn't find one in the CMIS mount point.");
157    }
158
159    @Override
160    public String getParentPath() throws AmetysRepositoryException
161    {
162        return getParent().getPath();
163    }
164
165    @Override
166    public String getPath() throws AmetysRepositoryException
167    {
168        return getParentPath() + "/" + getName();
169    }
170
171    @Override
172    public UserIdentity getCreator()
173    {
174        // FIXME We cannot convert the CMIS remote user to an Ametys user. We need to know the population. If not found, return the system user.
175        // getCmisDocument().getCreatedBy();
176        return UserPopulationDAO.SYSTEM_USER_IDENTITY;
177    }
178
179    @Override
180    public InputStream getInputStream() throws AmetysRepositoryException
181    {
182        ContentStream contentStream = getCmisDocument().getContentStream();
183        if (contentStream != null)
184        {
185            return contentStream.getStream();
186        }
187        return null;
188    }
189
190    @Override
191    public Date getLastModified()
192    {
193        Calendar calendar = getCmisDocument().getLastModificationDate();
194        return calendar.getTime();
195    }
196
197    @Override
198    public long getLength()
199    {
200        return getCmisDocument().getContentStreamLength();
201    }
202
203   
204    @Override
205    public String getMimeType() throws AmetysRepositoryException
206    {
207        String mimeType = getCmisDocument().getContentStreamMimeType();
208        
209        return mimeType != null ? mimeType : "application/unknown";
210    }
211
212    @Override
213    public String[] getKeywords() throws AmetysRepositoryException
214    {
215        return new String[0];
216    }
217
218    @Override
219    public String getKeywordsAsString() throws AmetysRepositoryException
220    {
221        return "";
222    }
223    
224    @Override
225    public String getResourcePath() throws AmetysRepositoryException
226    {
227        return ((ExplorerNode) getParent()).getExplorerPath() + "/" + getName();
228    }
229    
230    // Dublin Core metadata. //
231    
232    @Override
233    public String getDCTitle() throws AmetysRepositoryException
234    {
235        return null;
236    }
237    
238    @Override
239    public String getDCCreator() throws AmetysRepositoryException
240    {
241        return null;
242    }
243    
244    @Override
245    public String[] getDCSubject() throws AmetysRepositoryException
246    {
247        return null;
248    }
249    
250    @Override
251    public String getDCDescription() throws AmetysRepositoryException
252    {
253        return null;
254    }
255    
256    @Override
257    public String getDCPublisher() throws AmetysRepositoryException
258    {
259        return null;
260    }
261    
262    @Override
263    public String getDCContributor() throws AmetysRepositoryException
264    {
265        return null;
266    }
267    
268    @Override
269    public Date getDCDate() throws AmetysRepositoryException
270    {
271        return null;
272    }
273    
274    @Override
275    public String getDCType() throws AmetysRepositoryException
276    {
277        return null;
278    }
279    
280    @Override
281    public String getDCFormat() throws AmetysRepositoryException
282    {
283        return null;
284    }
285    
286    @Override
287    public String getDCIdentifier() throws AmetysRepositoryException
288    {
289        return null;
290    }
291    
292    @Override
293    public String getDCSource() throws AmetysRepositoryException
294    {
295        return null;
296    }
297    
298    @Override
299    public String getDCLanguage() throws AmetysRepositoryException
300    {
301        return null;
302    }
303    
304    @Override
305    public String getDCRelation() throws AmetysRepositoryException
306    {
307        return null;
308    }
309    
310    @Override
311    public String getDCCoverage() throws AmetysRepositoryException
312    {
313        return null;
314    }
315    
316    @Override
317    public String getDCRights() throws AmetysRepositoryException
318    {
319        return null;
320    }
321
322    public Date getCreationDate() throws AmetysRepositoryException
323    {
324        Calendar calendar = getCmisDocument().getCreationDate();
325        return calendar.getTime();
326    }
327
328    public UserIdentity getLastContributor() throws AmetysRepositoryException
329    {
330        return UserIdentity.stringToUserIdentity(getCmisDocument().getLastModifiedBy());
331    }
332    
333    // Data holder methods //
334    
335    public Composite getComposite(String compositePath) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException
336    {
337        return null;
338    }
339    
340    public boolean hasValue(String dataPath) throws IllegalArgumentException
341    {
342        return false;
343    }
344    
345    public boolean hasValue(String dataPath, String dataTypeId) throws IllegalArgumentException
346    {
347        return false;
348    }
349    
350    public boolean hasValueOrEmpty(String dataPath) throws IllegalArgumentException
351    {
352        return false;
353    }
354
355    public Collection<String> getDataNames()
356    {
357        return List.of();
358    }
359    
360    public <T> T getValue(String dataPath) throws IllegalArgumentException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException
361    {
362        return null;
363    }
364    
365    public <T> T getValueOrDefault(String dataPath, T defaultValue) throws IllegalArgumentException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException
366    {
367        return null;
368    }
369
370    public <T> T getValueOfType(String dataPath, String dataTypeId) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException
371    {
372        return null;
373    }
374    
375    public <T> T getValueOfTypeOrDefault(String dataPath, String dataTypeId, T defaultValue) throws IllegalArgumentException, UnknownTypeException, BadItemTypeException
376    {
377        return null;
378    }
379    
380    public boolean isMultiple(String dataPath) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException
381    {
382        return false;
383    }
384    
385    public boolean isMultiple(String dataPath, String dataTypeId) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, BadItemTypeException
386    {
387        return false;
388    }
389    
390    public <X extends ModelItemType> X getType(String dataPath) throws IllegalArgumentException, UnknownDataException, UnknownTypeException, NotUniqueTypeException
391    {
392        return null;
393    }
394    
395    public ModelItemTypeExtensionPoint getModelItemTypeExtensionPoint()
396    {
397        return null;
398    }
399    
400    public void copyTo(ModifiableDataHolder dataHolder) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException
401    {
402        // Do nothing
403    }
404    
405    public void copyTo(ModifiableDataHolder dataHolder, DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException
406    {
407        // Do nothing
408    }
409    
410    public void dataToSAX(ContentHandler contentHandler, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException
411    {
412        // Do nothing
413    }
414    
415    public void dataToSAX(ContentHandler contentHandler, String dataPath, DataContext context) throws SAXException, UnknownTypeException, NotUniqueTypeException, BadItemTypeException
416    {
417        // Do nothing
418    }
419    
420    public Map<String, Object> dataToJSON(DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException
421    {
422        return null;
423    }
424    
425    public Object dataToJSON(String dataPath, DataContext context) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException
426    {
427        return null;
428    }
429    
430    public boolean hasDifferences(Map<String, Object> values) throws UnknownTypeException, NotUniqueTypeException, BadItemTypeException
431    {
432        return false;
433    }
434    
435    public RepositoryData getRepositoryData()
436    {
437        return null;
438    }
439    
440    public Optional<? extends DataHolder> getParentDataHolder()
441    {
442        return Optional.empty();
443    }
444    
445    public DataHolder getRootDataHolder()
446    {
447        return null;
448    }
449}