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 javax.jcr.Node; 022import javax.jcr.RepositoryException; 023import javax.jcr.nodetype.ConstraintViolationException; 024 025import org.apache.chemistry.opencmis.client.api.CmisObject; 026import org.apache.chemistry.opencmis.client.api.Document; 027import org.apache.chemistry.opencmis.client.api.Folder; 028import org.apache.chemistry.opencmis.client.api.ItemIterable; 029import org.apache.chemistry.opencmis.client.api.Session; 030import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; 031import org.apache.commons.lang.StringUtils; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035import org.ametys.plugins.explorer.ExplorerNode; 036import org.ametys.plugins.explorer.resources.ResourceCollection; 037import org.ametys.plugins.repository.AbstractAmetysObject; 038import org.ametys.plugins.repository.AmetysObject; 039import org.ametys.plugins.repository.AmetysRepositoryException; 040import org.ametys.plugins.repository.CollectionIterable; 041import org.ametys.plugins.repository.RepositoryIntegrityViolationException; 042import org.ametys.plugins.repository.UnknownAmetysObjectException; 043import org.ametys.plugins.repository.jcr.JCRAmetysObject; 044import org.ametys.plugins.repository.jcr.SimpleAmetysObjectFactory; 045import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata; 046import org.ametys.plugins.repository.metadata.jcr.JCRCompositeMetadata; 047 048/** 049 * {@link AmetysObject} implementing the root of {@link CMISResourcesCollection}s 050 */ 051public class CMISRootResourcesCollection extends AbstractAmetysObject implements JCRAmetysObject, ResourceCollection 052{ 053 /** application id for resources collections. */ 054 public static final String APPLICATION_ID = "Ametys.plugins.explorer.applications.resources.Resources"; 055 056 /** Metadata for repository id */ 057 public static final String METADATA_REPOSITORY_ID = "repositoryId"; 058 /** Metadata for repository url */ 059 public static final String METADATA_REPOSITORY_URL = "repositoryUrl"; 060 /** Metadata for user login */ 061 public static final String METADATA_USER = "user"; 062 /** Metadata for user password */ 063 public static final String METADATA_PASSWORD = "password"; 064 065 private static final Logger __LOGGER = LoggerFactory.getLogger(CMISResourcesCollection.class); 066 067 /** The corresponding {@link SimpleAmetysObjectFactory} */ 068 private final CMISTreeFactory _factory; 069 070 private final Node _node; 071 072 private String _name; 073 private String _parentPath; 074 075 private Session _session; 076 private Folder _root; 077 078 /** 079 * Creates a {@link CMISRootResourcesCollection}. 080 * @param node the node backing this {@link AmetysObject} 081 * @param parentPath the parentPath in the Ametys hierarchy 082 * @param factory the CMISRootResourcesCollectionFactory which created this AmetysObject 083 */ 084 public CMISRootResourcesCollection(Node node, String parentPath, CMISTreeFactory factory) 085 { 086 _node = node; 087 _parentPath = parentPath; 088 _factory = factory; 089 090 try 091 { 092 _name = _node.getName(); 093 } 094 catch (RepositoryException e) 095 { 096 throw new AmetysRepositoryException("Unable to get node name", e); 097 } 098 } 099 100 void connect(Session session, Folder root) 101 { 102 _session = session; 103 _root = root; 104 } 105 106 Session getSession() 107 { 108 return _session; 109 } 110 111 Folder getRootFolder() 112 { 113 return _root; 114 } 115 116 @SuppressWarnings("unchecked") 117 @Override 118 public AmetysObject getChild(String path) throws AmetysRepositoryException, UnknownAmetysObjectException 119 { 120 // Test if path begins with "/" and does not ends with "/" (Chemistry restriction) 121 String childPath = path; 122 if (!path.startsWith("/")) 123 { 124 childPath = "/" + path; 125 } 126 if (path.endsWith("/") && path.length() != 1) 127 { 128 childPath = path.substring(0, path.length() - 1); 129 } 130 131 if (_session == null) 132 { 133 throw new UnknownAmetysObjectException("Failed to connect to CMIS server"); 134 } 135 136 CmisObject entry = _session.getObjectByPath(childPath); 137 CmisObject object = _session.getObject(entry); 138 139 BaseTypeId baseTypeId = object.getBaseType().getBaseTypeId(); 140 141 if (baseTypeId.equals(BaseTypeId.CMIS_FOLDER)) 142 { 143 return new CMISResourcesCollection((Folder) object, this, this); 144 } 145 else if (baseTypeId.equals(BaseTypeId.CMIS_DOCUMENT)) 146 { 147 return new CMISResource((Document) object, this, this); 148 } 149 else 150 { 151 throw new UnknownAmetysObjectException("Unhandled CMIS type '" + baseTypeId + "', cannot get child at path " + path); 152 } 153 } 154 155 @Override 156 public CollectionIterable<AmetysObject> getChildren() throws AmetysRepositoryException 157 { 158 Collection<AmetysObject> aoChildren = new ArrayList<>(); 159 160 if (_session == null) 161 { 162 return new CollectionIterable<>(aoChildren); 163 } 164 165 ItemIterable<CmisObject> children = _root.getChildren(); 166 167 for (CmisObject child : children) 168 { 169 BaseTypeId typeId = child.getBaseTypeId(); 170 171 if (typeId.equals(BaseTypeId.CMIS_FOLDER)) 172 { 173 aoChildren.add(new CMISResourcesCollection((Folder) child, this, this)); 174 } 175 else if (typeId.equals(BaseTypeId.CMIS_DOCUMENT)) 176 { 177 Document cmisDoc = (Document) child; 178 179 // Check if CMIS document has content, if not ignore it 180 if (StringUtils.isNotEmpty(cmisDoc.getContentStreamFileName())) 181 { 182 aoChildren.add(new CMISResource(cmisDoc, this, this)); 183 } 184 } 185 else 186 { 187 __LOGGER.warn("Unhandled CMIS type {}. It will be ignored.", typeId); 188 } 189 } 190 191 return new CollectionIterable<>(aoChildren); 192 } 193 194 @Override 195 public boolean hasChild(String name) throws AmetysRepositoryException 196 { 197 if (_session == null) 198 { 199 return false; 200 } 201 202 ItemIterable<CmisObject> children = _root.getChildren(); 203 for (CmisObject child : children) 204 { 205 if (child.getName().equals(name)) 206 { 207 return true; 208 } 209 } 210 211 return false; 212 } 213 214 @Override 215 public ModifiableCompositeMetadata getMetadataHolder() 216 { 217 return new JCRCompositeMetadata(getNode(), _factory._resolver); 218 } 219 220 @Override 221 public String getIconCls() 222 { 223 if (_session == null) 224 { 225 return "cmis-failed"; 226 } 227 228 String productName = _session.getRepositoryInfo().getProductName(); 229 if (productName.toLowerCase().indexOf("alfresco") != -1) 230 { 231 return "cmis-alfresco"; 232 } 233 else if (productName.toLowerCase().indexOf("nuxeo") != -1) 234 { 235 return "cmis-nuxeo"; 236 } 237 238 return "cmis"; 239 } 240 241 @Override 242 public String getApplicationId() 243 { 244 return APPLICATION_ID; 245 } 246 247 @Override 248 public String getName() throws AmetysRepositoryException 249 { 250 return _name; 251 } 252 253 @Override 254 public String getParentPath() throws AmetysRepositoryException 255 { 256 if (_parentPath == null) 257 { 258 _parentPath = getParent().getPath(); 259 } 260 261 return _parentPath; 262 } 263 264 @Override 265 public String getPath() throws AmetysRepositoryException 266 { 267 return getParentPath() + "/" + getName(); 268 } 269 270 @Override 271 public Node getNode() 272 { 273 return _node; 274 } 275 276 @Override 277 public String getId() 278 { 279 try 280 { 281 return _factory.getScheme() + "://" + _node.getIdentifier(); 282 } 283 catch (RepositoryException e) 284 { 285 throw new AmetysRepositoryException("Unable to get node UUID", e); 286 } 287 } 288 289 public boolean hasChildResources() throws AmetysRepositoryException 290 { 291 // we don't actually know if there are children or not, 292 // but it's an optimization to don't make another CMIS request 293 return true; 294 } 295 296 public boolean hasChildExplorerNodes() throws AmetysRepositoryException 297 { 298 // we don't actually know if there are children or not, 299 // but it's an optimization to don't make another CMIS request 300 return true; 301 } 302 303 @Override 304 public void rename(String newName) throws AmetysRepositoryException 305 { 306 try 307 { 308 getNode().getSession().move(getNode().getPath(), getNode().getParent().getPath() + "/" + newName); 309 } 310 catch (RepositoryException e) 311 { 312 throw new AmetysRepositoryException(e); 313 } 314 } 315 316 @Override 317 public void remove() throws AmetysRepositoryException, RepositoryIntegrityViolationException 318 { 319 try 320 { 321 getNode().remove(); 322 } 323 catch (ConstraintViolationException e) 324 { 325 throw new RepositoryIntegrityViolationException(e); 326 } 327 catch (RepositoryException e) 328 { 329 throw new AmetysRepositoryException(e); 330 } 331 } 332 333 @SuppressWarnings("unchecked") 334 @Override 335 public <A extends AmetysObject> A getParent() throws AmetysRepositoryException 336 { 337 return (A) _factory.getParent(this); 338 } 339 340 @Override 341 public void saveChanges() throws AmetysRepositoryException 342 { 343 try 344 { 345 getNode().getSession().save(); 346 } 347 catch (javax.jcr.RepositoryException e) 348 { 349 throw new AmetysRepositoryException("Unable to save changes", e); 350 } 351 } 352 353 @Override 354 public void revertChanges() throws AmetysRepositoryException 355 { 356 try 357 { 358 getNode().refresh(false); 359 } 360 catch (javax.jcr.RepositoryException e) 361 { 362 throw new AmetysRepositoryException("Unable to revert changes.", e); 363 } 364 } 365 366 @Override 367 public boolean needsSave() throws AmetysRepositoryException 368 { 369 try 370 { 371 return _node.getSession().hasPendingChanges(); 372 } 373 catch (RepositoryException e) 374 { 375 throw new AmetysRepositoryException(e); 376 } 377 } 378 379 @Override 380 public String getResourcePath() throws AmetysRepositoryException 381 { 382 return getExplorerPath(); 383 } 384 385 @Override 386 public String getExplorerPath() 387 { 388 AmetysObject parent = getParent(); 389 390 if (parent instanceof ExplorerNode) 391 { 392 return ((ExplorerNode) parent).getExplorerPath() + "/" + getName(); 393 } 394 else 395 { 396 return ""; 397 } 398 } 399 400 /** 401 * Get the user to connect to CMIS repository 402 * @return the user login 403 * @throws AmetysRepositoryException if an error occurred 404 */ 405 public String getUser() throws AmetysRepositoryException 406 { 407 return getMetadataHolder().getString(METADATA_USER); 408 } 409 410 /** 411 * Get the password to connect to CMIS repository 412 * @return the user password 413 * @throws AmetysRepositoryException if an error occurred 414 */ 415 public String getPassword() throws AmetysRepositoryException 416 { 417 return getMetadataHolder().getString(METADATA_PASSWORD); 418 } 419 420 /** 421 * Get the CMIS repository URL 422 * @return the CMIS repository URL 423 * @throws AmetysRepositoryException if an error occurred 424 */ 425 public String getRepositoryUrl() throws AmetysRepositoryException 426 { 427 return getMetadataHolder().getString(METADATA_REPOSITORY_URL); 428 } 429 430 /** 431 * Get the CMIS repository id 432 * @return the CMIS repository id 433 * @throws AmetysRepositoryException if an error occurred 434 */ 435 public String getRepositoryId () throws AmetysRepositoryException 436 { 437 return getMetadataHolder().getString(METADATA_REPOSITORY_ID); 438 } 439 440 /** 441 * Set the URL of the CMIS repository 442 * @param url the CMIS repository URL 443 * @throws AmetysRepositoryException if an error occurred 444 */ 445 public void setRepositoryUrl(String url) throws AmetysRepositoryException 446 { 447 getMetadataHolder().setMetadata(METADATA_REPOSITORY_URL, url); 448 } 449 450 /** 451 * Set the id of the CMIS repository 452 * @param id the CMIS repository id 453 * @throws AmetysRepositoryException if an error occurred 454 */ 455 public void setRepositoryId(String id) throws AmetysRepositoryException 456 { 457 getMetadataHolder().setMetadata(METADATA_REPOSITORY_ID, id); 458 } 459 460 /** 461 * Set a user name for the CMIS Repository 462 * @param user the login 463 */ 464 public void setUser(String user) 465 { 466 getMetadataHolder().setMetadata(METADATA_USER, user); 467 } 468 469 /** 470 * Set a password for the CMIS Repository 471 * @param password the password 472 */ 473 public void setPassword(String password) 474 { 475 getMetadataHolder().setMetadata(METADATA_PASSWORD, password); 476 } 477 478 @Override 479 public String getDescription() 480 { 481 return null; 482 } 483}