Java tutorial
/* * 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(); } }