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