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