001/*
002 * (C) Copyright 2014 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 *     Vladimir Pasquir <vpasquier@nuxeo.com>
017 */
018package org.nuxeo.ecm.webengine;
019
020import org.codehaus.jackson.JsonFactory;
021import org.codehaus.jackson.JsonGenerationException;
022import org.codehaus.jackson.JsonGenerator;
023import org.codehaus.jackson.Version;
024import org.codehaus.jackson.map.JsonSerializer;
025import org.codehaus.jackson.map.ObjectMapper;
026import org.codehaus.jackson.map.SerializationConfig;
027import org.codehaus.jackson.map.SerializerProvider;
028import org.codehaus.jackson.map.introspect.BasicBeanDescription;
029import org.codehaus.jackson.map.module.SimpleModule;
030import org.codehaus.jackson.map.ser.BeanSerializer;
031import org.codehaus.jackson.map.ser.BeanSerializerModifier;
032import org.nuxeo.runtime.api.Framework;
033
034import java.io.IOException;
035
036/**
037 * @since 6.0
038 */
039public class JsonFactoryManagerImpl implements JsonFactoryManager {
040
041    public static final String REST_STACK_DISPLAY = "org.nuxeo.rest.stack" + ".enable";
042
043    protected boolean stackDisplay;
044
045    public JsonFactoryManagerImpl() {
046        stackDisplay = Framework.isBooleanPropertyTrue(REST_STACK_DISPLAY);
047    }
048
049    private static class ThrowableSerializer extends BeanSerializer {
050
051        public ThrowableSerializer(BeanSerializer src) {
052            super(src);
053        }
054
055        @Override
056        protected void serializeFields(Object bean, JsonGenerator jgen, SerializerProvider provider)
057                throws IOException, JsonGenerationException {
058            serializeClassName(bean, jgen, provider);
059            super.serializeFields(bean, jgen, provider);
060        }
061
062        @Override
063        protected void serializeFieldsFiltered(Object bean, JsonGenerator jgen, SerializerProvider provider)
064                throws IOException, JsonGenerationException {
065            serializeClassName(bean, jgen, provider);
066            super.serializeFieldsFiltered(bean, jgen, provider);
067        }
068
069        protected void serializeClassName(Object bean, JsonGenerator jgen, SerializerProvider provider)
070                throws JsonGenerationException, IOException {
071            jgen.writeFieldName("className");
072            jgen.writeString(bean.getClass().getName());
073        }
074    }
075
076    private JsonFactory factory;
077
078    @Override
079    public JsonFactory getJsonFactory() {
080        if (factory == null) {
081            factory = createFactory();
082        }
083        return factory;
084    }
085
086    @Override
087    public JsonFactory createFactory() {
088        JsonFactory factory = new JsonFactory();
089        final ObjectMapper oc = new ObjectMapper(factory);
090        final SimpleModule module = new SimpleModule("webengine", Version.unknownVersion()) {
091
092            @Override
093            public void setupModule(SetupContext context) {
094                super.setupModule(context);
095
096                context.addBeanSerializerModifier(new BeanSerializerModifier() {
097
098                    @Override
099                    public JsonSerializer<?> modifySerializer(SerializationConfig config,
100                            BasicBeanDescription beanDesc, JsonSerializer<?> serializer) {
101                        if (!Throwable.class.isAssignableFrom(beanDesc.getBeanClass())) {
102                            return super.modifySerializer(config, beanDesc, serializer);
103                        }
104                        return new ThrowableSerializer((BeanSerializer) serializer);
105                    }
106                });
107            }
108        };
109        oc.registerModule(module);
110        factory.setCodec(oc);
111        return factory;
112    }
113
114    @Override
115    public boolean toggleStackDisplay() {
116        return stackDisplay = !stackDisplay;
117    }
118
119    public boolean isStackDisplay() {
120        return stackDisplay;
121    }
122}