001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.model.dataformat;
018
019import java.util.Arrays;
020import java.util.List;
021import java.util.Map;
022
023import javax.xml.bind.annotation.XmlAccessType;
024import javax.xml.bind.annotation.XmlAccessorType;
025import javax.xml.bind.annotation.XmlAttribute;
026import javax.xml.bind.annotation.XmlList;
027import javax.xml.bind.annotation.XmlRootElement;
028
029import org.apache.camel.CamelContext;
030import org.apache.camel.model.DataFormatDefinition;
031import org.apache.camel.spi.DataFormat;
032import org.apache.camel.spi.Metadata;
033
034/**
035 * XML JSon data format can convert from XML to JSON and vice-versa directly, without stepping through intermediate POJOs.
036 *
037 * @version 
038 */
039@Metadata(firstVersion = "2.10.0", label = "dataformat,transformation,xml,json", title = "XML JSon")
040@XmlRootElement(name = "xmljson")
041@XmlAccessorType(XmlAccessType.FIELD)
042@Deprecated
043public class XmlJsonDataFormat extends DataFormatDefinition {
044    
045    public static final String TYPE_HINTS = "typeHints";
046    public static final String REMOVE_NAMESPACE_PREFIXES = "removeNamespacePrefixes";
047    public static final String SKIP_NAMESPACES = "skipNamespaces";
048    public static final String TRIM_SPACES = "trimSpaces";
049    public static final String SKIP_WHITESPACE = "skipWhitespace";
050    public static final String EXPANDABLE_PROPERTIES = "expandableProperties";
051    public static final String ARRAY_NAME = "arrayName";
052    public static final String ELEMENT_NAME = "elementName";
053    public static final String ROOT_NAME = "rootName";
054    public static final String NAMESPACE_LENIENT = "namespaceLenient";
055    public static final String FORCE_TOP_LEVEL_OBJECT = "forceTopLevelObject";
056    public static final String ENCODING = "encoding";
057    
058    @XmlAttribute
059    private String encoding;
060    @XmlAttribute
061    private String elementName;
062    @XmlAttribute
063    private String arrayName;
064    @XmlAttribute
065    private Boolean forceTopLevelObject;
066    @XmlAttribute
067    private Boolean namespaceLenient;
068    @XmlAttribute
069    private String rootName;
070    @XmlAttribute
071    private Boolean skipWhitespace;
072    @XmlAttribute
073    private Boolean trimSpaces;
074    @XmlAttribute
075    private Boolean skipNamespaces;
076    @XmlAttribute
077    private Boolean removeNamespacePrefixes;
078    @XmlAttribute @XmlList @Metadata(label = "advanced")
079    private List<String> expandableProperties;
080    @XmlAttribute
081    private String typeHints;
082
083    public XmlJsonDataFormat() {
084        super("xmljson");
085    }
086
087    public XmlJsonDataFormat(Map<String, String> options) {
088        super("xmljson");
089        if (options.containsKey(ENCODING)) {
090            encoding = options.get(ENCODING);
091        }
092        if (options.containsKey(FORCE_TOP_LEVEL_OBJECT)) {
093            forceTopLevelObject = Boolean.parseBoolean(options.get(FORCE_TOP_LEVEL_OBJECT));
094        }
095        if (options.containsKey(NAMESPACE_LENIENT)) {
096            namespaceLenient = Boolean.parseBoolean(options.get(NAMESPACE_LENIENT));
097        }
098        if (options.containsKey(ROOT_NAME)) {
099            rootName = options.get(ROOT_NAME);
100        }
101        if (options.containsKey(ELEMENT_NAME)) {
102            elementName = options.get(ELEMENT_NAME);
103        }
104        if (options.containsKey(ARRAY_NAME)) {
105            arrayName = options.get(ARRAY_NAME);
106        }
107        if (options.containsKey(EXPANDABLE_PROPERTIES)) {
108            expandableProperties = Arrays.asList(options.get(EXPANDABLE_PROPERTIES).split(" "));
109        }
110        if (options.containsKey(SKIP_WHITESPACE)) {
111            skipWhitespace = Boolean.parseBoolean(options.get(SKIP_WHITESPACE));
112        }
113        if (options.containsKey(TRIM_SPACES)) {
114            trimSpaces = Boolean.parseBoolean(options.get(TRIM_SPACES));
115        }
116        if (options.containsKey(SKIP_NAMESPACES)) {
117            skipNamespaces = Boolean.parseBoolean(options.get(SKIP_NAMESPACES));
118        }
119        if (options.containsKey(REMOVE_NAMESPACE_PREFIXES)) {
120            removeNamespacePrefixes = Boolean.parseBoolean(options.get(REMOVE_NAMESPACE_PREFIXES));
121        }
122        if (options.containsKey(TYPE_HINTS)) {
123            typeHints = options.get(TYPE_HINTS);
124        }
125    }
126
127    @Override
128    protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) {
129        if (encoding != null) {
130            setProperty(camelContext, dataFormat, ENCODING, encoding);
131        }
132
133        if (forceTopLevelObject != null) {
134            setProperty(camelContext, dataFormat, FORCE_TOP_LEVEL_OBJECT, forceTopLevelObject);
135        }
136
137        if (namespaceLenient != null) {
138            setProperty(camelContext, dataFormat, NAMESPACE_LENIENT, namespaceLenient);
139        }
140
141        if (rootName != null) {
142            setProperty(camelContext, dataFormat, ROOT_NAME, rootName);
143        }
144        
145        if (elementName != null) {
146            setProperty(camelContext, dataFormat, ELEMENT_NAME, elementName);
147        }
148
149        if (arrayName != null) {
150            setProperty(camelContext, dataFormat, ARRAY_NAME, arrayName);
151        }
152
153        if (expandableProperties != null && expandableProperties.size() != 0) {
154            setProperty(camelContext, dataFormat, EXPANDABLE_PROPERTIES, expandableProperties);
155        }
156
157        if (skipWhitespace != null) {
158            setProperty(camelContext, dataFormat, SKIP_WHITESPACE, skipWhitespace);
159        }
160
161        if (trimSpaces != null) {
162            setProperty(camelContext, dataFormat, TRIM_SPACES, trimSpaces);
163        }
164
165        if (skipNamespaces != null) {
166            setProperty(camelContext, dataFormat, SKIP_NAMESPACES, skipNamespaces);
167        }
168
169        if (removeNamespacePrefixes != null) {
170            setProperty(camelContext, dataFormat, REMOVE_NAMESPACE_PREFIXES, removeNamespacePrefixes);
171        }
172
173        // will end up calling the setTypeHints(String s) which does the parsing from the Enum String key to the Enum value
174        if (typeHints != null) {
175            setProperty(camelContext, dataFormat, TYPE_HINTS, typeHints);
176        }
177
178        //TODO: xmljson: element-namespace mapping is not implemented in the XML DSL
179        // depending on adoption rate of this data format, we'll make this data format NamespaceAware so that it gets
180        // the prefix-namespaceURI mappings from the context, and with a new attribute called "namespacedElements",
181        // we'll associate named elements with prefixes following a format "element1:prefix1,element2:prefix2,..."
182    }
183
184    public String getEncoding() {
185        return encoding;
186    }
187
188    /**
189     * Sets the encoding.
190     * Used for unmarshalling (JSON to XML conversion).
191     */
192    public void setEncoding(String encoding) {
193        this.encoding = encoding;
194    }
195
196    public String getElementName() {
197        return elementName;
198    }
199
200    /**
201     * Specifies the name of the XML elements representing each array element.
202     * Used for unmarshalling (JSON to XML conversion).
203     */
204    public void setElementName(String elementName) {
205        this.elementName = elementName;
206    }
207
208    public String getArrayName() {
209        return arrayName;
210    }
211
212    /**
213     * Specifies the name of the top-level XML element.
214     * Used for unmarshalling (JSON to XML conversion).
215     *
216     * For example, when converting [1, 2, 3], it will be output by default as <a><e>1</e><e>2</e><e>3</e></a>.
217     * By setting this option or rootName, you can alter the name of element 'a'.
218     */
219    public void setArrayName(String arrayName) {
220        this.arrayName = arrayName;
221    }
222
223    public Boolean getForceTopLevelObject() {
224        return forceTopLevelObject;
225    }
226
227    /**
228     * Determines whether the resulting JSON will start off with a top-most element whose name matches the XML root element.
229     * Used for marshalling (XML to JSon conversion).
230     *
231     * If disabled, XML string <a><x>1</x><y>2</y></a> turns into { 'x: '1', 'y': '2' }.
232     * Otherwise, it turns into { 'a': { 'x: '1', 'y': '2' }}.
233     */
234    public void setForceTopLevelObject(Boolean forceTopLevelObject) {
235        this.forceTopLevelObject = forceTopLevelObject;
236    }
237
238    public Boolean getNamespaceLenient() {
239        return namespaceLenient;
240    }
241
242    /**
243     * Flag to be tolerant to incomplete namespace prefixes.
244     * Used for unmarshalling (JSON to XML conversion).
245     * In most cases, json-lib automatically changes this flag at runtime to match the processing.
246     */
247    public void setNamespaceLenient(Boolean namespaceLenient) {
248        this.namespaceLenient = namespaceLenient;
249    }
250
251    public String getRootName() {
252        return rootName;
253    }
254
255    /**
256     * Specifies the name of the top-level element.
257     * Used for unmarshalling (JSON to XML conversion).
258     *
259     * If not set, json-lib will use arrayName or objectName (default value: 'o', at the current time it is not configurable in this data format).
260     * If set to 'root', the JSON string { 'x': 'value1', 'y' : 'value2' } would turn
261     * into <root><x>value1</x><y>value2</y></root>, otherwise the 'root' element would be named 'o'.
262     */
263    public void setRootName(String rootName) {
264        this.rootName = rootName;
265    }
266
267    public Boolean getSkipWhitespace() {
268        return skipWhitespace;
269    }
270
271    /**
272     * Determines whether white spaces between XML elements will be regarded as text values or disregarded.
273     * Used for marshalling (XML to JSon conversion).
274     */
275    public void setSkipWhitespace(Boolean skipWhitespace) {
276        this.skipWhitespace = skipWhitespace;
277    }
278
279    public Boolean getTrimSpaces() {
280        return trimSpaces;
281    }
282
283    /**
284     * Determines whether leading and trailing white spaces will be omitted from String values.
285     * Used for marshalling (XML to JSon conversion).
286     */
287    public void setTrimSpaces(Boolean trimSpaces) {
288        this.trimSpaces = trimSpaces;
289    }
290
291    public Boolean getSkipNamespaces() {
292        return skipNamespaces;
293    }
294
295    /**
296     * Signals whether namespaces should be ignored. By default they will be added to the JSON output using @xmlns elements.
297     * Used for marshalling (XML to JSon conversion).
298     */
299    public void setSkipNamespaces(Boolean skipNamespaces) {
300        this.skipNamespaces = skipNamespaces;
301    }
302
303    public Boolean getRemoveNamespacePrefixes() {
304        return removeNamespacePrefixes;
305    }
306
307    /**
308     * Removes the namespace prefixes from XML qualified elements, so that the resulting JSON string does not contain them.
309     * Used for marshalling (XML to JSon conversion).
310     */
311    public void setRemoveNamespacePrefixes(Boolean removeNamespacePrefixes) {
312        this.removeNamespacePrefixes = removeNamespacePrefixes;
313    }
314
315    public List<String> getExpandableProperties() {
316        return expandableProperties;
317    }
318
319    /**
320     * With expandable properties, JSON array elements are converted to XML as a sequence of repetitive XML elements
321     * with the local name equal to the JSON key, for example: { number: 1,2,3 }, normally converted to:
322     * <number><e>1</e><e>2</e><e>3</e></number> (where e can be modified by setting elementName), would instead
323     * translate to <number>1</number><number>2</number><number>3</number>, if "number" is set as an expandable property
324     * Used for unmarshalling (JSON to XML conversion).
325     */
326    public void setExpandableProperties(List<String> expandableProperties) {
327        this.expandableProperties = expandableProperties;
328    }
329
330    public String getTypeHints() {
331        return typeHints;
332    }
333
334    /**
335     * Adds type hints to the resulting XML to aid conversion back to JSON.
336     * Used for unmarshalling (JSON to XML conversion).
337     */
338    public void setTypeHints(String typeHints) {
339        this.typeHints = typeHints;
340    }
341
342}