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