de.elomagic.carafile.server.bl.SeedBean.java Source code

Java tutorial

Introduction

Here is the source code for de.elomagic.carafile.server.bl.SeedBean.java

Source

/*
 * Copyright 2014 Carsten Rambow, elomagic.
 *
 * 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 de.elomagic.carafile.server.bl;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.DigestInputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Date;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.ws.rs.core.UriBuilder;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.log4j.Logger;

import static de.elomagic.carafile.client.CaraFileUtils.DEFAULT_PIECE_SIZE;
import de.elomagic.carafile.server.Constants;
import de.elomagic.carafile.server.dao.ChunkDAO;
import de.elomagic.carafile.server.model.Chunk;
import de.elomagic.carafile.share.ChunkData;
import de.elomagic.carafile.share.MetaData;

/**
 * Business logic bean for seeding files.
 *
 * @author carsten.rambow
 */
public class SeedBean {
    private static final Logger LOG = Logger.getLogger(SeedBean.class);

    @Resource(mappedName = "ConnectionFactory")
    private static ConnectionFactory connectionFactory;
    @Resource(mappedName = Constants.JMS_QUEUE_REGISTER_FILE)
    private static Queue fileQueue;
    @Resource(mappedName = Constants.JMS_QUEUE_REGISTER_CHUNK)
    private static Queue chunkQueue;
    @Resource(lookup = Constants.JNDI_REGISTRY_URI)
    private String registryURI;
    @Resource(lookup = Constants.JNDI_OWN_PEER_URI)
    private String ownURI;

    @Inject
    private RepositoryBean repositoryBean;
    @Inject
    private ChunkDAO chunkDAO;

    public MetaData seedFile(final InputStream inputStream, final String filename)
            throws IOException, GeneralSecurityException, JMSException {
        LOG.debug("Seeding file " + filename);
        MetaData md;
        md = new MetaData();
        md.setFilename(filename);
        md.setCreationDate(new Date());
        md.setChunkSize(DEFAULT_PIECE_SIZE);
        md.setRegistryURI(UriBuilder.fromUri(registryURI).build());

        MessageDigest messageDigest = DigestUtils.getSha1Digest();
        long totalBytes = 0;

        try (DigestInputStream dis = new DigestInputStream(inputStream, messageDigest)) {
            byte[] buffer = new byte[md.getChunkSize()];
            int bytesRead;
            while ((bytesRead = readBlock(dis, buffer)) > 0) {
                totalBytes += bytesRead;
                String chunkId = Hex
                        .encodeHexString(DigestUtils.sha1(new ByteArrayInputStream(buffer, 0, bytesRead)));

                repositoryBean.writeChunk(chunkId, buffer, bytesRead);

                URI uri = UriBuilder.fromUri(ownURI).build();

                ChunkData chunkData = new ChunkData(chunkId, uri);
                md.addChunk(chunkData);
            }
        }

        md.setSize(totalBytes);
        md.setId(Hex.encodeHexString(messageDigest.digest()));

        LOG.debug("File id of seed file is " + md.getId() + "; Size=" + md.getSize() + "; Chunks="
                + md.getChunks().size());

        // Initiate to register at tracker
        LOG.debug("Queue up new file for registration.");
        Connection connection = connectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer messageProducer = session.createProducer(fileQueue);

        ObjectMessage message = session.createObjectMessage(md);

        messageProducer.send(message);

        connection.close();

        return md;
    }

    /**
     * Reads byte array fully.
     *
     * @param inputStream
     * @param buffer
     * @return
     * @throws IOException
     */
    private int readBlock(final InputStream inputStream, final byte[] buffer) throws IOException {
        int n = 0;
        while (n < buffer.length) {
            int count = inputStream.read(buffer, n, buffer.length - n);
            if (count == -1) {
                break;
            }

            n += count;
        }

        return n;
    }

    public void seedChunk(final InputStream inputStream, final String chunkId)
            throws IOException, GeneralSecurityException, JMSException {
        LOG.debug("Seeding chunk " + chunkId);
        Chunk chunk = chunkDAO.findByIdentifier(chunkId);

        if (chunk == null) {
            throw new FileNotFoundException(
                    "Chunk id " + chunkId + " not found. File already registered at registry?");
        }

        byte[] buf = new byte[chunk.getFileMeta().getChunkSize()];
        int bufferSize;
        try (InputStream in = inputStream) {
            bufferSize = readBlock(in, buf);
        } catch (IOException ex) {
            throw ex;
        }

        // Check SHA-1
        String sha1 = Hex.encodeHexString(DigestUtils.sha1(Arrays.copyOf(buf, bufferSize)));
        if (!chunk.getHash().equalsIgnoreCase(sha1)) {
            throw new GeneralSecurityException(
                    "Chunk SHA-1 validation failed (Expected " + chunk.getHash() + ", but is " + sha1 + ")");
        }

        repositoryBean.writeChunk(chunkId, buf, bufferSize);

        LOG.debug("Chunk id " + chunkId + " seed");

        // Initiate to register at tracker
        LOG.debug("Queue up new file for registration.");
        Connection connection = connectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer messageProducer = session.createProducer(chunkQueue);

        TextMessage message = session.createTextMessage(chunkId);
        messageProducer.send(message);
        connection.close();
    }
}