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