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}