001/*
002 *  Copyright 2012 Anyware Services
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
017package org.ametys.core.util;
018
019import java.io.IOException;
020import java.io.OutputStream;
021import java.io.StringReader;
022import java.io.StringWriter;
023import java.util.ArrayList;
024import java.util.LinkedHashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.avalon.framework.activity.Initializable;
029import org.apache.avalon.framework.component.Component;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.avalon.framework.thread.ThreadSafe;
034import org.apache.commons.io.IOUtils;
035import org.apache.commons.lang.StringUtils;
036
037import com.fasterxml.jackson.core.JsonEncoding;
038import com.fasterxml.jackson.core.JsonFactory;
039import com.fasterxml.jackson.core.JsonGenerator;
040import com.fasterxml.jackson.core.JsonParser;
041import com.fasterxml.jackson.core.Version;
042import com.fasterxml.jackson.databind.ObjectMapper;
043import com.fasterxml.jackson.databind.module.SimpleModule;
044
045/**
046 * JSON helper
047 */
048public class JSONUtils implements Component, ThreadSafe, Serviceable, Initializable
049{
050    /** The avalon role */
051    public static final String ROLE = JSONUtils.class.getName();
052    
053    private JsonFactory _jsonFactory = new JsonFactory();
054    private ObjectMapper _objectMapper = new ObjectMapper();
055
056    private I18nizableTextSerializer _i18nizableTextSerializer;
057    
058    @Override
059    public void service(ServiceManager manager) throws ServiceException
060    {
061        _i18nizableTextSerializer = (I18nizableTextSerializer) manager.lookup(I18nizableTextSerializer.ROLE);
062    }
063    
064    @Override
065    public void initialize() throws Exception
066    {
067        // Register new serializer for I18nizableText
068        SimpleModule i18nModule = new SimpleModule("AmetysI18nModule", new Version(1, 0, 0, null, null, null));
069        i18nModule.addSerializer(_i18nizableTextSerializer);
070        _objectMapper.registerModule(i18nModule);
071    }
072    
073    /**
074     * Parse a JSON string to a {@link Map} object
075     * @param jsonString the string to parse
076     * @return object the infos as a Map.
077     */
078    public Map<String, Object> convertJsonToMap (String jsonString)
079    {
080        try 
081        {
082            if (StringUtils.isNotBlank(jsonString)) 
083            {
084                JsonParser jParser = _jsonFactory.createParser(new StringReader(jsonString));
085                Map<String, Object> map = _objectMapper.readValue(jParser, LinkedHashMap.class);
086                return map;
087            } 
088            else 
089            {
090                return new LinkedHashMap<>(); // We should not return a Collections.emptyMap() here, since we need to return a modifiable map that is always of the same type
091            }
092        } 
093        catch (Exception e) 
094        {
095            throw new IllegalArgumentException("The json string " + jsonString + " can not be parsed as a Map.", e);
096        }
097    }
098    
099    /**
100     * Parse a JSON string to a {@link List} object.
101     * @param jsonString the string to parse.
102     * @return the infos as a List.
103     */
104    public List<Object> convertJsonToList(String jsonString)
105    {
106        try 
107        {
108            if (StringUtils.isNotBlank(jsonString)) 
109            {
110                JsonParser jParser = _jsonFactory.createParser(new StringReader(jsonString));
111                List<Object> list = _objectMapper.readValue(jParser, ArrayList.class);
112                return list;
113            }
114            else
115            {
116                return new ArrayList<>();
117            }
118        } 
119        catch (Exception e) 
120        {
121            throw new IllegalArgumentException("The json string " + jsonString + " can not be parsed as a List.", e);
122        }
123    }
124    
125    /**
126     * Parse a JSON string to an Object array.
127     * @param jsonString the JSON string to parse.
128     * @return the converted Object array.
129     */
130    public Object[] convertJsonToArray(String jsonString)
131    {
132        try 
133        {
134            if (StringUtils.isNotBlank(jsonString)) 
135            {
136                JsonParser jParser = _jsonFactory.createParser(new StringReader(jsonString));
137                Object[] array = _objectMapper.readValue(jParser, Object[].class);
138                return array;
139            }
140            else
141            {
142                return new Object[0];
143            }
144        } 
145        catch (Exception e) 
146        {
147            throw new IllegalArgumentException("The json string " + jsonString + " can not be parsed as an array.", e);
148        }
149    }
150    
151    /**
152     * Parse a JSON string to a String array.
153     * @param jsonString the JSON string to parse.
154     * @return the converted String array.
155     */
156    public String[] convertJsonToStringArray(String jsonString)
157    {
158        try 
159        {
160            if (StringUtils.isNotBlank(jsonString)) 
161            {
162                JsonParser jParser = _jsonFactory.createParser(new StringReader(jsonString));
163                String[] array = _objectMapper.readValue(jParser, String[].class);
164                return array;
165            }
166            else
167            {
168                return new String[0];
169            }
170        } 
171        catch (Exception e) 
172        {
173            throw new IllegalArgumentException("The json string " + jsonString + " can not be parsed as a String array.", e);
174        }
175    }
176    
177    /**
178     * Convert an object to JSON string using specified output stream.
179     * The out stream is closed after processing.
180     * @param out The output stream
181     * @param parameters The object to convert
182     */
183    public void convertObjectToJson (OutputStream out, Object parameters)
184    {
185        try
186        {
187            JsonGenerator jsonGenerator = _jsonFactory.createGenerator(out, JsonEncoding.UTF8);
188            _objectMapper.writeValue(jsonGenerator, parameters);
189            
190            IOUtils.closeQuietly(out);
191        }
192        catch (IOException e)
193        {
194            throw new IllegalArgumentException("The object can not be converted to json string", e);
195        }
196    }
197    
198    /**
199     * Convert an object to a JSON string
200     * @param parameters The object to convert (List, Map ..)
201     * @return The JSON string
202     */
203    public String convertObjectToJson (Object parameters)
204    {
205        try
206        {
207            StringWriter writer = new StringWriter();
208            
209            JsonGenerator jsonGenerator = _jsonFactory.createGenerator(writer);
210            _objectMapper.writeValue(jsonGenerator, parameters);
211            
212            return writer.toString();
213        }
214        catch (IOException e)
215        {
216            throw new IllegalArgumentException("The object can not be converted to json string", e);
217        }
218    }
219}