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