001/* 002 * (C) Copyright 2013 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 * dmetzler 016 */ 017package org.nuxeo.ecm.restapi.jaxrs.io.directory; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.lang.annotation.Annotation; 022import java.lang.reflect.Type; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.Map.Entry; 026 027import javax.ws.rs.Consumes; 028import javax.ws.rs.WebApplicationException; 029import javax.ws.rs.core.Context; 030import javax.ws.rs.core.MediaType; 031import javax.ws.rs.core.MultivaluedMap; 032import javax.ws.rs.core.Response; 033import javax.ws.rs.ext.MessageBodyReader; 034import javax.ws.rs.ext.Provider; 035 036import org.apache.commons.io.IOUtils; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039import org.codehaus.jackson.JsonFactory; 040import org.codehaus.jackson.JsonNode; 041import org.codehaus.jackson.JsonParseException; 042import org.codehaus.jackson.JsonParser; 043import org.codehaus.jackson.JsonToken; 044import org.nuxeo.ecm.automation.core.util.DocumentHelper; 045import org.nuxeo.ecm.automation.core.util.Properties; 046import org.nuxeo.ecm.core.api.DocumentModel; 047import org.nuxeo.ecm.core.api.NuxeoException; 048import org.nuxeo.ecm.directory.BaseSession; 049import org.nuxeo.ecm.directory.Directory; 050import org.nuxeo.ecm.directory.DirectoryException; 051import org.nuxeo.ecm.directory.Session; 052import org.nuxeo.ecm.directory.api.DirectoryEntry; 053import org.nuxeo.ecm.directory.api.DirectoryService; 054import org.nuxeo.ecm.webengine.WebException; 055import org.nuxeo.ecm.webengine.jaxrs.coreiodelegate.JsonCoreIODelegate; 056import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException; 057import org.nuxeo.runtime.api.Framework; 058 059/** 060 * @since 5.7.3 061 * @deprecated since 7.10 The Nuxeo JSON marshalling was migrated to nuxeo-core-io. This class is replaced by 062 * org.nuxeo.ecm.directory.io.DirectoryEntryJsonReader which is registered by default and available to 063 * marshal {@link DirectoryEntry} from the Nuxeo Rest API thanks to the JAX-RS marshaller 064 * {@link JsonCoreIODelegate}. 065 */ 066@Deprecated 067@Provider 068@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON + "+nxentity" }) 069public class DirectoryEntryReader implements MessageBodyReader<DirectoryEntry> { 070 071 protected static final Log log = LogFactory.getLog(DirectoryEntryReader.class); 072 073 @Context 074 private JsonFactory factory; 075 076 @Override 077 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 078 return DirectoryEntry.class.isAssignableFrom(type); 079 } 080 081 @Override 082 public DirectoryEntry readFrom(Class<DirectoryEntry> type, Type genericType, Annotation[] annotations, 083 MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) 084 throws IOException, WebApplicationException { 085 String content = IOUtils.toString(entityStream); 086 if (content.isEmpty()) { 087 if (content.isEmpty()) { 088 throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode()); 089 } 090 091 } 092 093 try { 094 return readRequest(content, httpHeaders); 095 } catch (IOException | NuxeoException e) { 096 throw WebException.wrap(e); 097 } 098 } 099 100 /** 101 * @param content 102 * @param httpHeaders 103 * @return 104 * @throws IOException 105 * @throws JsonParseException 106 */ 107 private DirectoryEntry readRequest(String content, MultivaluedMap<String, String> httpHeaders) throws IOException { 108 109 JsonParser jp = factory.createJsonParser(content); 110 return readJson(jp, httpHeaders); 111 } 112 113 public static DirectoryEntry readJson(JsonParser jp, MultivaluedMap<String, String> httpHeaders) throws IOException { 114 115 JsonToken tok = jp.nextToken(); 116 117 // skip { 118 if (jp.getCurrentToken() == JsonToken.START_OBJECT) { 119 tok = jp.nextToken(); 120 } 121 String directoryName = null; 122 JsonNode propertiesNode = null; 123 while (tok != JsonToken.END_OBJECT) { 124 String key = jp.getCurrentName(); 125 jp.nextToken(); 126 if ("directoryName".equals(key)) { 127 directoryName = jp.readValueAs(String.class); 128 } else if ("properties".equals(key)) { 129 propertiesNode = jp.readValueAsTree(); 130 } else if ("entity-type".equals(key)) { 131 String entityType = jp.readValueAs(String.class); 132 if (!DirectoryEntryWriter.ENTITY_TYPE.equals(entityType)) { 133 throw new WebApplicationException(Response.Status.BAD_REQUEST); 134 } 135 } else { 136 log.debug("Unknown key: " + key); 137 jp.skipChildren(); 138 } 139 140 tok = jp.nextToken(); 141 142 } 143 144 DirectoryService ds = Framework.getLocalService(DirectoryService.class); 145 Directory directory = ds.getDirectory(directoryName); 146 147 if (directory == null) { 148 throw new WebResourceNotFoundException("Directory " + directoryName + " does not exists"); 149 } 150 151 return getDirectoryEntryFromNode(propertiesNode, directory); 152 153 } 154 155 private static DirectoryEntry getDirectoryEntryFromNode(JsonNode propertiesNode, Directory directory) 156 throws DirectoryException, IOException { 157 158 String schema = directory.getSchema(); 159 String id = propertiesNode.get(directory.getIdField()).getTextValue(); 160 161 try (Session session = directory.getSession()) { 162 DocumentModel entry = session.getEntry(id); 163 164 if (entry == null) { 165 entry = BaseSession.createEntryModel(null, schema, id, new HashMap<>()); 166 } 167 168 Properties props = new Properties(); 169 Iterator<Entry<String, JsonNode>> fields = propertiesNode.getFields(); 170 while (fields.hasNext()) { 171 Entry<String, JsonNode> fieldEntry = fields.next(); 172 props.put(schema + ":" + fieldEntry.getKey(), fieldEntry.getValue().getTextValue()); 173 } 174 175 DocumentHelper.setProperties(null, entry, props); 176 177 return new DirectoryEntry(directory.getName(), entry); 178 179 } 180 } 181 182}