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 ObjectId objectId = updateProperties(properties, true); 211 return session.getObject(objectId); 212 } 213 214 @Override 215 public ObjectId updateProperties(Map<String, ?> properties, boolean refresh) { 216 for (Entry<String, ?> en : properties.entrySet()) { 217 ((NuxeoPropertyDataBase<?>) data.getProperty(en.getKey())).setValue(en.getValue()); 218 } 219 CoreSession coreSession = session.getCoreSession(); 220 data.doc = coreSession.saveDocument(data.doc); 221 coreSession.save(); 222 return this; 223 } 224 225 @Override 226 public CmisObject rename(String newName) { 227 if (newName == null || newName.length() == 0) { 228 throw new IllegalArgumentException("New name must not be empty!"); 229 } 230 231 Map<String, Object> prop = new HashMap<String, Object>(); 232 prop.put(PropertyIds.NAME, newName); 233 234 return updateProperties(prop); 235 } 236 237 @Override 238 public ObjectId rename(String newName, boolean refresh) { 239 if (newName == null || newName.length() == 0) { 240 throw new IllegalArgumentException("New name must not be empty!"); 241 } 242 243 Map<String, Object> prop = new HashMap<String, Object>(); 244 prop.put(PropertyIds.NAME, newName); 245 246 return updateProperties(prop, refresh); 247 } 248 249 @SuppressWarnings("unchecked") 250 @Override 251 public <T> T getPropertyValue(String id) { 252 return (T) data.getProperty(id).getValue(); 253 } 254 255 @Override 256 public <T> Property<T> getProperty(String id) { 257 return new NuxeoProperty<T>(this, id); 258 } 259 260 @Override 261 public List<Property<?>> getProperties() { 262 List<Property<?>> list = new ArrayList<Property<?>>(); 263 for (ObjectType t : allTypes) { 264 Collection<PropertyDefinition<?>> defs = t.getPropertyDefinitions().values(); 265 for (PropertyDefinition<?> pd : defs) { 266 list.add(new NuxeoProperty<Object>(this, pd.getId())); 267 } 268 } 269 return list; 270 } 271 272 @Override 273 public Acl addAcl(List<Ace> addAces, AclPropagation aclPropagation) { 274 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces), null, aclPropagation, 275 null); 276 } 277 278 @Override 279 public Acl applyAcl(List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) { 280 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces), 281 objectFactory.convertAces(removeAces), aclPropagation, null); 282 } 283 284 @Override 285 public Acl setAcl(List<Ace> aces) { 286 return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(aces), 287 AclPropagation.REPOSITORYDETERMINED); 288 } 289 290 @Override 291 public Acl getAcl() { 292 return data.getAcl(); 293 } 294 295 @Override 296 public Acl removeAcl(List<Ace> removeAces, AclPropagation aclPropagation) { 297 return service.applyAcl(getRepositoryId(), getId(), null, objectFactory.convertAces(removeAces), 298 aclPropagation, null); 299 } 300 301 @Override 302 public AllowableActions getAllowableActions() { 303 // we don't call data.getAllowableActions as includeAllowableActions 304 // may be false 305 return NuxeoObjectData.getAllowableActions(data.doc, data.creation); 306 } 307 308 @Override 309 public List<Policy> getPolicies() { 310 return Collections.emptyList(); 311 } 312 313 @Override 314 public void applyPolicy(ObjectId... policyIds) { 315 throw new CmisNotSupportedException(); 316 } 317 318 @Override 319 public void removePolicy(ObjectId... policyIds) { 320 throw new CmisNotSupportedException(); 321 } 322 323 @Override 324 public List<Relationship> getRelationships() { 325 throw new CmisNotSupportedException(); 326 } 327 328 @Override 329 public List<Rendition> getRenditions() { 330 List<RenditionData> renditions = data.getRenditions(); 331 if (renditions == null) { 332 return Collections.emptyList(); 333 } 334 List<Rendition> res = new ArrayList<Rendition>(renditions.size()); 335 for (RenditionData ren : renditions) { 336 long length = ren.getBigLength() == null ? -1 : ren.getBigLength().longValue(); 337 int height = ren.getBigHeight() == null ? -1 : ren.getBigHeight().intValue(); 338 int width = ren.getBigWidth() == null ? -1 : ren.getBigWidth().intValue(); 339 RenditionImpl rendition = new RenditionImpl(session, getId(), ren.getStreamId(), 340 ren.getRenditionDocumentId(), ren.getKind(), length, ren.getMimeType(), ren.getTitle(), height, 341 width); 342 res.add(rendition); 343 } 344 return res; 345 } 346 347 @Override 348 public void refresh() { 349 data.doc.refresh(); 350 } 351 352 @Override 353 public void refreshIfOld(long durationInMillis) { 354 // TODO Auto-generated method stub 355 throw new UnsupportedOperationException(); 356 } 357 358 @Override 359 public long getRefreshTimestamp() { 360 // TODO Auto-generated method stub 361 throw new UnsupportedOperationException(); 362 } 363 364 @Override 365 public List<CmisExtensionElement> getExtensions(ExtensionLevel level) { 366 // TODO Auto-generated method stub 367 throw new UnsupportedOperationException(); 368 } 369 370 @Override 371 public boolean hasAllowableAction(Action action) { 372 // TODO Auto-generated method stub 373 throw new UnsupportedOperationException(); 374 } 375 376 @Override 377 public Set<String> getPermissonsForPrincipal(String principalId) { 378 // TODO Auto-generated method stub 379 throw new UnsupportedOperationException(); 380 } 381 382 @Override 383 public Set<String> getPermissionsForPrincipal(String principalId) { 384 throw new UnsupportedOperationException(); 385 } 386 387 @Override 388 public void applyPolicy(ObjectId policyId, boolean refresh) { 389 throw new UnsupportedOperationException(); 390 } 391 392 @Override 393 public void removePolicy(ObjectId policyId, boolean refresh) { 394 throw new UnsupportedOperationException(); 395 } 396 397}