001/* 002 * (C) Copyright 2015 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-2.1.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 * Nicolas Chapurlat <nchapurlat@nuxeo.com> 016 */ 017 018package org.nuxeo.ecm.core.io.marshallers.json.document; 019 020import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonWriter.ENTITY_TYPE; 021import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON; 022import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE; 023 024import java.io.IOException; 025import java.io.InputStream; 026import java.io.Serializable; 027import java.lang.reflect.ParameterizedType; 028import java.lang.reflect.Type; 029import java.util.List; 030 031import javax.ws.rs.core.MediaType; 032 033import org.apache.commons.lang.StringUtils; 034import org.apache.commons.lang3.reflect.TypeUtils; 035import org.codehaus.jackson.JsonNode; 036import org.nuxeo.ecm.core.api.Blob; 037import org.nuxeo.ecm.core.api.DocumentModel; 038import org.nuxeo.ecm.core.api.IdRef; 039import org.nuxeo.ecm.core.api.impl.DataModelImpl; 040import org.nuxeo.ecm.core.api.impl.SimpleDocumentModel; 041import org.nuxeo.ecm.core.api.model.Property; 042import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 043import org.nuxeo.ecm.core.api.model.impl.primitives.BlobProperty; 044import org.nuxeo.ecm.core.io.marshallers.json.EntityJsonReader; 045import org.nuxeo.ecm.core.io.registry.Reader; 046import org.nuxeo.ecm.core.io.registry.context.RenderingContext.SessionWrapper; 047import org.nuxeo.ecm.core.io.registry.reflect.Setup; 048 049/** 050 * Convert Json as {@link DocumentModel}. 051 * <p> 052 * Format is (any additional json property is ignored): 053 * 054 * <pre> 055 * { 056 * "entity-type": "document", 057 * "uid": "EXISTING_DOCUMENT_UID", <- use it to update an existing document 058 * "repository": "REPOSITORY_NAME" , <- explicitely specify the repository name 059 * "name": "DOCUMENT_NAME", <- use it to create an new document 060 * "type": "DOCUMENT_TYPE", <- use it to create an new document 061 * "properties": ... <-- see {@link DocumentPropertiesJsonReader} 062 * } 063 * </pre> 064 * 065 * </p> 066 * 067 * @since 7.2 068 */ 069@Setup(mode = SINGLETON, priority = REFERENCE) 070public class DocumentModelJsonReader extends EntityJsonReader<DocumentModel> { 071 072 public static final String LEGACY_MODE_READER = "DocumentModelLegacyModeReader"; 073 074 public DocumentModelJsonReader() { 075 super(ENTITY_TYPE); 076 } 077 078 @Override 079 public DocumentModel read(Class<?> clazz, Type genericType, MediaType mediaType, InputStream in) throws IOException { 080 Reader<DocumentModel> reader = ctx.getParameter(LEGACY_MODE_READER); 081 if (reader != null) { 082 DocumentModel doc = reader.read(clazz, genericType, mediaType, in); 083 return doc; 084 } else { 085 return super.read(clazz, genericType, mediaType, in); 086 } 087 } 088 089 @Override 090 protected DocumentModel readEntity(JsonNode jn) throws IOException { 091 092 SimpleDocumentModel simpleDoc = new SimpleDocumentModel(); 093 String name = getStringField(jn, "name"); 094 if (StringUtils.isNotBlank(name)) { 095 simpleDoc.setPathInfo(null, name); 096 } 097 String type = getStringField(jn, "type"); 098 if (StringUtils.isNotBlank(type)) { 099 simpleDoc.setType(type); 100 } 101 102 JsonNode propsNode = jn.get("properties"); 103 if (propsNode != null && !propsNode.isNull() && propsNode.isObject()) { 104 ParameterizedType genericType = TypeUtils.parameterize(List.class, Property.class); 105 List<Property> properties = readEntity(List.class, genericType, propsNode); 106 for (Property property : properties) { 107 String propertyName = property.getName(); 108 // handle schema with no prefix 109 if (!propertyName.contains(":")) { 110 propertyName = property.getField().getDeclaringType().getName() + ":" + propertyName; 111 } 112 simpleDoc.setPropertyValue(propertyName, property.getValue()); 113 } 114 } 115 116 DocumentModel doc = null; 117 118 String uid = getStringField(jn, "uid"); 119 if (StringUtils.isNotBlank(uid)) { 120 try (SessionWrapper wrapper = ctx.getSession(null)) { 121 doc = wrapper.getSession().getDocument(new IdRef(uid)); 122 } 123 applyPropertyValues(simpleDoc, doc); 124 } else { 125 doc = simpleDoc; 126 } 127 128 return doc; 129 } 130 131 public static void applyPropertyValues(DocumentModel src, DocumentModel dst) { 132 for (String schema : src.getSchemas()) { 133 DataModelImpl dataModel = (DataModelImpl) dst.getDataModel(schema); 134 DataModelImpl fromDataModel = (DataModelImpl) src.getDataModel(schema); 135 136 for (String field : fromDataModel.getDirtyFields()) { 137 Serializable data = (Serializable) fromDataModel.getData(field); 138 try { 139 if (!(dataModel.getDocumentPart().get(field) instanceof BlobProperty)) { 140 dataModel.setData(field, data); 141 } else { 142 dataModel.setData(field, decodeBlob(data)); 143 } 144 } catch (PropertyNotFoundException e) { 145 continue; 146 } 147 } 148 } 149 } 150 151 private static Serializable decodeBlob(Serializable data) { 152 if (data instanceof Blob) { 153 return data; 154 } else { 155 return null; 156 } 157 } 158 159}