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.webengine.jaxrs.coreiodelegate; 019 020import static javax.ws.rs.core.MediaType.APPLICATION_JSON; 021import static org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonReader.LEGACY_MODE_READER; 022import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON; 023import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.DERIVATIVE; 024 025import java.io.IOException; 026import java.io.InputStream; 027import java.lang.reflect.InvocationTargetException; 028import java.lang.reflect.Method; 029import java.lang.reflect.Type; 030 031import javax.servlet.http.HttpServletRequest; 032import javax.ws.rs.core.MediaType; 033import javax.ws.rs.core.MultivaluedMap; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.codehaus.jackson.JsonParser; 038import org.nuxeo.ecm.core.api.DocumentModel; 039import org.nuxeo.ecm.core.io.marshallers.json.JsonFactoryProvider; 040import org.nuxeo.ecm.core.io.registry.Reader; 041import org.nuxeo.ecm.core.io.registry.context.RenderingContext; 042import org.nuxeo.ecm.core.io.registry.reflect.Setup; 043import org.nuxeo.ecm.core.io.registry.reflect.Supports; 044import org.nuxeo.runtime.api.Framework; 045 046/** 047 * Delegates the {@link DocumentModel} Json reading to the old marshaller: JSONDocumentModelReader. 048 * <p> 049 * It's enable if system property nuxeo.document.json.legacy=true or if request header X-NXDocumentJsonLegacy=true. 050 * </p> 051 * 052 * @since 7.2 053 */ 054@Setup(mode = SINGLETON, priority = DERIVATIVE) 055@Supports(APPLICATION_JSON) 056public class DocumentModelJsonReaderLegacy implements Reader<DocumentModel> { 057 058 private static final Log log = LogFactory.getLog(DocumentModelJsonReaderLegacy.class); 059 060 public static final String CONF_DOCUMENT_JSON_LEGACY = "nuxeo.document.json.legacy"; 061 062 public static final String HEADER_DOCUMENT_JSON_LEGACY = "X-NXDocumentJsonLegacy"; 063 064 private static boolean IS_METHOD_LOADED = false; 065 066 private static Method METHOD = null; 067 068 private static void loadMethod() { 069 try { 070 Class<?> legacy = Class.forName("org.nuxeo.ecm.automation.jaxrs.io.documents.JSONDocumentModelReader"); 071 Method method = legacy.getMethod("readJson", JsonParser.class, MultivaluedMap.class, 072 HttpServletRequest.class); 073 METHOD = method; 074 } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) { 075 log.error( 076 "Unable to find method org.nuxeo.ecm.automation.jaxrs.io.documents.JSONDocumentModelReader.readJson(JsonParser, MultivaluedMap<String, String>, HttpServletRequest)", 077 e); 078 return; 079 } 080 } 081 082 private static Boolean CONF_KEY = null; 083 084 private static boolean getConfKey() { 085 if (CONF_KEY == null) { 086 CONF_KEY = Framework.isBooleanPropertyTrue(CONF_DOCUMENT_JSON_LEGACY); 087 } 088 return CONF_KEY; 089 } 090 091 public static void pushInstanceIfNeeded(RenderingContext ctx, HttpServletRequest request, 092 MultivaluedMap<String, String> httpHeaders) { 093 if (!IS_METHOD_LOADED) { 094 loadMethod(); 095 } 096 if (METHOD == null) { 097 return; 098 } 099 String header = request.getHeader(HEADER_DOCUMENT_JSON_LEGACY); 100 if (header != null) { 101 try { 102 boolean enable = Boolean.valueOf(header); 103 if (enable) { 104 DocumentModelJsonReaderLegacy instance = new DocumentModelJsonReaderLegacy(request, httpHeaders); 105 ctx.setParameterValues(LEGACY_MODE_READER, instance); 106 return; 107 } else { 108 return; 109 } 110 } catch (Exception e) { 111 log.warn("Invalid header value for X-NXDocumentJsonLegacy : true|false"); 112 } 113 } 114 if (getConfKey()) { 115 DocumentModelJsonReaderLegacy instance = new DocumentModelJsonReaderLegacy(request, httpHeaders); 116 ctx.setParameterValues(LEGACY_MODE_READER, instance); 117 return; 118 } else { 119 return; 120 } 121 } 122 123 private HttpServletRequest request; 124 125 private MultivaluedMap<String, String> httpHeaders; 126 127 private DocumentModelJsonReaderLegacy(HttpServletRequest request, MultivaluedMap<String, String> httpHeaders) { 128 super(); 129 this.request = request; 130 this.httpHeaders = httpHeaders; 131 } 132 133 @Override 134 public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) { 135 return true; 136 } 137 138 @Override 139 public DocumentModel read(Class<?> clazz, Type genericType, MediaType mediaType, InputStream in) throws IOException { 140 try { 141 JsonParser parser = JsonFactoryProvider.get().createJsonParser(in); 142 return DocumentModel.class.cast(METHOD.invoke(null, parser, httpHeaders, request)); 143 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 144 log.error("Unable to use legacy document model reading", e); 145 return null; 146 } 147 } 148 149}