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    protected final List<SecondaryType> secondaryTypes;
075
076    /** type + secondaryTypes */
077    protected final List<ObjectType> allTypes;
078
079    public static NuxeoObject construct(NuxeoSession session, NuxeoObjectData data, ObjectType type,
080            List<SecondaryType> secondaryTypes) {
081        BaseTypeId baseTypeId = type.getBaseTypeId();
082        switch (baseTypeId) {
083        case CMIS_FOLDER:
084            return new NuxeoFolder(session, data, type, secondaryTypes);
085        case CMIS_DOCUMENT:
086            return new NuxeoDocument(session, data, type, secondaryTypes);
087        case CMIS_POLICY:
088            throw new UnsupportedOperationException(baseTypeId.toString());
089        case CMIS_RELATIONSHIP:
090            return new NuxeoRelationship(session, data, type, secondaryTypes);
091        default:
092            throw new RuntimeException(baseTypeId.toString());
093        }
094    }
095
096    public NuxeoObject(NuxeoSession session, NuxeoObjectData data, ObjectType type,
097            List<SecondaryType> secondaryTypes) {
098        this.session = session;
099        service = session.getService();
100        nuxeoCmisService = NuxeoCmisService.extractFromCmisService(service);
101        objectFactory = session.getObjectFactory();
102        this.data = data;
103        this.type = type;
104        this.secondaryTypes = secondaryTypes;
105        allTypes = new ArrayList<>(1 + secondaryTypes.size());
106        allTypes.add(type);
107        allTypes.addAll(secondaryTypes);
108    }
109
110    @SuppressWarnings("unchecked")
111    @Override
112    public <T> T getAdapter(Class<T> adapterInterface) {
113        throw new CmisRuntimeException("Cannot adapt to " + adapterInterface.getName());
114    }
115
116    public String getRepositoryId() {
117        return session.getRepositoryId();
118    }
119
120    @Override
121    public String getId() {
122        return data.getId();
123    }
124
125    @Override
126    public ObjectType getType() {
127        return type;
128    }
129
130    @Override
131    public BaseTypeId getBaseTypeId() {
132        return data.getBaseTypeId();
133    }
134
135    @Override
136    public ObjectType getBaseType() {
137        return session.getTypeDefinition(getBaseTypeId().value());
138    }
139
140    @Override
141    public List<SecondaryType> getSecondaryTypes() {
142        return secondaryTypes;
143    }
144
145    @Override
146    public List<ObjectType> findObjectType(String id) {
147        List<ObjectType> types = new ArrayList<>(1);
148        for (ObjectType t : allTypes) {
149            if (t.getPropertyDefinitions().containsKey(id)) {
150                types.add(t);
151            }
152        }
153        return types;
154    }
155
156    @Override
157    public String getName() {
158        return NuxeoPropertyDataName.getValue(data.doc);
159    }
160
161    @Override
162    public String getChangeToken() {
163        return getPropertyValue(PropertyIds.CHANGE_TOKEN);
164    }
165
166    @Override
167    public String getCreatedBy() {
168        return getPropertyValue(PropertyIds.CREATED_BY);
169    }
170
171    @Override
172    public GregorianCalendar getCreationDate() {
173        return getPropertyValue(PropertyIds.CREATION_DATE);
174    }
175
176    @Override
177    public GregorianCalendar getLastModificationDate() {
178        return getPropertyValue(PropertyIds.LAST_MODIFICATION_DATE);
179    }
180
181    @Override
182    public String getLastModifiedBy() {
183        return getPropertyValue(PropertyIds.LAST_MODIFIED_BY);
184    }
185
186    @Override
187    public String getDescription() {
188        return getPropertyValue(PropertyIds.DESCRIPTION);
189    }
190
191    @Override
192    public void delete(boolean allVersions) {
193        service.deleteObject(getRepositoryId(), getId(), Boolean.valueOf(allVersions), null);
194    }
195
196    @Override
197    public void delete() {
198        delete(true);
199    }
200
201    @Override
202    public CmisObject updateProperties(Map<String, ?> properties) {
203        ObjectId objectId = updateProperties(properties, true);
204        return session.getObject(objectId);
205    }
206
207    @Override
208    public ObjectId updateProperties(Map<String, ?> properties, boolean refresh) {
209        for (Entry<String, ?> en : properties.entrySet()) {
210            ((NuxeoPropertyDataBase<?>) data.getProperty(en.getKey())).setValue(en.getValue());
211        }
212        CoreSession coreSession = session.getCoreSession();
213        data.doc = coreSession.saveDocument(data.doc);
214        coreSession.save();
215        return this;
216    }
217
218    @Override
219    public CmisObject rename(String newName) {
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);
228    }
229
230    @Override
231    public ObjectId rename(String newName, boolean refresh) {
232        if (newName == null || newName.length() == 0) {
233            throw new IllegalArgumentException("New name must not be empty!");
234        }
235
236        Map<String, Object> prop = new HashMap<String, Object>();
237        prop.put(PropertyIds.NAME, newName);
238
239        return updateProperties(prop, refresh);
240    }
241
242    @SuppressWarnings("unchecked")
243    @Override
244    public <T> T getPropertyValue(String id) {
245        return (T) data.getProperty(id).getValue();
246    }
247
248    @Override
249    public <T> Property<T> getProperty(String id) {
250        return new NuxeoProperty<T>(this, id);
251    }
252
253    @Override
254    public List<Property<?>> getProperties() {
255        List<Property<?>> list = new ArrayList<Property<?>>();
256        for (ObjectType t : allTypes) {
257            Collection<PropertyDefinition<?>> defs = t.getPropertyDefinitions().values();
258            for (PropertyDefinition<?> pd : defs) {
259                list.add(new NuxeoProperty<Object>(this, pd.getId()));
260            }
261        }
262        return list;
263    }
264
265    @Override
266    public Acl addAcl(List<Ace> addAces, AclPropagation aclPropagation) {
267        return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces), null, aclPropagation,
268                null);
269    }
270
271    @Override
272    public Acl applyAcl(List<Ace> addAces, List<Ace> removeAces, AclPropagation aclPropagation) {
273        return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(addAces),
274                objectFactory.convertAces(removeAces), aclPropagation, null);
275    }
276
277    @Override
278    public Acl setAcl(List<Ace> aces) {
279        return service.applyAcl(getRepositoryId(), getId(), objectFactory.convertAces(aces),
280                AclPropagation.REPOSITORYDETERMINED);
281    }
282
283    @Override
284    public Acl getAcl() {
285        return data.getAcl();
286    }
287
288    @Override
289    public Acl removeAcl(List<Ace> removeAces, AclPropagation aclPropagation) {
290        return service.applyAcl(getRepositoryId(), getId(), null, objectFactory.convertAces(removeAces),
291                aclPropagation, null);
292    }
293
294    @Override
295    public AllowableActions getAllowableActions() {
296        // we don't call data.getAllowableActions as includeAllowableActions
297        // may be false
298        return NuxeoObjectData.getAllowableActions(data.doc, data.creation);
299    }
300
301    @Override
302    public List<Policy> getPolicies() {
303        return Collections.emptyList();
304    }
305
306    @Override
307    public void applyPolicy(ObjectId... policyIds) {
308        throw new CmisNotSupportedException();
309    }
310
311    @Override
312    public void removePolicy(ObjectId... policyIds) {
313        throw new CmisNotSupportedException();
314    }
315
316    @Override
317    public List<Relationship> getRelationships() {
318        throw new CmisNotSupportedException();
319    }
320
321    @Override
322    public List<Rendition> getRenditions() {
323        List<RenditionData> renditions = data.getRenditions();
324        if (renditions == null) {
325            return Collections.emptyList();
326        }
327        List<Rendition> res = new ArrayList<Rendition>(renditions.size());
328        for (RenditionData ren : renditions) {
329            long length = ren.getBigLength() == null ? -1 : ren.getBigLength().longValue();
330            int height = ren.getBigHeight() == null ? -1 : ren.getBigHeight().intValue();
331            int width = ren.getBigWidth() == null ? -1 : ren.getBigWidth().intValue();
332            RenditionImpl rendition = new RenditionImpl(session, getId(), ren.getStreamId(),
333                    ren.getRenditionDocumentId(), ren.getKind(), length, ren.getMimeType(), ren.getTitle(), height,
334                    width);
335            res.add(rendition);
336        }
337        return res;
338    }
339
340    @Override
341    public void refresh() {
342        data.doc.refresh();
343    }
344
345    @Override
346    public void refreshIfOld(long durationInMillis) {
347        // TODO Auto-generated method stub
348        throw new UnsupportedOperationException();
349    }
350
351    @Override
352    public long getRefreshTimestamp() {
353        // TODO Auto-generated method stub
354        throw new UnsupportedOperationException();
355    }
356
357    @Override
358    public List<CmisExtensionElement> getExtensions(ExtensionLevel level) {
359        // TODO Auto-generated method stub
360        throw new UnsupportedOperationException();
361    }
362
363    @Override
364    public boolean hasAllowableAction(Action action) {
365        // TODO Auto-generated method stub
366        throw new UnsupportedOperationException();
367    }
368
369    @Override
370    public Set<String> getPermissonsForPrincipal(String principalId) {
371        // TODO Auto-generated method stub
372        throw new UnsupportedOperationException();
373    }
374
375    @Override
376    public Set<String> getPermissionsForPrincipal(String principalId) {
377        throw new UnsupportedOperationException();
378    }
379
380    @Override
381    public void applyPolicy(ObjectId policyId, boolean refresh) {
382        throw new UnsupportedOperationException();
383    }
384
385    @Override
386    public void removePolicy(ObjectId policyId, boolean refresh) {
387        throw new UnsupportedOperationException();
388    }
389
390}