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