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.reifier.dataformat; 018 019import java.util.HashMap; 020import java.util.LinkedHashMap; 021import java.util.Map; 022import java.util.function.BiFunction; 023 024import org.apache.camel.CamelContext; 025import org.apache.camel.ExtendedCamelContext; 026import org.apache.camel.model.DataFormatDefinition; 027import org.apache.camel.model.Model; 028import org.apache.camel.model.dataformat.ASN1DataFormat; 029import org.apache.camel.model.dataformat.Any23DataFormat; 030import org.apache.camel.model.dataformat.AvroDataFormat; 031import org.apache.camel.model.dataformat.BarcodeDataFormat; 032import org.apache.camel.model.dataformat.Base64DataFormat; 033import org.apache.camel.model.dataformat.BeanioDataFormat; 034import org.apache.camel.model.dataformat.BindyDataFormat; 035import org.apache.camel.model.dataformat.CBORDataFormat; 036import org.apache.camel.model.dataformat.CryptoDataFormat; 037import org.apache.camel.model.dataformat.CsvDataFormat; 038import org.apache.camel.model.dataformat.CustomDataFormat; 039import org.apache.camel.model.dataformat.FhirDataformat; 040import org.apache.camel.model.dataformat.FhirJsonDataFormat; 041import org.apache.camel.model.dataformat.FhirXmlDataFormat; 042import org.apache.camel.model.dataformat.FlatpackDataFormat; 043import org.apache.camel.model.dataformat.GrokDataFormat; 044import org.apache.camel.model.dataformat.GzipDataFormat; 045import org.apache.camel.model.dataformat.HL7DataFormat; 046import org.apache.camel.model.dataformat.IcalDataFormat; 047import org.apache.camel.model.dataformat.JacksonXMLDataFormat; 048import org.apache.camel.model.dataformat.JaxbDataFormat; 049import org.apache.camel.model.dataformat.JsonApiDataFormat; 050import org.apache.camel.model.dataformat.JsonDataFormat; 051import org.apache.camel.model.dataformat.LZFDataFormat; 052import org.apache.camel.model.dataformat.MimeMultipartDataFormat; 053import org.apache.camel.model.dataformat.PGPDataFormat; 054import org.apache.camel.model.dataformat.ProtobufDataFormat; 055import org.apache.camel.model.dataformat.RssDataFormat; 056import org.apache.camel.model.dataformat.SoapJaxbDataFormat; 057import org.apache.camel.model.dataformat.SyslogDataFormat; 058import org.apache.camel.model.dataformat.TarFileDataFormat; 059import org.apache.camel.model.dataformat.ThriftDataFormat; 060import org.apache.camel.model.dataformat.TidyMarkupDataFormat; 061import org.apache.camel.model.dataformat.UniVocityCsvDataFormat; 062import org.apache.camel.model.dataformat.UniVocityFixedWidthDataFormat; 063import org.apache.camel.model.dataformat.UniVocityTsvDataFormat; 064import org.apache.camel.model.dataformat.XMLSecurityDataFormat; 065import org.apache.camel.model.dataformat.XStreamDataFormat; 066import org.apache.camel.model.dataformat.XmlRpcDataFormat; 067import org.apache.camel.model.dataformat.YAMLDataFormat; 068import org.apache.camel.model.dataformat.ZipDeflaterDataFormat; 069import org.apache.camel.model.dataformat.ZipFileDataFormat; 070import org.apache.camel.reifier.AbstractReifier; 071import org.apache.camel.spi.DataFormat; 072import org.apache.camel.spi.DataFormatContentTypeHeader; 073import org.apache.camel.spi.PropertyConfigurer; 074import org.apache.camel.spi.PropertyConfigurerAware; 075import org.apache.camel.spi.ReifierStrategy; 076import org.apache.camel.support.CamelContextHelper; 077import org.apache.camel.support.PropertyBindingSupport; 078import org.apache.camel.util.ObjectHelper; 079import org.slf4j.Logger; 080import org.slf4j.LoggerFactory; 081 082public abstract class DataFormatReifier<T extends DataFormatDefinition> extends AbstractReifier { 083 084 private static final Logger LOG = LoggerFactory.getLogger(DataFormatReifier.class); 085 086 private static final Map<Class<? extends DataFormatDefinition>, BiFunction<CamelContext, DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>>> DATAFORMATS; 087 static { 088 Map<Class<? extends DataFormatDefinition>, BiFunction<CamelContext, DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>>> map = new HashMap<>(); 089 map.put(Any23DataFormat.class, Any23DataFormatReifier::new); 090 map.put(ASN1DataFormat.class, ASN1DataFormatReifier::new); 091 map.put(AvroDataFormat.class, AvroDataFormatReifier::new); 092 map.put(BarcodeDataFormat.class, BarcodeDataFormatReifier::new); 093 map.put(Base64DataFormat.class, Base64DataFormatReifier::new); 094 map.put(BeanioDataFormat.class, BeanioDataFormatReifier::new); 095 map.put(BindyDataFormat.class, BindyDataFormatReifier::new); 096 map.put(CBORDataFormat.class, CBORDataFormatReifier::new); 097 map.put(CryptoDataFormat.class, CryptoDataFormatReifier::new); 098 map.put(CsvDataFormat.class, CsvDataFormatReifier::new); 099 map.put(CustomDataFormat.class, CustomDataFormatReifier::new); 100 map.put(FhirDataformat.class, FhirDataFormatReifier::new); 101 map.put(FhirJsonDataFormat.class, FhirJsonDataFormatReifier::new); 102 map.put(FhirXmlDataFormat.class, FhirXmlDataFormatReifier::new); 103 map.put(FlatpackDataFormat.class, FlatpackDataFormatReifier::new); 104 map.put(GrokDataFormat.class, GrokDataFormatReifier::new); 105 map.put(GzipDataFormat.class, GzipDataFormatReifier::new); 106 map.put(HL7DataFormat.class, HL7DataFormatReifier::new); 107 map.put(IcalDataFormat.class, IcalDataFormatReifier::new); 108 map.put(JacksonXMLDataFormat.class, JacksonXMLDataFormatReifier::new); 109 map.put(JaxbDataFormat.class, JaxbDataFormatReifier::new); 110 map.put(JsonApiDataFormat.class, JsonApiDataFormatReifier::new); 111 map.put(JsonDataFormat.class, JsonDataFormatReifier::new); 112 map.put(LZFDataFormat.class, LZFDataFormatReifier::new); 113 map.put(MimeMultipartDataFormat.class, MimeMultipartDataFormatReifier::new); 114 map.put(PGPDataFormat.class, PGPDataFormatReifier::new); 115 map.put(ProtobufDataFormat.class, ProtobufDataFormatReifier::new); 116 map.put(RssDataFormat.class, RssDataFormatReifier::new); 117 map.put(SoapJaxbDataFormat.class, SoapJaxbDataFormatReifier::new); 118 map.put(SyslogDataFormat.class, SyslogDataFormatReifier::new); 119 map.put(TarFileDataFormat.class, TarFileDataFormatReifier::new); 120 map.put(ThriftDataFormat.class, ThriftDataFormatReifier::new); 121 map.put(TidyMarkupDataFormat.class, TidyMarkupDataFormatReifier::new); 122 map.put(UniVocityCsvDataFormat.class, UniVocityCsvDataFormatReifier::new); 123 map.put(UniVocityFixedWidthDataFormat.class, UniVocityFixedWidthDataFormatReifier::new); 124 map.put(UniVocityTsvDataFormat.class, UniVocityTsvDataFormatReifier::new); 125 map.put(XmlRpcDataFormat.class, XmlRpcDataFormatReifier::new); 126 map.put(XMLSecurityDataFormat.class, XMLSecurityDataFormatReifier::new); 127 map.put(XStreamDataFormat.class, XStreamDataFormatReifier::new); 128 map.put(YAMLDataFormat.class, YAMLDataFormatReifier::new); 129 map.put(ZipDeflaterDataFormat.class, ZipDataFormatReifier::new); 130 map.put(ZipFileDataFormat.class, ZipFileDataFormatReifier::new); 131 DATAFORMATS = map; 132 ReifierStrategy.addReifierClearer(DataFormatReifier::clearReifiers); 133 } 134 135 protected final T definition; 136 137 public DataFormatReifier(CamelContext camelContext, T definition) { 138 super(camelContext); 139 this.definition = definition; 140 } 141 142 public static void registerReifier(Class<? extends DataFormatDefinition> dataFormatClass, 143 BiFunction<CamelContext, DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>> creator) { 144 DATAFORMATS.put(dataFormatClass, creator); 145 } 146 147 public static void clearReifiers() { 148 DATAFORMATS.clear(); 149 } 150 151 public static DataFormat getDataFormat(CamelContext camelContext, DataFormatDefinition type) { 152 return getDataFormat(camelContext, ObjectHelper.notNull(type, "type"), null); 153 } 154 155 public static DataFormat getDataFormat(CamelContext camelContext, String ref) { 156 return getDataFormat(camelContext, null, ObjectHelper.notNull(ref, "ref")); 157 } 158 159 /** 160 * Factory method to create the data format 161 * 162 * @param camelContext the camel context 163 * @param type the data format type 164 * @param ref reference to lookup for a data format 165 * @return the data format or null if not possible to create 166 */ 167 public static DataFormat getDataFormat(CamelContext camelContext, DataFormatDefinition type, String ref) { 168 if (type == null) { 169 ObjectHelper.notNull(ref, "ref or type"); 170 171 DataFormat dataFormat = CamelContextHelper.lookup(camelContext, ref, DataFormat.class); 172 if (dataFormat != null) { 173 return dataFormat; 174 } 175 176 // try to let resolver see if it can resolve it, its not always 177 // possible 178 type = camelContext.getExtension(Model.class).resolveDataFormatDefinition(ref); 179 180 if (type == null) { 181 dataFormat = camelContext.resolveDataFormat(ref); 182 if (dataFormat == null) { 183 throw new IllegalArgumentException("Cannot find data format in registry with ref: " + ref); 184 } 185 186 return dataFormat; 187 } 188 } 189 if (type.getDataFormat() != null) { 190 return type.getDataFormat(); 191 } 192 return reifier(camelContext, type).createDataFormat(); 193 } 194 195 public static DataFormatReifier<? extends DataFormatDefinition> reifier(CamelContext camelContext, DataFormatDefinition definition) { 196 BiFunction<CamelContext, DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>> reifier = DATAFORMATS.get(definition.getClass()); 197 if (reifier != null) { 198 return reifier.apply(camelContext, definition); 199 } 200 throw new IllegalStateException("Unsupported definition: " + definition); 201 } 202 203 public DataFormat createDataFormat() { 204 DataFormat dataFormat = definition.getDataFormat(); 205 if (dataFormat == null) { 206 dataFormat = doCreateDataFormat(); 207 if (dataFormat != null) { 208 if (dataFormat instanceof DataFormatContentTypeHeader) { 209 // is enabled by default so assume true if null 210 final boolean contentTypeHeader = parseBoolean(definition.getContentTypeHeader(), true); 211 ((DataFormatContentTypeHeader) dataFormat).setContentTypeHeader(contentTypeHeader); 212 } 213 // configure the rest of the options 214 configureDataFormat(dataFormat); 215 } else { 216 throw new IllegalArgumentException("Data format '" + (definition.getDataFormatName() != null ? definition.getDataFormatName() : "<null>") 217 + "' could not be created. " 218 + "Ensure that the data format is valid and the associated Camel component is present on the classpath"); 219 } 220 } 221 return dataFormat; 222 } 223 224 /** 225 * Factory method to create the data format instance 226 */ 227 protected DataFormat doCreateDataFormat() { 228 // must use getDataFormatName() as we need special logic in json dataformat 229 String dfn = definition.getDataFormatName(); 230 if (dfn != null) { 231 return camelContext.createDataFormat(dfn); 232 } 233 return null; 234 } 235 236 private String getDataFormatName() { 237 return definition.getDataFormatName(); 238 } 239 240 /** 241 * Allows derived classes to customize the data format 242 */ 243 protected void configureDataFormat(DataFormat dataFormat) { 244 Map<String, Object> properties = new LinkedHashMap<>(); 245 prepareDataFormatConfig(properties); 246 properties.entrySet().removeIf(e -> e.getValue() == null); 247 248 PropertyConfigurer configurer = findPropertyConfigurer(dataFormat); 249 250 PropertyBindingSupport.build() 251 .withCamelContext(camelContext) 252 .withTarget(dataFormat) 253 .withReference(true) 254 .withMandatory(true) 255 .withConfigurer(configurer) 256 .withProperties(properties) 257 .bind(); 258 } 259 260 private PropertyConfigurer findPropertyConfigurer(DataFormat dataFormat) { 261 PropertyConfigurer configurer = null; 262 String name = getDataFormatName(); 263 LOG.trace("Discovering optional dataformat property configurer class for dataformat: {}", name); 264 if (dataFormat instanceof PropertyConfigurerAware) { 265 configurer = ((PropertyConfigurerAware) dataFormat).getPropertyConfigurer(dataFormat); 266 if (LOG.isDebugEnabled() && configurer != null) { 267 LOG.debug("Discovered dataformat property configurer using the PropertyConfigurerAware: {} -> {}", name, configurer); 268 } 269 } 270 if (configurer == null) { 271 String configurerName = name + "-dataformat-configurer"; 272 configurer = camelContext.adapt(ExtendedCamelContext.class).getConfigurerResolver().resolvePropertyConfigurer(configurerName, camelContext); 273 } 274 return configurer; 275 } 276 277 protected abstract void prepareDataFormatConfig(Map<String, Object> properties); 278 279}