Package org.jboss.soa.esb.listeners.gateway

Source Code of org.jboss.soa.esb.listeners.gateway.AbstractFileGateway$LegacyFileMessageComposerAdapter

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.soa.esb.listeners.gateway;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.Service;
import org.jboss.soa.esb.addressing.eprs.FileEpr;
import org.jboss.soa.esb.schedule.SchedulingException;
import org.jboss.soa.esb.common.Environment;
import org.jboss.soa.esb.couriers.CourierException;
import org.jboss.soa.esb.filter.FilterManager;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import org.jboss.soa.esb.listeners.ListenerUtil;
import org.jboss.soa.esb.client.ServiceInvoker;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.listeners.message.MessageComposer;
import org.jboss.soa.esb.listeners.lifecycle.*;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.services.registry.RegistryException;
import org.jboss.internal.soa.esb.message.LegacyMessageComposerAdapter;

/**
* Base class for all file gateways: local filesystem, ftp, sftp and ftps.
* <p/>Implementations for file manipulation (getFileList, getFileContents,
* renameFile and deleteFile) must be provided by factory
*
* @author <a href="mailto:schifest@heuristica.com.ar">schifest@heuristica.com.ar</a>
* @since Version 4.0
*/
public abstract class AbstractFileGateway extends AbstractScheduledManagedLifecycle {

    protected final static Logger _logger = Logger
            .getLogger(AbstractFileGateway.class);

    protected ConfigTree config;

    protected long _maxMillisForResponse;

    protected Service targetService;

    protected ServiceInvoker serviceInvoker;

    protected MessageComposer messageComposer;

    protected boolean _deleteAfterOK;
    protected boolean _renameAfterOK;

    protected File _inputDirectory, _errorDirectory, _postProcessDirectory;

    protected String _inputSuffix, _postProcessSuffix, _workingSuffix,
            _errorSuffix;

    protected AbstractFileGateway(ConfigTree config) throws ConfigurationException, RegistryException, GatewayException {
        super(config);
        this.config = config;
        checkMyParms();
    }

    /**
     * Handle the initialisation of the managed instance.
     *
     * @throws ManagedLifecycleException for errors while initialisation.
     */
    protected void doInitialise() throws ManagedLifecycleException {
        try {
            serviceInvoker = new ServiceInvoker(targetService);
        } catch (MessageDeliverException e) {
            throw new ManagedLifecycleException(e);
        }
    }

    /**
     * Execute on trigger from the scheduler.
     */
    public void onSchedule() throws SchedulingException {

        File[] fileList;
        try {
            fileList = getFileList();
            if(fileList == null) {
                _logger.warn("No files to process.");
                return;
            }
        }
        catch (GatewayException e) {
            _logger.error("Can't retrieve file list", e);
            return;
        }

        for (File fileIn : fileList) {

            // Only continue to process files if we're in a STARTED state...
            if(getState() != ManagedLifecycleState.STARTED) {
                break;
            }

            // Set the file working.  If that fails, move to the next file...
            File workingFile = setFileWorking(fileIn);
            if (workingFile == null) {
                continue;
            }

            try {
                Message message;
               
                try {
                    message = messageComposer.compose(workingFile);
                } catch (MessageDeliverException e) {
                    processException("Composer <" + messageComposer.getClass().getName() + "> Failed.", e, fileIn, workingFile);
                    continue;
                }
                if (message == null) {
                    _logger.warn("Composer <" + messageComposer.getClass().getName() + "> returned a null object");
                    continue;
                }

                Map<String, Object> params = new HashMap<String, Object>();

                params.put(Environment.ORIGINAL_FILE, fileIn);
                params.put(Environment.GATEWAY_CONFIG, config);

                message = FilterManager.getInstance().doOutputWork(message, params);
                try {
                    if (_maxMillisForResponse > 0) {
                        Message replyMsg = serviceInvoker.deliverSync(message, _maxMillisForResponse);
                        replyMsg.getAttachment().put(Environment.ORIGINAL_FILE, fileIn); // For backward compatibility!
                        try {
                            processReply(replyMsg, fileIn);
                        } catch (GatewayException e) {
                            processException("Failed to process reply.", e, fileIn, workingFile);
                            continue;
                        }
                    } else {
                        serviceInvoker.deliverAsync(message);
                    }
                } catch (MessageDeliverException e) {
                    processException("Message Delivery Failure.", e, fileIn, workingFile);
                    continue;
                } catch (RegistryException e) {
                    processException("Message Delivery Failure.", e, fileIn, workingFile);
                    continue;
                }
            } catch (CourierException e) {
                processException("Message Delivery Failure.", e, fileIn, workingFile);
                continue;
            }

            // The message has been successfully processed...
            processingComplete(fileIn, workingFile);
        }
    }

    private void processingComplete(File fileIn, File workingFile) {
        File fileOK = new File(_postProcessDirectory, fileIn.getName() + _postProcessSuffix);
        if (_deleteAfterOK) {
            try {
                deleteFile(workingFile);
            }
            catch (GatewayException e) {
                _logger.error("File "+ fileIn + " has been processed and renamed to " + workingFile
                                + ", but there were problems deleting it from the input directory ", e);
            }
        } else {
            try {
                if (_renameAfterOK) {
                    renameFile(workingFile, fileOK);
                }
            }
            catch (GatewayException e) {
                _logger.error("File " + fileIn + " has been processed and renamed to " + workingFile
                                        + ", but there were problems renaming it to " + fileOK, e);
            }
        }
    }

    private void processException(String message, Throwable thrown, File fileIn, File workingFile) {
        _logger.error(message, thrown);
        File fileError = new File(_errorDirectory, fileIn.getName() + _errorSuffix);

        try {
            deleteFile(fileError);
        } catch (GatewayException e) {
            _logger.warn("File : " + fileError + " did not exist.");
        }
        try {
            renameFile(workingFile, fileError);
        }catch (GatewayException e) {
            _logger.error("Problems renaming file " + workingFile + " to " + fileError, e);
        }
    }

    private void processReply(Message replyMsg, File fileIn) throws MessageDeliverException, GatewayException {
        Object responseData = messageComposer.decompose(replyMsg, fileIn);

        if(responseData == null) {
            // Legacy composers may handled response delivery themselves...
        } else if(responseData instanceof byte[]) {
            File responseFile = new File(fileIn.getParent(), fileIn.getName() + FileEpr.DEFAULT_REPLY_TO_FILE_SUFFIX + "_gw");

            bytesToFile((byte[])responseData, responseFile);
        } else {
            _logger.error("File based composers must return a byte[] from their decompose implementations.");
        }
    }

    protected File setFileWorking(File file) {
        File workingFile = getWorkFileName(file, _workingSuffix);
       
        try {
            if (renameFile(file, workingFile)) {
                return workingFile;
            }
        } catch (GatewayException e) {
            _logger.error("Unable to rename file '" + file.getAbsolutePath() + "' to it's working name '" + workingFile + "'. May be a contention issue with another listener.  You should avoid having multiple listeners polling on the same file subset.  Ignoring this file for now!");
        }

        return null;
    }

    protected File getWorkFileName(File fileIn, String suffix) {
        return new File(fileIn.toString() + _workingSuffix);
    }

    /*
         * Is the input suffix valid for this type of gateway?
         */

    protected void checkInputSuffix() throws ConfigurationException {
        if (_inputSuffix.length() < 1)
            throw new ConfigurationException("Invalid "
                    + ListenerTagNames.FILE_INPUT_SFX_TAG + " attribute");
    }

    /**
     * Check for mandatory and optional attributes in parameter tree
     *
     * @throws ConfigurationException Mandatory atts are not right or actionClass not in classpath.
     */
    private void checkMyParms() throws ConfigurationException {

        targetService = Service.getGatewayTargetService(config);

        String composerClass = config.getAttribute(ListenerTagNames.GATEWAY_COMPOSER_CLASS_TAG);
        if(composerClass == null) {
            composerClass = getDefaultComposer();
        }
        messageComposer = MessageComposer.Factory.getInstance(composerClass, config, LegacyFileMessageComposerAdapter.class);

        _maxMillisForResponse = ListenerUtil.getMaxMillisGatewayWait(config, _logger);

        String sInpDir = getInputDir(config);

        _inputDirectory = fileFromString(sInpDir);
        seeIfOkToWorkOnDir(_inputDirectory);

        _inputSuffix = ListenerUtil.getValue(config, ListenerTagNames.FILE_INPUT_SFX_TAG, "").trim();
        checkInputSuffix();

        // WORK suffix (will rename in input directory)
        _workingSuffix = ListenerUtil.getValue(config, ListenerTagNames.FILE_WORK_SFX_TAG, ".esbWork").trim();
        if (_workingSuffix.length() < 1) {
            throw new ConfigurationException("Invalid "+ ListenerTagNames.FILE_WORK_SFX_TAG + " attribute");
        }

        if (_inputSuffix.equals(_workingSuffix)) {
            throw new ConfigurationException("Work suffix must differ from input suffix <" + _workingSuffix + ">");
        }

        // ERROR directory and suffix (defaults to input dir and
        // ".esbError"
        // suffix)
        String sErrDir = ListenerUtil.getValue(config, ListenerTagNames.FILE_ERROR_DIR_TAG, sInpDir);
        _errorDirectory = fileFromString(sErrDir);
        seeIfOkToWorkOnDir(_errorDirectory);

        _errorSuffix = ListenerUtil.getValue(config, ListenerTagNames.FILE_ERROR_SFX_TAG, ".esbError").trim();
        if (_errorSuffix.length() < 1) {
            throw new ConfigurationException("Invalid " + ListenerTagNames.FILE_ERROR_SFX_TAG + " attribute");
        }
        if (_errorDirectory.equals(_inputDirectory) && _inputSuffix.equals(_errorSuffix)) {
            throw new ConfigurationException("Error suffix must differ from input suffix <" + _errorSuffix + ">");
        }

        // Do users wish to delete files that were processed OK ?
        String sPostDel = ListenerUtil.getValue(config, ListenerTagNames.FILE_POST_DEL_TAG, "false").trim();
        _deleteAfterOK = Boolean.parseBoolean(sPostDel);
        if (_deleteAfterOK) {
            return;
        }
       
        // Do users wish to rename files that were processed OK ?
        String sPostRename = ListenerUtil.getValue(config, ListenerTagNames.FILE_POST_RENAME_TAG, "true").trim();
        _renameAfterOK = Boolean.parseBoolean(sPostRename);

        // POST (done) directory and suffix (defaults to input dir and
        // ".esbDone" suffix)
        String sPostDir = ListenerUtil.getValue(config, ListenerTagNames.FILE_POST_DIR_TAG, sInpDir);
        _postProcessDirectory = fileFromString(sPostDir);
        seeIfOkToWorkOnDir(_postProcessDirectory);
        _postProcessSuffix = ListenerUtil.getValue(config, ListenerTagNames.FILE_POST_SFX_TAG, ".esbDone").trim();

        if (_postProcessDirectory.equals(_inputDirectory)) {
            if (_postProcessSuffix.length() < 1) {
                throw new ConfigurationException("Invalid " + ListenerTagNames.FILE_POST_SFX_TAG + " attribute");
            }
            if (_postProcessSuffix.equals(_inputSuffix)) {
                throw new ConfigurationException("Post process suffix must differ from input suffix <" + _postProcessSuffix + ">");
            }
        }
    }

    public static File getFileInputDirectory(ConfigTree config) throws ConfigurationException {
        String sInpDir = getInputDir(config);
        return fileFromString(sInpDir);
    }

    private static String getInputDir(ConfigTree config) throws ConfigurationException {
        String uri = config.getAttribute(ListenerTagNames.URL_TAG);

        if(uri != null) {
            try {
                return new URI(uri).getPath();
            } catch (URISyntaxException e) {
                throw new ConfigurationException("Invalid '" + ListenerTagNames.URL_TAG + "' value '" + uri + "'.  Must be a valid URI.");
            }
        }

        return config.getRequiredAttribute(ListenerTagNames.FILE_INPUT_DIR_TAG);
    }

    private static File fileFromString(String file) {
        try {
            return new File(new URI(file));
        }
        catch (Exception e) {
            return new File(file);
        }
    }

    abstract File[] getFileList() throws GatewayException;

    abstract byte[] getFileContents(File file) throws GatewayException;

    abstract boolean renameFile(File from, File to) throws GatewayException;

    abstract boolean deleteFile(File file) throws GatewayException;

    abstract void seeIfOkToWorkOnDir(File p_oDir) throws ConfigurationException;

    abstract String getDefaultComposer() throws ConfigurationException;

    abstract void bytesToFile(byte[] bytes, File file) throws GatewayException;

    /**
     * Legacy Message composer adapter for the file based gateways.
     * <p/>
     * The old AbstractFileGateway used to leave it to the composer to handle the
     * response.  It also used to supply the composer with the input file and leave
     * it to the composer to determine the name of the output file.
     *
     * @author <a href="mailto:tom.fennelly@jboss.com">tom.fennelly@jboss.com</a>
     */
    private class LegacyFileMessageComposerAdapter<T extends File> extends LegacyMessageComposerAdapter<T> {

        public Object decompose(Message message, T inputFile) throws MessageDeliverException {
            try {
                return _responderMethod.invoke(_composer, message, inputFile);
            } catch (IllegalAccessException e) {
                throw new MessageDeliverException("Legacy composer class ('" + _composerClass.getName() + "') responder method '" + _responderMethod.getName() + "' is not callable.", e);
            } catch (InvocationTargetException e) {
                throw new MessageDeliverException("Legacy composer class ('" + _composerClass.getName() + "') responder method '" + _responderMethod.getName() + "' failed with exception.", e.getCause());
            }
        }

        public Class[] getResponderParameters() {
            return new Class[]{Message.class, File.class};
        }
    }
}
TOP

Related Classes of org.jboss.soa.esb.listeners.gateway.AbstractFileGateway$LegacyFileMessageComposerAdapter

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.