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