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