001/* 002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * ataillefer 016 */ 017 018package org.nuxeo.ecm.core.io.impl; 019 020import java.io.IOException; 021import java.util.List; 022import java.util.Map; 023 024import org.dom4j.Element; 025import org.dom4j.QName; 026import org.nuxeo.common.collections.PrimitiveArrays; 027import org.nuxeo.common.utils.Path; 028import org.nuxeo.ecm.core.api.Blob; 029import org.nuxeo.ecm.core.api.DocumentModel; 030import org.nuxeo.ecm.core.schema.Namespace; 031import org.nuxeo.ecm.core.schema.TypeConstants; 032import org.nuxeo.ecm.core.schema.types.ComplexType; 033import org.nuxeo.ecm.core.schema.types.Field; 034import org.nuxeo.ecm.core.schema.types.ListType; 035import org.nuxeo.ecm.core.schema.types.Type; 036import org.nuxeo.ecm.core.schema.types.primitives.BinaryType; 037import org.nuxeo.ecm.core.schema.types.primitives.BooleanType; 038import org.nuxeo.ecm.core.schema.types.primitives.DateType; 039import org.nuxeo.ecm.core.schema.types.primitives.DoubleType; 040import org.nuxeo.ecm.core.schema.types.primitives.IntegerType; 041import org.nuxeo.ecm.core.schema.types.primitives.LongType; 042import org.nuxeo.ecm.core.schema.types.primitives.StringType; 043 044/** 045 * A representation for an exported document aware of property types. 046 * 047 * @author <a href="mailto:ataillefer@nuxeo.com">Antoine Taillefer</a> 048 * @since 5.6 049 */ 050public class TypedExportedDocumentImpl extends ExportedDocumentImpl { 051 052 private static final String TYPE_ATTRIBUTE = "type"; 053 054 private static final String COMPLEX_TYPE_ID = "complex"; 055 056 private static final String SCALAR_LIST_TYPE_ID = "scalarList"; 057 058 private static final String COMPLEX_LIST_TYPE_ID = "complexList"; 059 060 private static final String CONTENT_LIST_TYPE_ID = "contentList"; 061 062 public TypedExportedDocumentImpl() { 063 super(); 064 } 065 066 /** 067 * Instantiates a new typed exported document impl. 068 * 069 * @param doc the doc 070 * @param path the path to use for this document this is used to remove full paths 071 * @param inlineBlobs the inline blobs 072 * @throws IOException Signals that an I/O exception has occurred. 073 */ 074 public TypedExportedDocumentImpl(DocumentModel doc, Path path, boolean inlineBlobs) throws IOException { 075 super(doc, path, inlineBlobs); 076 } 077 078 /** 079 * Instantiates a new typed exported document impl. 080 * 081 * @param doc the doc 082 * @throws IOException Signals that an I/O exception has occurred. 083 */ 084 public TypedExportedDocumentImpl(DocumentModel doc) throws IOException { 085 super(doc, false); 086 } 087 088 /** 089 * Instantiates a new typed exported document impl. 090 * 091 * @param doc the doc 092 * @param inlineBlobs the inline blobs 093 * @throws IOException Signals that an I/O exception has occurred. 094 */ 095 public TypedExportedDocumentImpl(DocumentModel doc, boolean inlineBlobs) throws IOException { 096 super(doc, doc.getPath(), inlineBlobs); 097 } 098 099 /** 100 * Here we do what super does but add the "type" attribute to the XML elements. 101 */ 102 @Override 103 @SuppressWarnings("rawtypes") 104 protected void readProperty(Element parent, Namespace targetNs, Field field, Object value, boolean inlineBlobs) 105 throws IOException { 106 Type type = field.getType(); 107 QName name = QName.get(field.getName().getLocalName(), targetNs.prefix, targetNs.uri); 108 Element element = parent.addElement(name); 109 110 // extract the element content 111 if (type.isSimpleType()) { 112 element.addAttribute(TYPE_ATTRIBUTE, getSimpleTypeId(type)); 113 if (value != null) { 114 element.addText(type.encode(value)); 115 } 116 } else if (type.isComplexType()) { 117 ComplexType ctype = (ComplexType) type; 118 if (TypeConstants.isContentType(ctype)) { 119 element.addAttribute(TYPE_ATTRIBUTE, TypeConstants.CONTENT); 120 if (value != null) { 121 readBlob(element, ctype, (Blob) value, inlineBlobs); 122 } 123 } else { 124 element.addAttribute(TYPE_ATTRIBUTE, COMPLEX_TYPE_ID); 125 if (value != null) { 126 readComplex(element, ctype, (Map) value, inlineBlobs); 127 } 128 } 129 } else if (type.isListType()) { 130 String typeId; 131 ListType listType = ((ListType) type); 132 // Scalar list 133 if (listType.isScalarList()) { 134 typeId = SCALAR_LIST_TYPE_ID; 135 } 136 // Content list 137 else if (TypeConstants.isContentType(listType.getFieldType())) { 138 typeId = CONTENT_LIST_TYPE_ID; 139 } 140 // Complex list 141 else { 142 typeId = COMPLEX_LIST_TYPE_ID; 143 } 144 element.addAttribute(TYPE_ATTRIBUTE, typeId); 145 if (value != null) { 146 if (value instanceof List) { 147 readList(element, (ListType) type, (List) value, inlineBlobs); 148 } else if (value.getClass().getComponentType() != null) { 149 readList(element, (ListType) type, PrimitiveArrays.toList(value), inlineBlobs); 150 } else { 151 throw new IllegalArgumentException("A value of list type is neither list neither array: " + value); 152 } 153 } 154 } 155 } 156 157 /** 158 * Gets the simple type id. 159 * 160 * @param type the type 161 * @return the simple type id 162 */ 163 protected String getSimpleTypeId(Type type) { 164 165 String typeId = StringType.ID; 166 167 if (BooleanType.INSTANCE == type) { 168 typeId = BooleanType.ID; 169 } else if (DateType.INSTANCE == type) { 170 typeId = DateType.ID; 171 } else if (LongType.INSTANCE == type) { 172 typeId = LongType.ID; 173 } else if (IntegerType.INSTANCE == type) { 174 typeId = IntegerType.ID; 175 } else if (DoubleType.INSTANCE == type) { 176 typeId = DoubleType.ID; 177 } else if (BinaryType.INSTANCE == type) { 178 typeId = BinaryType.ID; 179 } 180 return typeId; 181 182 } 183 184}