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.ArrayList; 020import java.util.Arrays; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Map.Entry; 025import javax.xml.bind.annotation.XmlAccessType; 026import javax.xml.bind.annotation.XmlAccessorType; 027import javax.xml.bind.annotation.XmlAttribute; 028import javax.xml.bind.annotation.XmlElement; 029import javax.xml.bind.annotation.XmlRootElement; 030import javax.xml.bind.annotation.XmlTransient; 031import javax.xml.bind.annotation.XmlType; 032import javax.xml.bind.annotation.adapters.XmlAdapter; 033import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 034 035import org.apache.camel.CamelContext; 036import org.apache.camel.model.DataFormatDefinition; 037import org.apache.camel.spi.DataFormat; 038import org.apache.camel.spi.Metadata; 039import org.apache.camel.spi.RouteContext; 040import org.apache.camel.util.CamelContextHelper; 041import org.apache.camel.util.ObjectHelper; 042 043/** 044 * xstream data format 045 * 046 * @version 047 */ 048@Metadata(label = "dataformat,transformation", title = "XStream") 049@XmlRootElement(name = "xstream") 050@XmlAccessorType(XmlAccessType.NONE) 051public class XStreamDataFormat extends DataFormatDefinition { 052 @XmlAttribute 053 private String encoding; 054 @XmlAttribute 055 private String driver; 056 @XmlAttribute 057 private String driverRef; 058 @XmlAttribute 059 private String mode; 060 061 @XmlJavaTypeAdapter(ConvertersAdapter.class) 062 @XmlElement(name = "converters") 063 private List<String> converters; 064 @XmlJavaTypeAdapter(AliasAdapter.class) 065 @XmlElement(name = "aliases") 066 private Map<String, String> aliases; 067 @XmlJavaTypeAdapter(OmitFieldsAdapter.class) 068 @XmlElement(name = "omitFields") 069 private Map<String, String[]> omitFields; 070 @XmlJavaTypeAdapter(ImplicitCollectionsAdapter.class) 071 @XmlElement(name = "implicitCollections") 072 private Map<String, String[]> implicitCollections; 073 074 public XStreamDataFormat() { 075 super("xstream"); 076 } 077 078 public XStreamDataFormat(String encoding) { 079 this(); 080 setEncoding(encoding); 081 } 082 083 public String getEncoding() { 084 return encoding; 085 } 086 087 /** 088 * Sets the encoding to use 089 */ 090 public void setEncoding(String encoding) { 091 this.encoding = encoding; 092 } 093 094 public String getDriver() { 095 return driver; 096 } 097 098 /** 099 * To use a custom XStream driver. 100 * The instance must be of type com.thoughtworks.xstream.io.HierarchicalStreamDriver 101 */ 102 public void setDriver(String driver) { 103 this.driver = driver; 104 } 105 106 public String getDriverRef() { 107 return driverRef; 108 } 109 110 /** 111 * To refer to a custom XStream driver to lookup in the registry. 112 * The instance must be of type com.thoughtworks.xstream.io.HierarchicalStreamDriver 113 */ 114 public void setDriverRef(String driverRef) { 115 this.driverRef = driverRef; 116 } 117 118 public String getMode() { 119 return mode; 120 } 121 122 /** 123 * Mode for dealing with duplicate references The possible values are: 124 * <ul> 125 * <li>NO_REFERENCES</li> 126 * <li>ID_REFERENCES</li> 127 * <li>XPATH_RELATIVE_REFERENCES</li> 128 * <li>XPATH_ABSOLUTE_REFERENCES</li> 129 * <li>SINGLE_NODE_XPATH_RELATIVE_REFERENCES</li> 130 * <li>SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES</li> 131 * </ul> 132 */ 133 public void setMode(String mode) { 134 this.mode = mode; 135 } 136 137 public List<String> getConverters() { 138 return converters; 139 } 140 141 /** 142 * List of class names for using custom XStream converters. 143 * The classes must be of type com.thoughtworks.xstream.converters.Converter 144 */ 145 public void setConverters(List<String> converters) { 146 this.converters = converters; 147 } 148 149 public Map<String, String> getAliases() { 150 return aliases; 151 } 152 153 /** 154 * Alias a Class to a shorter name to be used in XML elements. 155 */ 156 public void setAliases(Map<String, String> aliases) { 157 this.aliases = aliases; 158 } 159 160 public Map<String, String[]> getOmitFields() { 161 return omitFields; 162 } 163 164 /** 165 * Prevents a field from being serialized. To omit a field you must always provide the 166 * declaring type and not necessarily the type that is converted. 167 */ 168 public void setOmitFields(Map<String, String[]> omitFields) { 169 this.omitFields = omitFields; 170 } 171 172 public Map<String, String[]> getImplicitCollections() { 173 return implicitCollections; 174 } 175 176 /** 177 * Adds a default implicit collection which is used for any unmapped XML tag. 178 */ 179 public void setImplicitCollections(Map<String, String[]> implicitCollections) { 180 this.implicitCollections = implicitCollections; 181 } 182 183 @Override 184 protected DataFormat createDataFormat(RouteContext routeContext) { 185 if ("json".equals(this.driver)) { 186 setProperty(routeContext.getCamelContext(), this, "dataFormatName", "json-xstream"); 187 } 188 DataFormat answer = super.createDataFormat(routeContext); 189 // need to lookup the reference for the xstreamDriver 190 if (ObjectHelper.isNotEmpty(driverRef)) { 191 setProperty(routeContext.getCamelContext(), answer, "xstreamDriver", CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), driverRef)); 192 } 193 return answer; 194 } 195 196 @Override 197 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 198 if (encoding != null) { 199 setProperty(camelContext, dataFormat, "encoding", encoding); 200 } 201 if (this.converters != null) { 202 setProperty(camelContext, dataFormat, "converters", this.converters); 203 } 204 if (this.aliases != null) { 205 setProperty(camelContext, dataFormat, "aliases", this.aliases); 206 } 207 if (this.omitFields != null) { 208 setProperty(camelContext, dataFormat, "omitFields", this.omitFields); 209 } 210 if (this.implicitCollections != null) { 211 setProperty(camelContext, dataFormat, "implicitCollections", this.implicitCollections); 212 } 213 if (this.mode != null) { 214 setProperty(camelContext, dataFormat, "mode", mode); 215 } 216 } 217 218 219 220 @XmlTransient 221 public static class ConvertersAdapter extends XmlAdapter<ConverterList, List<String>> { 222 @Override 223 public ConverterList marshal(List<String> v) throws Exception { 224 if (v == null) { 225 return null; 226 } 227 228 List<ConverterEntry> list = new ArrayList<ConverterEntry>(); 229 for (String str : v) { 230 ConverterEntry entry = new ConverterEntry(); 231 entry.setClsName(str); 232 list.add(entry); 233 } 234 ConverterList converterList = new ConverterList(); 235 converterList.setList(list); 236 return converterList; 237 } 238 239 @Override 240 public List<String> unmarshal(ConverterList v) throws Exception { 241 if (v == null) { 242 return null; 243 } 244 245 List<String> list = new ArrayList<String>(); 246 for (ConverterEntry entry : v.getList()) { 247 list.add(entry.getClsName()); 248 } 249 return list; 250 } 251 } 252 253 @XmlAccessorType(XmlAccessType.NONE) 254 @XmlType(name = "converterList", namespace = "http://camel.apache.org/schema/spring") 255 public static class ConverterList { 256 @XmlElement(name = "converter", namespace = "http://camel.apache.org/schema/spring") 257 private List<ConverterEntry> list; 258 259 public List<ConverterEntry> getList() { 260 return list; 261 } 262 263 public void setList(List<ConverterEntry> list) { 264 this.list = list; 265 } 266 } 267 268 @XmlAccessorType(XmlAccessType.NONE) 269 @XmlType(name = "converterEntry", namespace = "http://camel.apache.org/schema/spring") 270 public static class ConverterEntry { 271 @XmlAttribute(name = "class") 272 private String clsName; 273 274 public String getClsName() { 275 return clsName; 276 } 277 278 public void setClsName(String clsName) { 279 this.clsName = clsName; 280 } 281 } 282 283 @XmlTransient 284 public static class ImplicitCollectionsAdapter 285 extends XmlAdapter<ImplicitCollectionList, Map<String, String[]>> { 286 287 @Override 288 public ImplicitCollectionList marshal(Map<String, String[]> v) throws Exception { 289 if (v == null || v.isEmpty()) { 290 return null; 291 } 292 293 List<ImplicitCollectionEntry> list = new ArrayList<ImplicitCollectionEntry>(); 294 for (Entry<String, String[]> e : v.entrySet()) { 295 ImplicitCollectionEntry entry = new ImplicitCollectionEntry(e.getKey(), e.getValue()); 296 list.add(entry); 297 } 298 299 ImplicitCollectionList collectionList = new ImplicitCollectionList(); 300 collectionList.setList(list); 301 302 return collectionList; 303 } 304 305 @Override 306 public Map<String, String[]> unmarshal(ImplicitCollectionList v) throws Exception { 307 if (v == null) { 308 return null; 309 } 310 311 Map<String, String[]> map = new HashMap<String, String[]>(); 312 for (ImplicitCollectionEntry entry : v.getList()) { 313 map.put(entry.getClsName(), entry.getFields()); 314 } 315 return map; 316 } 317 } 318 319 @XmlAccessorType(XmlAccessType.NONE) 320 @XmlType(name = "implicitCollectionList", namespace = "http://camel.apache.org/schema/spring") 321 public static class ImplicitCollectionList { 322 @XmlElement(name = "class", namespace = "http://camel.apache.org/schema/spring") 323 private List<ImplicitCollectionEntry> list; 324 325 public List<ImplicitCollectionEntry> getList() { 326 return list; 327 } 328 329 public void setList(List<ImplicitCollectionEntry> list) { 330 this.list = list; 331 } 332 } 333 334 @XmlAccessorType(XmlAccessType.NONE) 335 @XmlType(name = "implicitCollectionEntry", namespace = "http://camel.apache.org/schema/spring") 336 public static class ImplicitCollectionEntry { 337 @XmlAttribute(name = "name") 338 private String clsName; 339 340 @XmlElement(name = "field", namespace = "http://camel.apache.org/schema/spring") 341 private String[] fields; 342 343 public ImplicitCollectionEntry() { 344 } 345 346 public ImplicitCollectionEntry(String clsName, String[] fields) { 347 this.clsName = clsName; 348 this.fields = fields; 349 } 350 351 public String getClsName() { 352 return clsName; 353 } 354 355 public void setClsName(String clsName) { 356 this.clsName = clsName; 357 } 358 359 public String[] getFields() { 360 return fields; 361 } 362 363 public void setFields(String[] fields) { 364 this.fields = fields; 365 } 366 367 @Override 368 public String toString() { 369 return "Alias[ImplicitCollection=" + clsName + ", fields=" + Arrays.asList(this.fields) + "]"; 370 } 371 } 372 373 @XmlTransient 374 public static class AliasAdapter extends XmlAdapter<AliasList, Map<String, String>> { 375 376 @Override 377 public AliasList marshal(Map<String, String> value) throws Exception { 378 if (value == null || value.isEmpty()) { 379 return null; 380 } 381 382 List<AliasEntry> ret = new ArrayList<AliasEntry>(value.size()); 383 for (Map.Entry<String, String> entry : value.entrySet()) { 384 ret.add(new AliasEntry(entry.getKey(), entry.getValue())); 385 } 386 AliasList jaxbMap = new AliasList(); 387 jaxbMap.setList(ret); 388 return jaxbMap; 389 } 390 391 @Override 392 public Map<String, String> unmarshal(AliasList value) throws Exception { 393 if (value == null || value.getList() == null || value.getList().isEmpty()) { 394 return null; 395 } 396 397 Map<String, String> answer = new HashMap<String, String>(); 398 for (AliasEntry alias : value.getList()) { 399 answer.put(alias.getName(), alias.getClsName()); 400 } 401 return answer; 402 } 403 } 404 405 @XmlAccessorType(XmlAccessType.NONE) 406 @XmlType(name = "aliasList", namespace = "http://camel.apache.org/schema/spring") 407 public static class AliasList { 408 @XmlElement(name = "alias", namespace = "http://camel.apache.org/schema/spring") 409 private List<AliasEntry> list; 410 411 public List<AliasEntry> getList() { 412 return list; 413 } 414 415 public void setList(List<AliasEntry> list) { 416 this.list = list; 417 } 418 } 419 420 @XmlAccessorType(XmlAccessType.NONE) 421 @XmlType(name = "aliasEntry", namespace = "http://camel.apache.org/schema/spring") 422 public static class AliasEntry { 423 424 @XmlAttribute 425 private String name; 426 427 @XmlAttribute(name = "class") 428 private String clsName; 429 430 public AliasEntry() { 431 } 432 433 public AliasEntry(String key, String clsName) { 434 this.name = key; 435 this.clsName = clsName; 436 } 437 438 public String getName() { 439 return name; 440 } 441 442 public void setName(String name) { 443 this.name = name; 444 } 445 446 public String getClsName() { 447 return clsName; 448 } 449 450 public void setClsName(String clsName) { 451 this.clsName = clsName; 452 } 453 454 @Override 455 public String toString() { 456 return "Alias[name=" + name + ", class=" + clsName + "]"; 457 } 458 } 459 460 @XmlTransient 461 public static class OmitFieldsAdapter 462 extends XmlAdapter<OmitFieldList, Map<String, String[]>> { 463 464 @Override 465 public OmitFieldList marshal(Map<String, String[]> v) throws Exception { 466 if (v == null || v.isEmpty()) { 467 return null; 468 } 469 470 List<OmitFieldEntry> list = new ArrayList<OmitFieldEntry>(); 471 for (Entry<String, String[]> e : v.entrySet()) { 472 OmitFieldEntry entry = new OmitFieldEntry(e.getKey(), e.getValue()); 473 list.add(entry); 474 } 475 476 OmitFieldList collectionList = new OmitFieldList(); 477 collectionList.setList(list); 478 479 return collectionList; 480 } 481 482 @Override 483 public Map<String, String[]> unmarshal(OmitFieldList v) throws Exception { 484 if (v == null || v.getList() == null || v.getList().isEmpty()) { 485 return null; 486 } 487 488 Map<String, String[]> map = new HashMap<String, String[]>(); 489 for (OmitFieldEntry entry : v.getList()) { 490 map.put(entry.getClsName(), entry.getFields()); 491 } 492 return map; 493 } 494 } 495 496 @XmlAccessorType(XmlAccessType.NONE) 497 @XmlType(name = "omitFieldList", namespace = "http://camel.apache.org/schema/spring") 498 public static class OmitFieldList { 499 @XmlElement(name = "omitField", namespace = "http://camel.apache.org/schema/spring") 500 private List<OmitFieldEntry> list; 501 502 public List<OmitFieldEntry> getList() { 503 return list; 504 } 505 506 public void setList(List<OmitFieldEntry> list) { 507 this.list = list; 508 } 509 } 510 511 @XmlAccessorType(XmlAccessType.NONE) 512 @XmlType(name = "omitFieldEntry", namespace = "http://camel.apache.org/schema/spring") 513 public static class OmitFieldEntry { 514 515 @XmlAttribute(name = "class") 516 private String clsName; 517 518 @XmlElement(name = "field", namespace = "http://camel.apache.org/schema/spring") 519 private String[] fields; 520 521 public OmitFieldEntry() { 522 } 523 524 public OmitFieldEntry(String clsName, String[] fields) { 525 this.clsName = clsName; 526 this.fields = fields; 527 } 528 529 public String getClsName() { 530 return clsName; 531 } 532 533 public void setClsName(String clsName) { 534 this.clsName = clsName; 535 } 536 537 public String[] getFields() { 538 return fields; 539 } 540 541 public void setFields(String[] fields) { 542 this.fields = fields; 543 } 544 545 @Override 546 public String toString() { 547 return "OmitField[" + clsName + ", fields=" + Arrays.asList(this.fields) + "]"; 548 } 549 } 550 551}