All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.calrissian.mango.jms.stream.AbstractJmsFileTransferSupport Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2013 The Calrissian Authors
 *
 * Licensed 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.calrissian.mango.jms.stream;

import org.calrissian.mango.jms.stream.domain.Piece;
import org.calrissian.mango.jms.stream.domain.Request;
import org.calrissian.mango.jms.stream.domain.Response;
import org.calrissian.mango.jms.stream.domain.ResponseStatusEnum;
import org.calrissian.mango.jms.stream.utils.DestinationRequestor;
import org.calrissian.mango.jms.stream.utils.DomainMessageUtils;
import org.calrissian.mango.jms.stream.utils.MessageQueueListener;
import org.calrissian.mango.uri.support.UriStreamOpener;
import org.calrissian.mango.uri.support.impl.BasicStreamOpener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.SessionCallback;
import org.springframework.util.Assert;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

@Deprecated
public abstract class AbstractJmsFileTransferSupport {

    protected JmsTemplate jmsTemplate;
    Logger logger = LoggerFactory.getLogger(getClass());
    private int pieceSize = 10240;
    private Destination streamRequestDestination;
    private String hashAlgorithm;

    private UriStreamOpener streamOpener;

    private Logger logService;

    public AbstractJmsFileTransferSupport() {

        this.streamOpener = new BasicStreamOpener();
    }

    public void setStreamOpener(UriStreamOpener streamOpener) {
        this.streamOpener = streamOpener;
    }


    protected String generateId() {
        return UUID.randomUUID().toString();
    }

    public JmsTemplate getJmsTemplate() {
        return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    public int getPieceSize() {
        return pieceSize;
    }

    public void setPieceSize(int pieceSize) {
        this.pieceSize = pieceSize;
    }

    public Destination getStreamRequestDestination() {
        return streamRequestDestination;
    }

    public void setStreamRequestDestination(Destination streamRequestDestination) {
        this.streamRequestDestination = streamRequestDestination;
    }

    public InputStream receiveStream(final Request req)
            throws JmsFileTransferException {
        try {
            logger.info(
                    "Broadcasting request for [" + req.getDownloadUri()
                            + "] and id[" + req.getRequestId() + "]"
            );
            Message returnMessage = sendWithResponse(new MessageCreator() {

                @Override
                public Message createMessage(Session session)
                        throws JMSException {
                    return DomainMessageUtils.toRequestMessage(session, req);
                }

            }, getStreamRequestDestination());

            // No one could fulfill the request
            if (returnMessage == null) {
                logger.info(
                        "No one can fullfil this request ["
                                + req.getDownloadUri() + "]"
                );
                return null;
            }

            // start the stream transfer at this destination
            final Destination receiveAckDestination = returnMessage
                    .getJMSReplyTo();
            final String sendDataDestination = UUID.randomUUID().toString();

            logger.info(
                    "Receiver[" + req.getRequestId()
                            + "]: File Transfer starting"
            );

            return new JmsFileReceiverInputStream(this, sendDataDestination,
                    receiveAckDestination);
        } catch (Exception e) {
            throw new JmsFileTransferException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public void sendStream(Request req, final Destination replyTo)
            throws IOException {

        DigestInputStream is;
        Assert.notNull(req, "Request cannot be null");
        final URI downloadUrl;
        try {
            downloadUrl = new URI(req.getDownloadUri());
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
        try {

            is = new DigestInputStream(new BufferedInputStream(streamOpener.openStream(downloadUrl)),
                    MessageDigest.getInstance(getHashAlgorithm()));


        } catch (NoSuchAlgorithmException e) {
            throw new JmsFileTransferException(e);
        } catch (Throwable e) {

            logger.info("Error occurred opening stream: " + e);
            return;
        }

        MessageQueueListener queueListener = null;
        try {

            @SuppressWarnings("rawtypes")
            Message returnMessage = (Message) jmsTemplate.execute(
                    new SessionCallback() {

                        @Override
                        public Object doInJms(Session session)
                                throws JMSException {
                            DestinationRequestor requestor = null;
                            try {
                                Message responseMessage = DomainMessageUtils
                                        .toResponseMessage(session, new Response(
                                                ResponseStatusEnum.ACCEPT));

                                // Actual file transfer should be done on a queue.
                                // Topics will not work
                                Destination streamTransferDestination = factoryDestination(
                                        session, UUID.randomUUID().toString());
                                requestor = new DestinationRequestor(
                                        session, replyTo,
                                        streamTransferDestination, jmsTemplate
                                        .getReceiveTimeout()
                                );
                                Message returnMessage = requestor
                                        .request(responseMessage);
                                requestor.close();
                                return returnMessage;
                            } finally {
                                if (requestor != null)
                                    requestor.close();
                            }
                        }

                    }, true
            );

            // timeout
            if (returnMessage == null)
                return;
            Response response = DomainMessageUtils
                    .fromResponseMessage(returnMessage);

            // cancel transfer
            if (!ResponseStatusEnum.STARTSEND.equals(response.getStatus()))
                return;

            final Destination receiveAckDestination = returnMessage
                    .getJMSDestination();
            final Destination sendDataDestination = returnMessage
                    .getJMSReplyTo();

            queueListener = new MessageQueueListener(this, receiveAckDestination);

            logger.info(
                    "Sender[" + req.getRequestId() + "]: Starting send to: "
                            + sendDataDestination
            );

            byte[] buffer = new byte[getPieceSize()];
            int read = is.read(buffer);
            long placeInFile = 0;
            while (read >= 0) {
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                stream.write(buffer, 0, read);
                stream.close();
                final byte[] pieceData = stream.toByteArray();
                final Piece piece = new Piece(placeInFile, pieceData,
                        getHashAlgorithm());
                logger.info(
                        "Sender[" + req.getRequestId()
                                + "]: Sending piece with position: "
                                + piece.getPosition() + " Size of piece: "
                                + pieceData.length
                );
                jmsTemplate.send(sendDataDestination, new MessageCreator() {

                    @Override
                    public Message createMessage(Session session)
                            throws JMSException {
                        return DomainMessageUtils
                                .toPieceMessage(session, piece);
                    }

                });
//                Message ret = jmsTemplate.receive(receiveAckDestination);
                Message ret = queueListener.getMessageInQueue();
                logger.info(
                        "Sender[" + req.getRequestId()
                                + "]: Sent piece and got ack"
                );

                // no one on the other end any longer, timeout
                if (ret == null)
                    return;

                Response res = DomainMessageUtils.fromResponseMessage(ret);
                // stop transfer
                if (ResponseStatusEnum.RESEND.equals(res.getStatus())) {
                    // resend piece
                    logger.info(
                            "Sender[" + req.getRequestId()
                                    + "]: Resending piece"
                    );
                } else if (ResponseStatusEnum.DENY.equals(res.getStatus())) {
                    return;
                } else {
                    buffer = new byte[getPieceSize()];
                    placeInFile += read;
                    read = is.read(buffer);
                }
            }

            logger.info(
                    "Sender[" + req.getRequestId() + "]: Sending stop send");

            final DigestInputStream fiIs = is;

            jmsTemplate.send(sendDataDestination, new MessageCreator() {

                @Override
                public Message createMessage(Session session)
                        throws JMSException {
                    Response stopSendResponse = new Response(
                            ResponseStatusEnum.STOPSEND);
                    stopSendResponse.setHash(new String(fiIs.getMessageDigest().digest()));
                    return DomainMessageUtils.toResponseMessage(session,
                            stopSendResponse);
                }

            });

            Message ackMessage = queueListener.getMessageInQueue();

            Object fromMessage = DomainMessageUtils.fromMessage(ackMessage);
            if (fromMessage instanceof Response) {
                Response ackResponse = (Response) fromMessage;
                if (ResponseStatusEnum.RESEND.equals(ackResponse.getStatus())) {
                    // TODO: resend the whole file
                }
            }

        } catch (Exception e) {
            throw new JmsFileTransferException(e);
        } finally {
            try {
                is.close();
            } catch (IOException ignored) {
            }
            if (queueListener != null)
                queueListener.close();
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    protected Message sendWithResponse(final MessageCreator mc,
                                       final Destination replyTo) {
        return (Message) jmsTemplate.execute(new SessionCallback() {

            @Override
            public Object doInJms(Session session) throws JMSException {
                DestinationRequestor requestor = null;
                try {
                    Message sendMessage = mc.createMessage(session);

                    requestor = new DestinationRequestor(
                            session, replyTo, jmsTemplate.getReceiveTimeout());

                    Message returnMessage = requestor.request(sendMessage);

                    requestor.close();
                    return returnMessage;
                } finally {
                    if (requestor != null)
                        requestor.close();
                }
            }

        }, true);
    }

    protected Destination factoryDestination(Session session, String destinationName)
            throws JMSException {
        return jmsTemplate.getDestinationResolver().resolveDestinationName(
                session, destinationName, true);
    }

    public String getHashAlgorithm() {
        return hashAlgorithm;
    }

    public void setHashAlgorithm(String hashAlgorithm) {
        this.hashAlgorithm = hashAlgorithm;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy