Package org.mule.transformer

Source Code of org.mule.transformer.AbstractTransformer

/*
* $Id: AbstractTransformer.java 21939 2011-05-18 13:32:09Z aperepel $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/

package org.mule.transformer;

import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.config.MuleProperties;
import org.mule.api.context.notification.MuleContextNotificationListener;
import org.mule.api.endpoint.ImmutableEndpoint;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.transformer.DataType;
import org.mule.api.transformer.Transformer;
import org.mule.api.transformer.TransformerException;
import org.mule.api.transformer.TransformerMessagingException;
import org.mule.config.i18n.CoreMessages;
import org.mule.config.i18n.Message;
import org.mule.context.notification.MuleContextNotification;
import org.mule.context.notification.NotificationException;
import org.mule.transformer.types.DataTypeFactory;
import org.mule.transformer.types.SimpleDataType;
import org.mule.transport.NullPayload;
import org.mule.util.ClassUtils;
import org.mule.util.StringMessageUtils;
import org.mule.util.StringUtils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <code>AbstractTransformer</code> is a base class for all transformers.
* Transformations transform one object into another.
*/

public abstract class AbstractTransformer implements Transformer, MuleContextNotificationListener<MuleContextNotification>
{
    public static final DataType<MuleMessage> MULE_MESSAGE_DATA_TYPE = new SimpleDataType<MuleMessage>(MuleMessage.class);

    protected MuleContext muleContext;

    protected final Log logger = LogFactory.getLog(getClass());

    /**
     * The return type that will be returned by the {@link #transform} method is
     * called
     */
    protected DataType<?> returnType = new SimpleDataType<Object>(Object.class);

    /**
     * The name that identifies this transformer. If none is set the class name of
     * the transformer is used
     */
    protected String name = null;

    /**
     * The endpoint that this transformer instance is configured on
     */
    protected ImmutableEndpoint endpoint = null;

    /**
     * A list of supported Class types that the source payload passed into this
     * transformer
     */
    @SuppressWarnings("unchecked")
    protected final List<DataType<?>> sourceTypes = new CopyOnWriteArrayList/*<DataType>*/();

    /**
     * Determines whether the transformer will throw an exception if the message
     * passed is is not supported
     */
    private boolean ignoreBadInput = false;

    /**
     * Allows a transformer to return a null result
     */
    private boolean allowNullReturn = false;

    /*
     *  Mime type and encoding for transformer output
     */
    protected String mimeType;
    protected String encoding;

    /**
     * default constructor required for discovery
     */
    public AbstractTransformer()
    {
        super();
    }

    public MuleEvent process(MuleEvent event) throws MuleException
    {
        if (event != null && event.getMessage() != null)
        {
            try
            {
                event.getMessage().applyTransformers(event, this);
            }
            catch (Exception e)
            {
                throw new TransformerMessagingException(event, this, e);
            }
        }
        return event;
    }
   
    protected Object checkReturnClass(Object object) throws TransformerException
    {
        //Null is a valid return type
        if(object==null || object instanceof NullPayload && isAllowNullReturn())
        {
            return object;
        }

        if (returnType != null)
        {
            DataType<?> dt = DataTypeFactory.create(object.getClass());
            if (!returnType.isCompatibleWith(dt))
            {
                throw new TransformerException(
                        CoreMessages.transformUnexpectedType(dt, returnType),
                        this);
            }
        }

        if (logger.isDebugEnabled())
        {
            logger.debug("The transformed object is of expected type. Type is: " +
                    ClassUtils.getSimpleName(object.getClass()));
        }

        return object;
    }

    /**
     * Register a supported data type with this transformer.  The will allow objects that match this data type to be
     * transformed by this transformer.
     *
     * @param aClass the source type to allow
     * @deprecated use registerSourceType(DataType)
     */
    @Deprecated
    protected void registerSourceType(Class<?> aClass)
    {
        registerSourceType(new SimpleDataType<Object>(aClass));
    }

    /**
     * Unregister a supported source type from this transformer
     *
     * @param aClass the type to remove
     * @deprecated use unregisterSourceType(DataType)
     */
    @Deprecated
    protected void unregisterSourceType(Class<?> aClass)
    {
        unregisterSourceType(new SimpleDataType<Object>(aClass));
    }

    /**
     * Register a supported data type with this transformer.  The will allow objects that match this data type to be
     * transformed by this transformer.
     *
     * @param dataType the source type to allow
     */
    protected void registerSourceType(DataType<?> dataType)
    {
        if (!sourceTypes.contains(dataType))
        {
            sourceTypes.add(dataType);

            if (dataType.getType().equals(Object.class))
            {
                logger.debug("java.lang.Object has been added as source type for this transformer, there will be no source type checking performed");
            }
        }
    }

    /**
     * Unregister a supported source type from this transformer
     *
     * @param dataType the type to remove
     */
    protected void unregisterSourceType(DataType<?> dataType)
    {
        sourceTypes.remove(dataType);
    }

    /**
     * @return transformer name
     */
    public String getName()
    {
        if (name == null)
        {
            name = this.generateTransformerName();
        }
        return name;
    }

    /**
     * @param string
     */
    public void setName(String string)
    {
        if (string == null)
        {
            string = ClassUtils.getSimpleName(this.getClass());
        }

        logger.debug("Setting transformer name to: " + string);
        name = string;
    }

    @Deprecated
    public Class<?> getReturnClass()
    {
        return returnType.getType();
    }

    public void setReturnDataType(DataType<?> type)
    {
        this.returnType = type.cloneDataType();
        this.encoding = type.getEncoding();
        this.mimeType = type.getMimeType();
    }

    public DataType<?> getReturnDataType()
    {
        return returnType;
    }

    @Deprecated
    public void setReturnClass(Class<?> newClass)
    {
        DataType<?> tempReturnType = new SimpleDataType<Object>(newClass);
        tempReturnType.setMimeType(mimeType);
        tempReturnType.setEncoding(encoding);
        setReturnDataType(tempReturnType);
    }

    public void setMimeType(String mimeType) throws MimeTypeParseException
    {
        if (mimeType == null)
        {
            this.mimeType = null;
        }
        else
        {
            MimeType mt = new MimeType(mimeType);
            this.mimeType = mt.getPrimaryType() + "/" + mt.getSubType();
        }
        if (returnType != null)
        {
            returnType.setMimeType(mimeType);
        }
    }

    public String getMimeType()
    {
        return mimeType;
    }

    public String getEncoding()
    {
        return encoding;
    }

    public void setEncoding(String encoding)
    {
        this.encoding = encoding;
        if (returnType != null)
        {
            returnType.setEncoding(encoding);
        }
    }

    public boolean isAllowNullReturn()
    {
        return allowNullReturn;
    }

    public void setAllowNullReturn(boolean allowNullReturn)
    {
        this.allowNullReturn = allowNullReturn;
    }

    @Deprecated
    public boolean isSourceTypeSupported(Class<?> aClass)
    {
        return isSourceDataTypeSupported(DataTypeFactory.create(aClass), false);
    }

    public boolean isSourceDataTypeSupported(DataType<?> dataType)
    {
        return isSourceDataTypeSupported(dataType, false);
    }

    /**
     * Determines whether that data type passed in is supported by this transformer
     *
     * @param aClass     the type to check against
     * @param exactMatch if the source type on this transformer is open (can be anything) it will return true unless an
     *                   exact match is requested using this flag
     * @return true if the source type is supported by this transformer, false otherwise
     * @deprecated use {@link #isSourceDataTypeSupported(org.mule.api.transformer.DataType, boolean)}
     */
    @Deprecated
    public boolean isSourceTypeSupported(Class<MuleMessage> aClass, boolean exactMatch)
    {
        return isSourceDataTypeSupported(new SimpleDataType<MuleMessage>(aClass), exactMatch);
    }

    /**
     * Determines whether that data type passed in is supported by this transformer
     *
     * @param dataType   the type to check against
     * @param exactMatch if set to true, this method will look for an exact match to the data type, if false it will look
     *                   for a compatible data type.
     * @return true if the source type is supported by this transformer, false otherwise
     */
    public boolean isSourceDataTypeSupported(DataType<?> dataType, boolean exactMatch)
    {
        int numTypes = sourceTypes.size();

        if (numTypes == 0)
        {
            return !exactMatch;
        }

        for (DataType<?> sourceType : sourceTypes)
        {
            if (exactMatch)
            {
                if (sourceType.equals(dataType))
                {
                    return true;
                }
            }
            else
            {
                if (sourceType.isCompatibleWith(dataType))
                {
                    return true;
                }
            }
        }
        return false;
    }

    public final Object transform(Object src) throws TransformerException
    {
        return transform(src, getEncoding(src));
    }

    public Object transform(Object src, String enc) throws TransformerException
    {
        Object payload = src;
        if (src instanceof MuleMessage)
        {
            MuleMessage message = (MuleMessage) src;
            if ((!isSourceDataTypeSupported(MULE_MESSAGE_DATA_TYPE, true) &&
                 !(this instanceof AbstractMessageTransformer)))
            {
                src = ((MuleMessage) src).getPayload();
                payload = message.getPayload();
            }
        }

        DataType<?> sourceType = DataTypeFactory.create(payload.getClass());
        //Once we support mime types, it should be possible to do this since we'll be able to discern the difference
        //between objects with the same type
//        if(getReturnDataType().isCompatibleWith(sourceType))
//        {
//            logger.debug("Object is already of type: " + getReturnDataType() + " No transform to perform");
//            return payload;
//        }

        if (!isSourceDataTypeSupported(sourceType))
        {
            if (ignoreBadInput)
            {
                logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
                return payload;
            }
            else
            {
                Message msg = CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(getName(),
                    payload.getClass(), endpoint);
                /// FIXME
                throw new TransformerException(msg, this);
            }
        }

        if (logger.isDebugEnabled())
        {
            logger.debug(String.format("Applying transformer %s (%s)", getName(), getClass().getName()));
            logger.debug(String.format("Object before transform: %s", StringMessageUtils.toString(payload)));
        }

        Object result = doTransform(payload, enc);

        if (result == null)
        {
            result = NullPayload.getInstance();
        }

        if (logger.isDebugEnabled())
        {
            logger.debug(String.format("Object after transform: %s", StringMessageUtils.toString(result)));
        }

        result = checkReturnClass(result);
        return result;
    }

    protected String getEncoding(Object src)
    {
        String enc = null;
        if (src instanceof MuleMessage)
        {
            enc = ((MuleMessage) src).getEncoding();
        }

        if (enc == null && endpoint != null)
        {
            enc = endpoint.getEncoding();
        }
        else if (enc == null)
        {
            enc = System.getProperty(MuleProperties.MULE_ENCODING_SYSTEM_PROPERTY);
        }
        return enc;
    }

    protected boolean isConsumed(Class<?> srcCls)
    {
        return InputStream.class.isAssignableFrom(srcCls) || StreamSource.class.isAssignableFrom(srcCls);
    }

    public ImmutableEndpoint getEndpoint()
    {
        return endpoint;
    }

    public void setEndpoint(ImmutableEndpoint endpoint)
    {
        this.endpoint = endpoint;
    }

    protected abstract Object doTransform(Object src, String enc) throws TransformerException;

    /**
     * Template method where deriving classes can do any initialisation after the
     * properties have been set on this transformer
     *
     * @throws InitialisationException
     */
    public void initialise() throws InitialisationException
    {
        // do nothing, subclasses may override
    }

    /**
     * Template method where deriving classes can do any clean up any resources or state
     * before the object is disposed.
     */
    public void dispose()
    {
        // do nothing, subclasses may override
    }

    protected String generateTransformerName()
    {
        String transformerName = ClassUtils.getSimpleName(this.getClass());
        int i = transformerName.indexOf("To");
        if (i > 0 && returnType != null)
        {
            String target = ClassUtils.getSimpleName(returnType.getType());
            if (target.equals("byte[]"))
            {
                target = "byteArray";
            }
            transformerName = transformerName.substring(0, i + 2) + StringUtils.capitalize(target);
        }
        return transformerName;
    }

    @Deprecated
    public List<Class<?>> getSourceTypes()
    {
        //A work around to support the legacy API
        List<Class<?>> sourceClasses = new ArrayList<Class<?>>();
        for (DataType<?> sourceType : sourceTypes)
        {
            sourceClasses.add(sourceType.getType());
        }
        return Collections.unmodifiableList(sourceClasses);
    }

    public List<DataType<?>> getSourceDataTypes()
    {
        return Collections.unmodifiableList(sourceTypes);
    }

    public boolean isIgnoreBadInput()
    {
        return ignoreBadInput;
    }

    public void setIgnoreBadInput(boolean ignoreBadInput)
    {
        this.ignoreBadInput = ignoreBadInput;
    }

    @Override
    public String toString()
    {
        StringBuffer sb = new StringBuffer(80);
        sb.append(ClassUtils.getSimpleName(this.getClass()));
        sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
        sb.append(", name='").append(name).append('\'');
        sb.append(", ignoreBadInput=").append(ignoreBadInput);
        sb.append(", returnClass=").append(returnType);
        sb.append(", sourceTypes=").append(sourceTypes);
        sb.append('}');
        return sb.toString();
    }

    public boolean isAcceptNull()
    {
        return false;
    }

    public void setMuleContext(MuleContext context)
    {
        this.muleContext = context;
        try
        {
            muleContext.registerListener(this);
        }
        catch (NotificationException e)
        {
            logger.error("failed to register context listener", e);
        }
    }

    public void onNotification(MuleContextNotification notification)
    {
        if (notification.getAction() == MuleContextNotification.CONTEXT_DISPOSING)
        {
            this.dispose();
        }
    }
}
TOP

Related Classes of org.mule.transformer.AbstractTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.