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 "folder";
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        Session session = getCmisRoot().getSession();
117        if (session == null)
118        {
119            throw new UnknownAmetysObjectException("Failed to connect to CMIS server");
120        }
121        
122        String parentId = _cmisFolder.getParentId();
123        Folder parent = (Folder) session.getObject(parentId);
124        
125        if (parent.isRootFolder())
126        {
127            _parent = getCmisRoot();
128            return _parent;
129        }
130        else
131        {
132            _parent = new CMISResourcesCollection(parent, _root, null);
133            return _parent;
134        }
135    }
136
137    @Override
138    public String getParentPath() throws AmetysRepositoryException
139    {
140        return getParent().getPath();
141    }
142
143    @Override
144    public String getPath() throws AmetysRepositoryException
145    {
146        return getParentPath() + "/" + getName();
147    }
148    
149    @Override
150    @SuppressWarnings("unchecked")
151    public AmetysObject getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException
152    {
153        Session session = getCmisRoot().getSession();
154        if (session == null)
155        {
156            throw new UnknownAmetysObjectException("Failed to connect to CMIS server");
157        }
158        
159        CmisObject child = session.getObjectByPath(path);
160        BaseTypeId baseTypeId = child.getBaseType().getBaseTypeId(); 
161        
162        if (baseTypeId.equals(BaseTypeId.CMIS_FOLDER))
163        {
164            return new CMISResourcesCollection((Folder) child, _root, this);            
165        }
166        if (baseTypeId.equals(BaseTypeId.CMIS_DOCUMENT))
167        {
168            Document cmisDoc = (Document) child;
169            // Check if CMIS document has content, if not ignore it
170            if (cmisDoc.getContentStream() != null)
171            {
172                return new CMISResource((Document) child, _root, this);  
173            }
174            throw new UnknownAmetysObjectException("The CMIS document " + path + " has no content");   
175        }
176        else
177        {
178            throw new UnknownAmetysObjectException("Unhandled CMIS type '" + baseTypeId + "', cannot get child at path " + path);
179        }
180    }
181
182    
183    @Override
184    public CollectionIterable<AmetysObject> getChildren() throws AmetysRepositoryException
185    {
186        Collection<AmetysObject> aoChildren = new ArrayList<>();
187        
188        ItemIterable<CmisObject> children = getCmisFolder().getChildren();
189        for (CmisObject child : children)
190        {
191            BaseTypeId baseTypeId = child.getBaseTypeId(); 
192            if (baseTypeId.equals(BaseTypeId.CMIS_FOLDER))
193            {
194                aoChildren.add(new CMISResourcesCollection((Folder) child, _root, this));
195            }
196            else if (baseTypeId.equals(BaseTypeId.CMIS_DOCUMENT))
197            {
198                Document cmisDoc = (Document) child;
199                
200                // Check if CMIS document has content, if not ignore it
201                if (StringUtils.isNotEmpty(cmisDoc.getContentStreamFileName()))
202                {
203                    aoChildren.add(new CMISResource(cmisDoc, _root, this));
204                }
205            }
206            else
207            {
208                __LOGGER.warn("Unhandled CMIS type {}. It will be ignored.", baseTypeId);
209            }
210        }
211
212        return new CollectionIterable<>(aoChildren);
213    }
214
215    @Override
216    public boolean hasChild(String name) throws AmetysRepositoryException
217    {
218        ItemIterable<CmisObject> children = _cmisFolder.getChildren();
219        for (CmisObject child : children)
220        {
221            if (child.getName().equals(name))
222            {
223                return true;
224            }
225        }
226        
227        return false;
228    }
229    
230    public boolean hasChildResources() throws AmetysRepositoryException
231    {
232        // we don't actually know if there are children or not, 
233        // but it's an optimization to don't make another CMIS request
234        return true;
235    }
236    
237    public boolean hasChildExplorerNodes() throws AmetysRepositoryException
238    {
239        // we don't actually know if there are children or not, 
240        // but it's an optimization to don't make another CMIS request
241        return true;
242    }
243    
244    @Override
245    public String getExplorerPath()
246    {
247        AmetysObject parent = getParent();
248        
249        if (parent instanceof ExplorerNode)
250        {
251            return ((ExplorerNode) parent).getExplorerPath() + "/" + getName();
252        }
253        else
254        {
255            return "";
256        }
257    }
258    
259    @Override
260    public String getResourcePath() throws AmetysRepositoryException
261    {
262        return getExplorerPath();
263    }
264    
265    @Override
266    public String getDescription()
267    {
268        return null;
269    }
270}