/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.dozer; import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.el.ExpressionFactory; import org.apache.camel.Component; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.Producer; import org.apache.camel.converter.dozer.DozerTypeConverterLoader; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ResourceHelper; import org.dozer.CustomConverter; import org.dozer.DozerBeanMapper; import org.dozer.config.BeanContainer; import org.dozer.loader.xml.ELEngine; import org.dozer.loader.xml.ElementReader; import org.dozer.loader.xml.ExpressionElementReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The dozer component provides the ability to map between Java beans using the Dozer mapping library. */ @UriEndpoint(firstVersion = "2.15.0", scheme = "dozer", title = "Dozer", syntax = "dozer:name", producerOnly = true, label = "transformation") public class DozerEndpoint extends DefaultEndpoint { private static final Logger LOG = LoggerFactory.getLogger(DozerEndpoint.class); // IDs for built-in custom converters used with the Dozer component private static final String CUSTOM_MAPPING_ID = "_customMapping"; private static final String VARIABLE_MAPPING_ID = "_variableMapping"; private static final String EXPRESSION_MAPPING_ID = "_expressionMapping"; private DozerBeanMapper mapper; private VariableMapper variableMapper; private CustomMapper customMapper; private ExpressionMapper expressionMapper; @UriParam private DozerConfiguration configuration; public DozerEndpoint(String endpointUri, Component component, DozerConfiguration configuration) throws Exception { super(endpointUri, component); this.configuration = configuration; variableMapper = new VariableMapper(); customMapper = new CustomMapper(getCamelContext().getClassResolver()); expressionMapper = new ExpressionMapper(); } @Override public Producer createProducer() throws Exception { return new DozerProducer(this); } @Override public Consumer createConsumer(Processor processor) throws Exception { throw new UnsupportedOperationException("Consumer not supported for Dozer endpoints"); } @Override public boolean isSingleton() { return true; } public DozerBeanMapper getMapper() throws Exception { return mapper; } public DozerConfiguration getConfiguration() { return configuration; } public void setConfiguration(DozerConfiguration configuration) { this.configuration = configuration; } CustomMapper getCustomMapper() { return customMapper; } VariableMapper getVariableMapper() { return variableMapper; } ExpressionMapper getExpressionMapper() { return expressionMapper; } @Override protected void doStart() throws Exception { super.doStart(); initDozerBeanContainerAndMapper(); } @Override protected void doStop() throws Exception { super.doStop(); // noop } protected void initDozerBeanContainerAndMapper() throws Exception { LOG.info("Configuring DozerBeanContainer and DozerBeanMapper"); // init the expression engine with a fallback to the impl from glasfish initELEngine(); // configure mapper as well if (mapper == null) { if (configuration.getMappingConfiguration() != null) { mapper = DozerTypeConverterLoader.createDozerBeanMapper( configuration.getMappingConfiguration()); } else { mapper = createDozerBeanMapper(); } configureMapper(mapper); } } public void initELEngine() { String elprop = System.getProperty("javax.el.ExpressionFactory"); ClassLoader tccl = Thread.currentThread().getContextClassLoader(); try { ClassLoader appcl = getCamelContext().getApplicationContextClassLoader(); ClassLoader auxcl = appcl != null ? appcl : DozerEndpoint.class.getClassLoader(); Thread.currentThread().setContextClassLoader(auxcl); try { Class<?> clazz = auxcl.loadClass("com.sun.el.ExpressionFactoryImpl"); ExpressionFactory factory = (ExpressionFactory) clazz.newInstance(); System.setProperty("javax.el.ExpressionFactory", factory.getClass().getName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { LOG.debug("Cannot load glasfish expression engine, using default"); } ELEngine engine = new ELEngine(); engine.init(); BeanContainer.getInstance().setElEngine(engine); ElementReader reader = new ExpressionElementReader(engine); BeanContainer.getInstance().setElementReader(reader); } finally { Thread.currentThread().setContextClassLoader(tccl); if (elprop != null) { System.setProperty("javax.el.ExpressionFactory", elprop); } else { System.clearProperty("javax.el.ExpressionFactory"); } } } private DozerBeanMapper createDozerBeanMapper() throws Exception { DozerBeanMapper answer = DozerComponent.createDozerBeanMapper(Collections.<String>emptyList()); InputStream mapStream = null; try { LOG.info("Loading Dozer mapping file {}.", configuration.getMappingFile()); // create the mapper instance and add the mapping file mapStream = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext(), configuration.getMappingFile()); answer.addMapping(mapStream); } finally { IOHelper.close(mapStream); } return answer; } private void configureMapper(DozerBeanMapper mapper) throws Exception { // add our built-in converters Map<String, CustomConverter> converters = new HashMap<String, CustomConverter>(); converters.put(CUSTOM_MAPPING_ID, customMapper); converters.put(VARIABLE_MAPPING_ID, variableMapper); converters.put(EXPRESSION_MAPPING_ID, expressionMapper); converters.putAll(mapper.getCustomConvertersWithId()); mapper.setCustomConvertersWithId(converters); } }