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