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}