001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 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 * 016 * Contributors: 017 * Florent Guillaume 018 */ 019package org.nuxeo.ecm.core.opencmis.impl.client; 020 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.GregorianCalendar; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028import java.util.Map.Entry; 029import java.util.Set; 030 031import org.apache.chemistry.opencmis.client.api.CmisObject; 032import org.apache.chemistry.opencmis.client.api.ObjectId; 033import org.apache.chemistry.opencmis.client.api.ObjectType; 034import org.apache.chemistry.opencmis.client.api.Policy; 035import org.apache.chemistry.opencmis.client.api.Property; 036import org.apache.chemistry.opencmis.client.api.Relationship; 037import org.apache.chemistry.opencmis.client.api.Rendition; 038import org.apache.chemistry.opencmis.client.api.SecondaryType; 039import org.apache.chemistry.opencmis.client.runtime.RenditionImpl; 040import org.apache.chemistry.opencmis.commons.PropertyIds; 041import org.apache.chemistry.opencmis.commons.data.Ace; 042import org.apache.chemistry.opencmis.commons.data.Acl; 043import org.apache.chemistry.opencmis.commons.data.AllowableActions; 044import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement; 045import org.apache.chemistry.opencmis.commons.data.RenditionData; 046import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition; 047import org.apache.chemistry.opencmis.commons.enums.AclPropagation; 048import org.apache.chemistry.opencmis.commons.enums.Action; 049import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; 050import org.apache.chemistry.opencmis.commons.enums.ExtensionLevel; 051import org.apache.chemistry.opencmis.commons.enums.Updatability; 052import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException; 053import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException; 054import org.apache.chemistry.opencmis.commons.server.CmisService; 055import org.nuxeo.ecm.core.api.CoreSession; 056import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoCmisService; 057import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoObjectData; 058import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoPropertyData.NuxeoPropertyDataName; 059import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoPropertyDataBase; 060 061/** 062 * Base abstract live local CMIS Object, wrapping a {@link NuxeoSession} and a {@link NuxeoObjectData} which is backed 063 * by a Nuxeo document. 064 */ 065public abstract class NuxeoObject implements CmisObject { 066 067 protected static final Set<Updatability> UPDATABILITY_READWRITE = Collections.singleton(Updatability.READWRITE); 068 069 protected final NuxeoSession session; 070 071 protected final CmisService service; 072 073 protected final NuxeoCmisService nuxeoCmisService; 074 075 protected final NuxeoObjectFactory objectFactory; 076 077 public final NuxeoObjectData data; 078 079 protected final ObjectType type; 080 081 protected final List<SecondaryType> secondaryTypes; 082 083 /** type + secondaryTypes */ 084 protected final List<ObjectType> allTypes; 085 086 public static NuxeoObject construct(NuxeoSession session, NuxeoObjectData data, ObjectType type, 087 List<SecondaryType> secondaryTypes) { 088 BaseTypeId baseTypeId = type.getBaseTypeId(); 089 switch (baseTypeId) { 090 case CMIS_FOLDER: 091 return new NuxeoFolder(session, data, type, secondaryTypes); 092 case CMIS_DOCUMENT: 093 return new NuxeoDocument(session, data, type, secondaryTypes); 094 case CMIS_POLICY: 095 throw new UnsupportedOperationException(baseTypeId.toString()); 096 case CMIS_RELATIONSHIP: 097 return new NuxeoRelationship(session, data, type, secondaryTypes); 098 default: 099 throw new RuntimeException(baseTypeId.toString()); 100 } 101 } 102 103 public NuxeoObject(NuxeoSession session, NuxeoObjectData data, ObjectType type, 104 List<SecondaryType> secondaryTypes) { 105 this.session = session; 106 service = session.getService(); 107 nuxeoCmisService = NuxeoCmisService.extractFromCmisService(service); 108 objectFactory = session.getObjectFactory(); 109 this.data = data; 110 this.type = type; 111 this.secondaryTypes = secondaryTypes; 112 allTypes = new ArrayList<>(1 + secondaryTypes.size()); 113 allTypes.add(type); 114 allTypes.addAll(secondaryTypes); 115 } 116 117 @SuppressWarnings("unchecked") 118 @Override 119 public <T> T getAdapter(Class<T> adapterInterface) { 120 throw new CmisRuntimeException("Cannot adapt to " + adapterInterface.getName()); 121 } 122 123 public String getRepositoryId() { 124 return session.getRepositoryId(); 125 } 126 127 @Override 128 public String getId() { 129 return data.getId(); 130 } 131 132 @Override 133 public ObjectType getType() { 134 return type; 135 } 136 137 @Override 138 public BaseTypeId getBaseTypeId() { 139 return data.getBaseTypeId(); 140 } 141 142 @Override 143 public ObjectType getBaseType() { 144 return session.getTypeDefinition(getBaseTypeId().value()); 145 } 146 147 @Override 148 public List<SecondaryType> getSecondaryTypes() { 149 return secondaryTypes; 150 } 151 152 @Override 153 public List<ObjectType> findObjectType(String id) { 154 List<ObjectType> types = new ArrayList<>(1); 155 for (ObjectType t : allTypes) { 156 if (t.getPropertyDefinitions().containsKey(id)) { 157 types.add(t); 158 } 159 } 160 return types; 161 } 162 163 @Override 164 public String getName() { 165 return NuxeoPropertyDataName.getValue(data.doc); 166 } 167 168 @Override 169 public String getChangeToken() { 170 return getPropertyValue(PropertyIds.CHANGE_TOKEN); 171 } 172 173 @Override 174 public String getCreatedBy() { 175 return getPropertyValue(PropertyIds.CREATED_BY); 176 } 177 178 @Override 179 public GregorianCalendar getCreationDate() { 180 return getPropertyValue(PropertyIds.CREATION_DATE); 181 } 182 183 @Override 184 public GregorianCalendar getLastModificationDate() { 185 return getPropertyValue(PropertyIds.LAST_MODIFICATION_DATE); 186 } 187 188 @Override 189 public String getLastModifiedBy() { 190 return getPropertyValue(PropertyIds.LAST_MODIFIED_BY); 191 } 192 193 @Override 194 public String getDescription() { 195 return getPropertyValue(PropertyIds.DESCRIPTION); 196 } 197 198 @Override 199 public void delete(boolean allVersions) { 200 service.deleteObject(getRepositoryId(), getId(), Boolean.valueOf(allVersions), null); 201 } 202 203 @Override 204 public void delete() { 205 delete(true); 206 } 207 208 @Override 209 public CmisObject updateProperties(Map<String, ?> properties) { 210 return updateProperties(properties, null, null); 211 } 212 213 @Override 214 public ObjectId updateProperties(Map<String, ?> properties, boolean refresh) { 215 return updateProperties(properties, null, null, refresh); 216 } 217 218 @Override 219 public CmisObject updateProperties(Map<String, ?> properties, List<String> addSecondaryTypeIds, 220 List<String> removeSecondaryTypeIds) { 221 ObjectId objectId = updateProperties(properties, addSecondaryTypeIds, removeSecondaryTypeIds, true); 222 return session.getObject(objectId); 223 } 224 225 @Override 226 public ObjectId updateProperties(Map<String, ?> properties, List<String> addSecondaryTypeIds, 227 List<String> removeSecondaryTypeIds, boolean refresh) { 228 // refresh is ignored 229 if (addSecondaryTypeIds != null) { 230 for (String facet : addSecondaryTypeIds) { 231 data.doc.addFacet(facet); 232 } 233 } 234 if (removeSecondaryTypeIds != null) { 235 for (String facet : removeSecondaryTypeIds) { 236 data.doc.removeFacet(facet); 237 } 238 } 239 if (properties != null) { 240 for (Entry<String, ?> en : properties.entrySet()) { 241 ((NuxeoPropertyDataBase<?>) data.getProperty(en.getKey())).setValue(en.getValue()); 242 } 243 } 244 CoreSession coreSession = session.getCoreSession(); 245 data.doc = coreSession.saveDocument(data.doc); 246 coreSession.save(); 247 return this; 248 } 249 250 @Override 251 public CmisObject rename(String newName) { 252 if (newName == null || newName.length() == 0) { 253 throw new IllegalArgumentException("New name must not be empty!"); 254 } 255 256 Map<String, Object> prop = new HashMap<String, Object>(); 257 prop.put(PropertyIds.NAME, newName); 258 259 return updateProperties(prop); 260 } 261 262 @Override 263 public ObjectId rename(String newName, boolean refresh) { 264 if (newName == null || newName.length() == 0) { 265 throw new IllegalArgumentException("New name must not be empty!"); 266 } 267 268 Map<String, Object> prop = new HashMap<String, Object>(); 269 prop.put(PropertyIds.NAME, newName); 270 271 return updateProperties(prop, refresh); 272 } 273 274 @SuppressWarnings("unchecked") 275 @Override 276 public <T> T getPropertyValue(String id) { 277 return (T) data.getProperty(id).getValue(); 278 } 279 280 @Override 281 public <T> Property<T> getProperty(String id) { 282 return new NuxeoProperty<T>(this, id); 283 } 284 285 @Override 286 public List<Property<?>> getProperties() { 287 List<Property<?>> list = new ArrayList<Property<?>>(); 288 for (ObjectType t : allTypes) { 289 Collection<PropertyDefinition<?>> defs = t.getPropertyDefinitions().values(); 290 for (PropertyDefinition<?> pd : defs) { 291 list.add(new NuxeoProperty<Object>(this, pd.getId())); 292 } 293 } 294 return list; 295 } 296 297 @Override 298 public Acl addAcl(List<Ace> addAces, AclPropagation aclPropagation) { 299 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces), null, aclPropagation, 300 null); 301 } 302 303 @Override 304 public Acl applyAcl(List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) { 305 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces), 306 objectFactory.convertAces(removeAces), aclPropagation, null); 307 } 308 309 @Override 310 public Acl setAcl(List<Ace> aces) { 311 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(aces), 312 AclPropagation.REPOSITORYDETERMINED); 313 } 314 315 @Override 316 public Acl getAcl() { 317 return data.getAcl(); 318 } 319 320 @Override 321 public Acl removeAcl(List<Ace> removeAces, AclPropagation aclPropagation) { 322 return service.applyAcl(getRepositoryId(), getId(), null, objectFactory.convertAces(removeAces), 323 aclPropagation, null); 324 } 325 326 @Override 327 public AllowableActions getAllowableActions() { 328 // we don't call data.getAllowableActions as includeAllowableActions 329 // may be false 330 return NuxeoObjectData.getAllowableActions(data.doc, data.creation); 331 } 332 333 @Override 334 public List<Policy> getPolicies() { 335 return Collections.emptyList(); 336 } 337 338 @Override 339 public void applyPolicy(ObjectId... policyIds) { 340 throw new CmisNotSupportedException(); 341 } 342 343 @Override 344 public void removePolicy(ObjectId... policyIds) { 345 throw new CmisNotSupportedException(); 346 } 347 348 @Override 349 public List<Relationship> getRelationships() { 350 throw new CmisNotSupportedException(); 351 } 352 353 @Override 354 public List<Rendition> getRenditions() { 355 List<RenditionData> renditions = data.getRenditions(); 356 if (renditions == null) { 357 return Collections.emptyList(); 358 } 359 List<Rendition> res = new ArrayList<Rendition>(renditions.size()); 360 for (RenditionData ren : renditions) { 361 long length = ren.getBigLength() == null ? -1 : ren.getBigLength().longValue(); 362 int height = ren.getBigHeight() == null ? -1 : ren.getBigHeight().intValue(); 363 int width = ren.getBigWidth() == null ? -1 : ren.getBigWidth().intValue(); 364 RenditionImpl rendition = new RenditionImpl(session, getId(), ren.getStreamId(), 365 ren.getRenditionDocumentId(), ren.getKind(), length, ren.getMimeType(), ren.getTitle(), height, 366 width); 367 res.add(rendition); 368 } 369 return res; 370 } 371 372 @Override 373 public void refresh() { 374 data.doc.refresh(); 375 } 376 377 @Override 378 public void refreshIfOld(long durationInMillis) { 379 // TODO Auto-generated method stub 380 throw new UnsupportedOperationException(); 381 } 382 383 @Override 384 public long getRefreshTimestamp() { 385 // TODO Auto-generated method stub 386 throw new UnsupportedOperationException(); 387 } 388 389 @Override 390 public List<CmisExtensionElement> getExtensions(ExtensionLevel level) { 391 // TODO Auto-generated method stub 392 throw new UnsupportedOperationException(); 393 } 394 395 @Override 396 public boolean hasAllowableAction(Action action) { 397 // TODO Auto-generated method stub 398 throw new UnsupportedOperationException(); 399 } 400 401 @Override 402 public Set<String> getPermissionsForPrincipal(String principalId) { 403 throw new UnsupportedOperationException(); 404 } 405 406 @Override 407 public void applyPolicy(ObjectId policyId, boolean refresh) { 408 throw new UnsupportedOperationException(); 409 } 410 411 @Override 412 public void removePolicy(ObjectId policyId, boolean refresh) { 413 throw new UnsupportedOperationException(); 414 } 415 416}