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