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.io.InputStream;
015import java.math.BigDecimal;
016import java.math.BigInteger;
017import java.util.ArrayList;
018import java.util.Collection;
019import java.util.Collections;
020import java.util.GregorianCalendar;
021import java.util.List;
022import java.util.Map;
023import java.util.Map.Entry;
024import java.util.Set;
025
026import org.apache.chemistry.opencmis.client.api.ChangeEvent;
027import org.apache.chemistry.opencmis.client.api.ChangeEvents;
028import org.apache.chemistry.opencmis.client.api.ObjectFactory;
029import org.apache.chemistry.opencmis.client.api.ObjectType;
030import org.apache.chemistry.opencmis.client.api.OperationContext;
031import org.apache.chemistry.opencmis.client.api.Policy;
032import org.apache.chemistry.opencmis.client.api.Property;
033import org.apache.chemistry.opencmis.client.api.QueryResult;
034import org.apache.chemistry.opencmis.client.api.Rendition;
035import org.apache.chemistry.opencmis.client.api.SecondaryType;
036import org.apache.chemistry.opencmis.client.api.Session;
037import org.apache.chemistry.opencmis.client.runtime.PropertyImpl;
038import org.apache.chemistry.opencmis.client.runtime.RenditionImpl;
039import org.apache.chemistry.opencmis.client.runtime.objecttype.DocumentTypeImpl;
040import org.apache.chemistry.opencmis.client.runtime.objecttype.FolderTypeImpl;
041import org.apache.chemistry.opencmis.client.runtime.objecttype.PolicyTypeImpl;
042import org.apache.chemistry.opencmis.client.runtime.objecttype.RelationshipTypeImpl;
043import org.apache.chemistry.opencmis.commons.PropertyIds;
044import org.apache.chemistry.opencmis.commons.data.Ace;
045import org.apache.chemistry.opencmis.commons.data.Acl;
046import org.apache.chemistry.opencmis.commons.data.ContentStream;
047import org.apache.chemistry.opencmis.commons.data.ObjectData;
048import org.apache.chemistry.opencmis.commons.data.ObjectList;
049import org.apache.chemistry.opencmis.commons.data.Properties;
050import org.apache.chemistry.opencmis.commons.data.PropertyData;
051import org.apache.chemistry.opencmis.commons.data.PropertyId;
052import org.apache.chemistry.opencmis.commons.data.RenditionData;
053import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
054import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
055import org.apache.chemistry.opencmis.commons.definitions.FolderTypeDefinition;
056import org.apache.chemistry.opencmis.commons.definitions.PolicyTypeDefinition;
057import org.apache.chemistry.opencmis.commons.definitions.PropertyBooleanDefinition;
058import org.apache.chemistry.opencmis.commons.definitions.PropertyDateTimeDefinition;
059import org.apache.chemistry.opencmis.commons.definitions.PropertyDecimalDefinition;
060import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
061import org.apache.chemistry.opencmis.commons.definitions.PropertyHtmlDefinition;
062import org.apache.chemistry.opencmis.commons.definitions.PropertyIdDefinition;
063import org.apache.chemistry.opencmis.commons.definitions.PropertyIntegerDefinition;
064import org.apache.chemistry.opencmis.commons.definitions.PropertyStringDefinition;
065import org.apache.chemistry.opencmis.commons.definitions.PropertyUriDefinition;
066import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
067import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
068import org.apache.chemistry.opencmis.commons.enums.Cardinality;
069import org.apache.chemistry.opencmis.commons.enums.Updatability;
070import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
071import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
072import org.apache.chemistry.opencmis.commons.impl.dataobjects.BindingsObjectFactoryImpl;
073import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
074import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
075import org.apache.chemistry.opencmis.commons.spi.BindingsObjectFactory;
076import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoObjectData;
077
078/**
079 * Factory for {@link NuxeoObject} and its related classes.
080 */
081public class NuxeoObjectFactory implements ObjectFactory {
082
083    private final NuxeoSession session;
084
085    private static final BindingsObjectFactory of = new BindingsObjectFactoryImpl();
086
087    public NuxeoObjectFactory(NuxeoSession session) {
088        this.session = session;
089    }
090
091    @Override
092    public void initialize(Session session, Map<String, String> parameters) {
093        // TODO
094        throw new UnsupportedOperationException();
095    }
096
097    @Override
098    public RepositoryInfo convertRepositoryInfo(RepositoryInfo repositoryInfo) {
099        return repositoryInfo;
100    }
101
102    @Override
103    public NuxeoObject convertObject(ObjectData data, OperationContext context) {
104        if (data == null || data.getProperties() == null || data.getProperties().getProperties() == null) {
105            return null;
106        }
107        ObjectType type;
108        PropertyData<?> propData = data.getProperties().getProperties().get(PropertyIds.OBJECT_TYPE_ID);
109        if (!(propData instanceof PropertyId)) {
110            throw new IllegalArgumentException("Property cmis:objectTypeId must be of type PropertyIdData, not: "
111                    + propData.getClass().getName());
112        }
113        type = session.getTypeDefinition((String) propData.getFirstValue());
114        return NuxeoObject.construct(session, (NuxeoObjectData) data, type);
115    }
116
117    @Override
118    public ObjectType getTypeFromObjectData(ObjectData objectData) {
119        // TODO Auto-generated method stub
120        throw new UnsupportedOperationException();
121    }
122
123    @Override
124    public Ace createAce(String principal, List<String> permissions) {
125        // TODO Auto-generated method stub
126        throw new UnsupportedOperationException();
127    }
128
129    @Override
130    public Acl createAcl(List<Ace> aces) {
131        // TODO Auto-generated method stub
132        throw new UnsupportedOperationException();
133    }
134
135    @Override
136    public <T> Property<T> createProperty(PropertyDefinition<T> type, List<T> values) {
137        return new PropertyImpl<T>(type, values);
138    }
139
140    @Override
141    public ContentStream createContentStream(String filename, long length, String mimetype, InputStream stream) {
142        return new ContentStreamImpl(filename, BigInteger.valueOf(length), mimetype, stream);
143    }
144
145    @Override
146    public ContentStream createContentStream(String filename, long length, String mimetype, InputStream stream,
147            boolean partial) {
148        // TODO partial
149        return createContentStream(filename, length, mimetype, stream);
150    }
151
152    @Override
153    public Acl convertAces(List<Ace> aces) {
154        return aces == null ? null : new AccessControlListImpl(aces);
155    }
156
157    @Override
158    public ContentStream convertContentStream(ContentStream contentStream) {
159        if (contentStream == null) {
160            return null;
161        }
162        long len = contentStream.getLength();
163        BigInteger length = len < 0 ? null : BigInteger.valueOf(len);
164        return of.createContentStream(contentStream.getFileName(), length, contentStream.getMimeType(),
165                contentStream.getStream());
166    }
167
168    @Override
169    public List<String> convertPolicies(List<Policy> policies) {
170        if (policies == null) {
171            return null;
172        }
173        List<String> policyIds = new ArrayList<String>(policies.size());
174        for (Policy p : policies) {
175            policyIds.add(p.getId());
176        }
177        return policyIds;
178    }
179
180    @Override
181    public Map<String, Property<?>> convertProperties(ObjectType objectType, Collection<SecondaryType> secondaryTypes,
182            Properties properties) {
183        throw new UnsupportedOperationException();
184    }
185
186    @Override
187    public Properties convertProperties(Map<String, ?> properties, ObjectType type,
188            Collection<SecondaryType> secondaryTypes, Set<Updatability> updatabilityFilter) {
189        if (properties == null) {
190            return null;
191        }
192        // TODO secondaryTypes
193        // TODO updatabilityFilter
194        PropertiesImpl props = new PropertiesImpl();
195        for (Entry<String, ?> es : properties.entrySet()) {
196            PropertyData<?> prop = convertProperty(es.getKey(), es.getValue(), type);
197            props.addProperty(prop);
198        }
199        return props;
200    }
201
202    @SuppressWarnings("unchecked")
203    protected static PropertyData<?> convertProperty(String key, Object value, ObjectType type) {
204        PropertyDefinition<?> pd = type.getPropertyDefinitions().get(key);
205        if (pd == null) {
206            throw new IllegalArgumentException("Unknown property '" + key + "' for type: " + type.getId());
207        }
208        boolean single = pd.getCardinality() == Cardinality.SINGLE;
209
210        List<?> values;
211        if (value == null) {
212            values = null;
213        } else if (value instanceof List<?>) {
214            if (single) {
215                throw new IllegalArgumentException("Property '" + key + "' is not a multi value property!");
216            }
217            values = (List<?>) value;
218        } else {
219            if (!single) {
220                throw new IllegalArgumentException("Property '" + key + "' is not a single value property!");
221            }
222            values = Collections.singletonList(value);
223        }
224        Object firstValue = values == null ? null : values.get(0);
225
226        if (pd instanceof PropertyStringDefinition) {
227            return of.createPropertyStringData(key, (List<String>) values);
228        } else if (pd instanceof PropertyIdDefinition) {
229            return of.createPropertyIdData(key, (List<String>) values);
230        } else if (pd instanceof PropertyHtmlDefinition) {
231            return of.createPropertyHtmlData(key, (List<String>) values);
232        } else if (pd instanceof PropertyUriDefinition) {
233            return of.createPropertyUriData(key, (List<String>) values);
234        } else if (pd instanceof PropertyIntegerDefinition) {
235            if (firstValue == null) {
236                return of.createPropertyIntegerData(key, (List<BigInteger>) null);
237            } else if (firstValue instanceof BigInteger) {
238                return of.createPropertyIntegerData(key, (List<BigInteger>) values);
239            } else if ((firstValue instanceof Byte) || (firstValue instanceof Short) || (firstValue instanceof Integer)
240                    || (firstValue instanceof Long)) {
241                List<BigInteger> list = new ArrayList<BigInteger>(values.size());
242                for (Object v : values) {
243                    list.add(BigInteger.valueOf(((Number) v).longValue()));
244                }
245                return of.createPropertyIntegerData(key, list);
246            } else {
247                throw new IllegalArgumentException("Property '" + key + "' is an Integer property");
248            }
249        } else if (pd instanceof PropertyBooleanDefinition) {
250            return of.createPropertyBooleanData(key, (List<Boolean>) values);
251        } else if (pd instanceof PropertyDecimalDefinition) {
252            return of.createPropertyDecimalData(key, (List<BigDecimal>) values);
253        } else if (pd instanceof PropertyDateTimeDefinition) {
254            return of.createPropertyDateTimeData(key, (List<GregorianCalendar>) values);
255        }
256        throw new CmisRuntimeException("Unknown class: " + pd.getClass().getName());
257    }
258
259    @Override
260    public List<PropertyData<?>> convertQueryProperties(Properties properties) {
261        if (properties == null || properties.getProperties() == null) {
262            return null;
263        }
264        return new ArrayList<PropertyData<?>>(properties.getPropertyList());
265    }
266
267    @Override
268    public QueryResult convertQueryResult(ObjectData objectData) {
269        throw new UnsupportedOperationException();
270    }
271
272    @Override
273    public Rendition convertRendition(String objectId, RenditionData rendition) {
274        if (rendition == null) {
275            return null;
276        }
277        BigInteger rl = rendition.getBigLength();
278        BigInteger rh = rendition.getBigHeight();
279        BigInteger rw = rendition.getBigWidth();
280        long length = rl == null ? -1 : rl.longValue();
281        int height = rh == null ? -1 : rh.intValue();
282        int width = rw == null ? -1 : rw.intValue();
283        return new RenditionImpl(session, objectId, rendition.getStreamId(), rendition.getRenditionDocumentId(),
284                rendition.getKind(), length, rendition.getMimeType(), rendition.getTitle(), height, width);
285    }
286
287    @Override
288    public ObjectType convertTypeDefinition(TypeDefinition typeDefinition) {
289        if (typeDefinition instanceof DocumentTypeDefinition) {
290            return new DocumentTypeImpl(session, (DocumentTypeDefinition) typeDefinition);
291        } else if (typeDefinition instanceof FolderTypeDefinition) {
292            return new FolderTypeImpl(session, (FolderTypeDefinition) typeDefinition);
293        } else if (typeDefinition instanceof RelationshipTypeDefinition) {
294            return new RelationshipTypeImpl(session, (RelationshipTypeDefinition) typeDefinition);
295        } else if (typeDefinition instanceof PolicyTypeDefinition) {
296            return new PolicyTypeImpl(session, (PolicyTypeDefinition) typeDefinition);
297        }
298        throw new CmisRuntimeException("Unknown base class: " + typeDefinition.getClass().getName());
299    }
300
301    @Override
302    public ChangeEvent convertChangeEvent(ObjectData objectData) {
303        // TODO Auto-generated method stub
304        throw new UnsupportedOperationException();
305    }
306
307    @Override
308    public ChangeEvents convertChangeEvents(String changeLogToken, ObjectList objectList) {
309        // TODO Auto-generated method stub
310        throw new UnsupportedOperationException();
311    }
312
313}