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.util.ArrayList;
019import java.util.Collection;
020
021import org.apache.chemistry.opencmis.client.api.CmisObject;
022import org.apache.chemistry.opencmis.client.api.Document;
023import org.apache.chemistry.opencmis.client.api.Folder;
024import org.apache.chemistry.opencmis.client.api.ItemIterable;
025import org.apache.chemistry.opencmis.client.api.Session;
026import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
027import org.apache.commons.lang.StringUtils;
028import org.slf4j.Logger;
029import org.slf4j.LoggerFactory;
030
031import org.ametys.plugins.explorer.ExplorerNode;
032import org.ametys.plugins.explorer.resources.ResourceCollection;
033import org.ametys.plugins.repository.AmetysObject;
034import org.ametys.plugins.repository.AmetysRepositoryException;
035import org.ametys.plugins.repository.CollectionIterable;
036import org.ametys.plugins.repository.UnknownAmetysObjectException;
037
038/**
039 * Implementation of an {@link ExplorerNode}, backed by a CMIS server.<br>
040 */
041public class CMISResourcesCollection implements ResourceCollection
042{
043    /** Application id for resources collections. */
044    public static final String APPLICATION_ID = "Ametys.plugins.explorer.applications.resources.Resources";
045
046    private static final Logger __LOGGER = LoggerFactory.getLogger(CMISResourcesCollection.class);
047    
048    private final Folder _cmisFolder;
049    private final CMISRootResourcesCollection _root;
050    private AmetysObject _parent;
051    
052    /**
053     * Creates a {@link CMISResourcesCollection}
054     * @param folder The CMIS folder
055     * @param root The root of the virtual tree
056     * @param parent the parent {@link AmetysObject} if known
057     */
058    public CMISResourcesCollection(Folder folder, CMISRootResourcesCollection root, AmetysObject parent)
059    {
060        _cmisFolder = folder;
061        _root = root;
062        _parent = parent;
063    }
064    
065    @Override
066    public String getApplicationId()
067    {
068        return APPLICATION_ID;
069    }
070
071    @Override
072    public String getIconCls()
073    {
074        return "ametysicon-folder249";
075    }
076
077    @Override
078    public String getId() throws AmetysRepositoryException
079    {
080        return getCmisRoot().getId() + "/" + getCmisFolder().getId();
081    }
082
083    @Override
084    public String getName() throws AmetysRepositoryException
085    {
086        return getCmisFolder().getName();
087    }
088    
089    /**
090     * Retrieves the {@link CMISRootResourcesCollection}
091     * @return the {@link CMISRootResourcesCollection}
092     */
093    public CMISRootResourcesCollection getCmisRoot ()
094    {
095        return _root;
096    }
097    
098    /**
099     * Retrieves the {@link Folder}
100     * @return the {@link Folder}
101     */
102    public Folder getCmisFolder ()
103    {
104        return _cmisFolder;
105    }
106
107    @SuppressWarnings("unchecked")
108    @Override
109    public AmetysObject getParent() throws AmetysRepositoryException
110    {
111        if (_parent != null)
112        {
113            return _parent;
114        }
115        
116        // iterate on all parents and returns the first valid parent
117        String rootPath = _root.getRootFolder().getPath();
118        String rootId = _root.getRootFolder().getId();
119        for (Folder parent : _cmisFolder.getParents())
120        {
121            // check if the parent is valid by making sure that it is below the root folder
122            // This is necessary to unsure that the parent is included in the mount point
123            if (StringUtils.contains(parent.getPath(), rootPath))
124            {
125                if (StringUtils.equals(parent.getId(), rootId))
126                {
127                    _parent = getCmisRoot();
128                }
129                else
130                {
131                    _parent = new CMISResourcesCollection(parent, _root, null);
132                }
133                return _parent;
134            }
135        }
136        
137        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.");
138    }
139
140    @Override
141    public String getParentPath() throws AmetysRepositoryException
142    {
143        return getParent().getPath();
144    }
145
146    @Override
147    public String getPath() throws AmetysRepositoryException
148    {
149        return getParentPath() + "/" + getName();
150    }
151    
152    @Override
153    @SuppressWarnings("unchecked")
154    public AmetysObject getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
155    {
156        Session session = getCmisRoot().getSession();
157        if (session == null)
158        {
159            throw new UnknownAmetysObjectException("Failed to connect to CMIS server");
160        }
161        
162        CmisObject child = session.getObjectByPath(path);
163        BaseTypeId baseTypeId = child.getBaseType().getBaseTypeId();
164        
165        if (baseTypeId.equals(BaseTypeId.CMIS_FOLDER))
166        {
167            return new CMISResourcesCollection((Folder) child, _root, this);
168        }
169        if (baseTypeId.equals(BaseTypeId.CMIS_DOCUMENT))
170        {
171            Document cmisDoc = (Document) child;
172            // Check if CMIS document has content, if not ignore it
173            if (cmisDoc.getContentStream() != null)
174            {
175                return new CMISResource((Document) child, _root, this);
176            }
177            throw new UnknownAmetysObjectException("The CMIS document " + path + " has no content");
178        }
179        else
180        {
181            throw new UnknownAmetysObjectException("Unhandled CMIS type '" + baseTypeId + "', cannot get child at path " + path);
182        }
183    }
184
185    
186    @Override
187    public CollectionIterable<AmetysObject> getChildren() throws AmetysRepositoryException
188    {
189        Collection<AmetysObject> aoChildren = new ArrayList<>();
190        
191        ItemIterable<CmisObject> children = getCmisFolder().getChildren();
192        for (CmisObject child : children)
193        {
194            BaseTypeId baseTypeId = child.getBaseTypeId();
195            if (baseTypeId.equals(BaseTypeId.CMIS_FOLDER))
196            {
197                aoChildren.add(new CMISResourcesCollection((Folder) child, _root, this));
198            }
199            else if (baseTypeId.equals(BaseTypeId.CMIS_DOCUMENT))
200            {
201                Document cmisDoc = (Document) child;
202                
203                // Check if CMIS document has content, if not ignore it
204                if (StringUtils.isNotEmpty(cmisDoc.getContentStreamFileName()))
205                {
206                    aoChildren.add(new CMISResource(cmisDoc, _root, this));
207                }
208            }
209            else
210            {
211                __LOGGER.warn("Unhandled CMIS type {}. It will be ignored.", baseTypeId);
212            }
213        }
214
215        return new CollectionIterable<>(aoChildren);
216    }
217
218    @Override
219    public boolean hasChild(String name) throws AmetysRepositoryException
220    {
221        ItemIterable<CmisObject> children = _cmisFolder.getChildren();
222        for (CmisObject child : children)
223        {
224            if (child.getName().equals(name))
225            {
226                return true;
227            }
228        }
229        
230        return false;
231    }
232    
233    public boolean hasChildResources() throws AmetysRepositoryException
234    {
235        // we don't actually know if there are children or not,
236        // but it's an optimization to don't make another CMIS request
237        return true;
238    }
239    
240    public boolean hasChildExplorerNodes() throws AmetysRepositoryException
241    {
242        // we don't actually know if there are children or not,
243        // but it's an optimization to don't make another CMIS request
244        return true;
245    }
246    
247    @Override
248    public String getExplorerPath()
249    {
250        AmetysObject parent = getParent();
251        
252        if (parent instanceof ExplorerNode)
253        {
254            return ((ExplorerNode) parent).getExplorerPath() + "/" + getName();
255        }
256        else
257        {
258            return "";
259        }
260    }
261    
262    @Override
263    public String getResourcePath() throws AmetysRepositoryException
264    {
265        return getExplorerPath();
266    }
267    
268    @Override
269    public String getDescription()
270    {
271        return null;
272    }
273}