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.Map; 021import java.util.function.Function; 022 023import org.apache.camel.CamelContext; 024import org.apache.camel.ExtendedCamelContext; 025import org.apache.camel.model.DataFormatDefinition; 026import org.apache.camel.model.Model; 027import org.apache.camel.model.ProcessorDefinitionHelper; 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.spi.DataFormat; 071import org.apache.camel.util.ObjectHelper; 072 073import static org.apache.camel.support.EndpointHelper.isReferenceParameter; 074 075public abstract class DataFormatReifier<T extends DataFormatDefinition> { 076 077 private static final Map<Class<? extends DataFormatDefinition>, Function<DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>>> DATAFORMATS; 078 static { 079 Map<Class<? extends DataFormatDefinition>, Function<DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>>> map = new HashMap<>(); 080 map.put(Any23DataFormat.class, Any23DataFormatReifier::new); 081 map.put(ASN1DataFormat.class, ASN1DataFormatReifier::new); 082 map.put(AvroDataFormat.class, AvroDataFormatReifier::new); 083 map.put(BarcodeDataFormat.class, BarcodeDataFormatReifier::new); 084 map.put(Base64DataFormat.class, Base64DataFormatReifier::new); 085 map.put(BeanioDataFormat.class, BeanioDataFormatReifier::new); 086 map.put(BindyDataFormat.class, BindyDataFormatReifier::new); 087 map.put(CBORDataFormat.class, CBORDataFormatReifier::new); 088 map.put(CryptoDataFormat.class, CryptoDataFormatReifier::new); 089 map.put(CsvDataFormat.class, CsvDataFormatReifier::new); 090 map.put(CustomDataFormat.class, CustomDataFormatReifier::new); 091 map.put(FhirDataformat.class, FhirDataFormatReifier::new); 092 map.put(FhirJsonDataFormat.class, FhirJsonDataFormatReifier::new); 093 map.put(FhirXmlDataFormat.class, FhirXmlDataFormatReifier::new); 094 map.put(FlatpackDataFormat.class, FlatpackDataFormatReifier::new); 095 map.put(GrokDataFormat.class, GrokDataFormatReifier::new); 096 map.put(GzipDataFormat.class, GzipDataFormatReifier::new); 097 map.put(HL7DataFormat.class, HL7DataFormatReifier::new); 098 map.put(IcalDataFormat.class, IcalDataFormatReifier::new); 099 map.put(JacksonXMLDataFormat.class, JacksonXMLDataFormatReifier::new); 100 map.put(JaxbDataFormat.class, JaxbDataFormatReifier::new); 101 map.put(JsonApiDataFormat.class, JsonApiDataFormatReifier::new); 102 map.put(JsonDataFormat.class, JsonDataFormatReifier::new); 103 map.put(LZFDataFormat.class, LZFDataFormatReifier::new); 104 map.put(MimeMultipartDataFormat.class, MimeMultipartDataFormatReifier::new); 105 map.put(PGPDataFormat.class, PGPDataFormatReifier::new); 106 map.put(ProtobufDataFormat.class, ProtobufDataFormatReifier::new); 107 map.put(RssDataFormat.class, RssDataFormatReifier::new); 108 map.put(SoapJaxbDataFormat.class, SoapJaxbDataFormatReifier::new); 109 map.put(SyslogDataFormat.class, SyslogDataFormatReifier::new); 110 map.put(TarFileDataFormat.class, TarFileDataFormatReifier::new); 111 map.put(ThriftDataFormat.class, ThriftDataFormatReifier::new); 112 map.put(TidyMarkupDataFormat.class, TidyMarkupDataFormatReifier::new); 113 map.put(UniVocityCsvDataFormat.class, UniVocityCsvDataFormatReifier::new); 114 map.put(UniVocityFixedWidthDataFormat.class, UniVocityFixedWidthDataFormatReifier::new); 115 map.put(UniVocityTsvDataFormat.class, UniVocityTsvDataFormatReifier::new); 116 map.put(XmlRpcDataFormat.class, XmlRpcDataFormatReifier::new); 117 map.put(XMLSecurityDataFormat.class, XMLSecurityDataFormatReifier::new); 118 map.put(XStreamDataFormat.class, XStreamDataFormatReifier::new); 119 map.put(YAMLDataFormat.class, YAMLDataFormatReifier::new); 120 map.put(ZipDeflaterDataFormat.class, ZipDataFormatReifier::new); 121 map.put(ZipFileDataFormat.class, ZipFileDataFormatReifier::new); 122 DATAFORMATS = map; 123 } 124 125 protected final T definition; 126 127 public DataFormatReifier(T definition) { 128 this.definition = definition; 129 } 130 131 public static void registerReifier(Class<? extends DataFormatDefinition> dataFormatClass, 132 Function<DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>> creator) { 133 DATAFORMATS.put(dataFormatClass, creator); 134 } 135 136 /** 137 * Factory method to create the data format 138 * 139 * @param camelContext the camel context 140 * @param type the data format type 141 * @param ref reference to lookup for a data format 142 * @return the data format or null if not possible to create 143 */ 144 public static DataFormat getDataFormat(CamelContext camelContext, DataFormatDefinition type, String ref) { 145 if (type == null) { 146 ObjectHelper.notNull(ref, "ref or type"); 147 148 DataFormat dataFormat = camelContext.getRegistry().lookupByNameAndType(ref, DataFormat.class); 149 if (dataFormat != null) { 150 return dataFormat; 151 } 152 153 // try to let resolver see if it can resolve it, its not always 154 // possible 155 type = camelContext.getExtension(Model.class).resolveDataFormatDefinition(ref); 156 157 if (type == null) { 158 dataFormat = camelContext.resolveDataFormat(ref); 159 if (dataFormat == null) { 160 throw new IllegalArgumentException("Cannot find data format in registry with ref: " + ref); 161 } 162 163 return dataFormat; 164 } 165 } 166 if (type.getDataFormat() != null) { 167 return type.getDataFormat(); 168 } 169 return reifier(type).createDataFormat(camelContext); 170 } 171 172 public static DataFormatReifier<? extends DataFormatDefinition> reifier(DataFormatDefinition definition) { 173 Function<DataFormatDefinition, DataFormatReifier<? extends DataFormatDefinition>> reifier = DATAFORMATS.get(definition.getClass()); 174 if (reifier != null) { 175 return reifier.apply(definition); 176 } 177 throw new IllegalStateException("Unsupported definition: " + definition); 178 } 179 180 public DataFormat createDataFormat(CamelContext camelContext) { 181 DataFormat dataFormat = definition.getDataFormat(); 182 if (dataFormat == null) { 183 Runnable propertyPlaceholdersChangeReverter = ProcessorDefinitionHelper.createPropertyPlaceholdersChangeReverter(); 184 185 // resolve properties before we create the data format 186 try { 187 ProcessorDefinitionHelper.resolvePropertyPlaceholders(camelContext, definition); 188 } catch (Exception e) { 189 throw new IllegalArgumentException("Error resolving property placeholders on data format: " + definition, e); 190 } 191 try { 192 dataFormat = doCreateDataFormat(camelContext); 193 if (dataFormat != null) { 194 // is enabled by default so assume true if null 195 final boolean contentTypeHeader = definition.getContentTypeHeader() == null || definition.getContentTypeHeader(); 196 try { 197 setProperty(camelContext, dataFormat, "contentTypeHeader", contentTypeHeader); 198 } catch (Exception e) { 199 // ignore as this option is optional and not all data 200 // formats support this 201 } 202 // configure the rest of the options 203 configureDataFormat(dataFormat, camelContext); 204 } else { 205 throw new IllegalArgumentException("Data format '" + (definition.getDataFormatName() != null ? definition.getDataFormatName() : "<null>") 206 + "' could not be created. " 207 + "Ensure that the data format is valid and the associated Camel component is present on the classpath"); 208 } 209 } finally { 210 propertyPlaceholdersChangeReverter.run(); 211 } 212 } 213 return dataFormat; 214 } 215 216 /** 217 * Factory method to create the data format instance 218 */ 219 protected DataFormat doCreateDataFormat(CamelContext camelContext) { 220 // must use getDataFormatName() as we need special logic in json 221 // dataformat 222 if (definition.getDataFormatName() != null) { 223 return camelContext.createDataFormat(definition.getDataFormatName()); 224 } 225 return null; 226 } 227 228 /** 229 * Allows derived classes to customize the data format 230 */ 231 protected void configureDataFormat(DataFormat dataFormat, CamelContext camelContext) { 232 } 233 234 /** 235 * Sets a named property on the data format instance using introspection 236 */ 237 protected void setProperty(CamelContext camelContext, Object bean, String name, Object value) { 238 try { 239 String ref = value instanceof String ? value.toString() : null; 240 if (isReferenceParameter(ref) && camelContext != null) { 241 camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection().setProperty(camelContext, camelContext.getTypeConverter(), bean, name, null, ref, true, false, false); 242 } else { 243 camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection().setProperty(camelContext, bean, name, value); 244 } 245 } catch (Exception e) { 246 throw new IllegalArgumentException("Failed to set property: " + name + " on: " + bean + ". Reason: " + e, e); 247 } 248 } 249 250}