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