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.model.exceptions.WebResourceNotFoundException; 056import org.nuxeo.runtime.api.Framework; 057 058/** 059 * @since 5.7.3 060 */ 061@Provider 062@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON + "+nxentity" }) 063public class DirectoryEntryReader implements MessageBodyReader<DirectoryEntry> { 064 065 protected static final Log log = LogFactory.getLog(DirectoryEntryReader.class); 066 067 @Context 068 private JsonFactory factory; 069 070 @Override 071 public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) { 072 return DirectoryEntry.class.isAssignableFrom(type); 073 } 074 075 @Override 076 public DirectoryEntry readFrom(Class<DirectoryEntry> type, Type genericType, Annotation[] annotations, 077 MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) 078 throws IOException, WebApplicationException { 079 String content = IOUtils.toString(entityStream); 080 if (content.isEmpty()) { 081 if (content.isEmpty()) { 082 throw new WebException("No content in request body", Response.Status.BAD_REQUEST.getStatusCode()); 083 } 084 085 } 086 087 try { 088 return readRequest(content, httpHeaders); 089 } catch (IOException | NuxeoException e) { 090 throw WebException.wrap(e); 091 } 092 } 093 094 /** 095 * @param content 096 * @param httpHeaders 097 * @return 098 * @throws IOException 099 * @throws JsonParseException 100 */ 101 private DirectoryEntry readRequest(String content, MultivaluedMap<String, String> httpHeaders) throws IOException { 102 103 JsonParser jp = factory.createJsonParser(content); 104 return readJson(jp, httpHeaders); 105 } 106 107 public static DirectoryEntry readJson(JsonParser jp, MultivaluedMap<String, String> httpHeaders) 108 throws IOException { 109 110 JsonToken tok = jp.nextToken(); 111 112 // skip { 113 if (jp.getCurrentToken() == JsonToken.START_OBJECT) { 114 tok = jp.nextToken(); 115 } 116 String directoryName = null; 117 JsonNode propertiesNode = null; 118 while (tok != JsonToken.END_OBJECT) { 119 String key = jp.getCurrentName(); 120 jp.nextToken(); 121 if ("directoryName".equals(key)) { 122 directoryName = jp.readValueAs(String.class); 123 } else if ("properties".equals(key)) { 124 propertiesNode = jp.readValueAsTree(); 125 } else if ("entity-type".equals(key)) { 126 String entityType = jp.readValueAs(String.class); 127 if (!DirectoryEntryWriter.ENTITY_TYPE.equals(entityType)) { 128 throw new WebApplicationException(Response.Status.BAD_REQUEST); 129 } 130 } else { 131 log.debug("Unknown key: " + key); 132 jp.skipChildren(); 133 } 134 135 tok = jp.nextToken(); 136 137 } 138 139 DirectoryService ds = Framework.getLocalService(DirectoryService.class); 140 Directory directory = ds.getDirectory(directoryName); 141 142 if (directory == null) { 143 throw new WebResourceNotFoundException("Directory " + directoryName + " does not exists"); 144 } 145 146 return getDirectoryEntryFromNode(propertiesNode, directory); 147 148 } 149 150 private static DirectoryEntry getDirectoryEntryFromNode(JsonNode propertiesNode, Directory directory) 151 throws DirectoryException, IOException { 152 153 String schema = directory.getSchema(); 154 String id = propertiesNode.get(directory.getIdField()).getTextValue(); 155 156 try (Session session = directory.getSession()) { 157 DocumentModel entry = session.getEntry(id); 158 159 if (entry == null) { 160 entry = BaseSession.createEntryModel(null, schema, id, new HashMap<>()); 161 } 162 163 Properties props = new Properties(); 164 Iterator<Entry<String, JsonNode>> fields = propertiesNode.getFields(); 165 while (fields.hasNext()) { 166 Entry<String, JsonNode> fieldEntry = fields.next(); 167 props.put(schema + ":" + fieldEntry.getKey(), fieldEntry.getValue().getTextValue()); 168 } 169 170 DocumentHelper.setProperties(null, entry, props); 171 172 return new DirectoryEntry(directory.getName(), entry); 173 174 } 175 } 176 177}