Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package sam_testclient.services; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import sam_testclient.entities.Message; import sam_testclient.enums.EnumKindOfMessage; import sam_testclient.ui.main.MainUI; /** * * @author Jan */ public class FileSubmitService { // [Id, Amount] private static Map<Integer, Integer> partDistribution; // [Id, Limits] private static Map<Integer, Range> partRanges; // [Id, Bytes per Part] private static Map<Integer, byte[]> bytesPerPart; private static Map<String, WaitingService> serviceMap = new HashMap<String, WaitingService>(); /** * This method starts a {@link WaitingService}. * Additional to the start the {@link FileSubmitService} puts the * WaitingService to the {@link #serviceMap}. * * @param id ID of the Service (given by the other client) * @param fileName Name of File * @param parts Parts of the File. The {@link WaitingService} waits for the parts * @param timeOut Timeout for the waiting */ public static void startWaitingService(String id, String fileName, int parts, int timeOut) { WaitingService ws = new WaitingService(id, fileName, parts, timeOut); serviceMap.put(id, ws); ws.start(); } /** * This method deletes a specific WaitingService by passed ID * @param id */ private static synchronized void deleteWaitingService(String id) { System.out.println("Service with ID: " + id + " is deleted..."); serviceMap.remove(id); } /** * The method manages if a incoming part can be added to the passed serviceID. * * @param serviceID * @param m * @return true, if the passed message is added. False, if the service * does not exist. */ public static synchronized boolean addPartToService(String serviceID, Message m) { if (!serviceMap.containsKey(serviceID)) { System.out.println("No Service with this ID started. Message ignored."); return false; } else { WaitingService ws = serviceMap.get(serviceID); System.out.println("try to add..."); ws.tryToAddMessage(m); return true; } } /** * This method returns the List of byte- Arrays of the file which is aimed * by the passed path and the parts. * @param path of the file * @param parts of the file are coming back * @return List of byte[]- parts. */ public static List<byte[]> getPartsOfFile(String path, int parts) { List<byte[]> byteList = new ArrayList<>(); partDistribution = new HashMap<>(); partRanges = new HashMap<>(); bytesPerPart = new HashMap<>(); File file = new File(path); byte[] globalByteList = null; try { globalByteList = IOUtils.toByteArray(new FileInputStream(file)); } catch (FileNotFoundException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } System.out.println(globalByteList.length); System.out.println(globalByteList.length / parts); createDistribution(globalByteList.length, parts); // cutting int globalCounter = 0; for (int i = 0; i < partRanges.size(); i++) { Range a = partRanges.get(i); System.out.println(a.toString()); byte[] partByteArray; int byteCounter = 0; partByteArray = new byte[a.getSize()]; while (byteCounter != partByteArray.length) { partByteArray[byteCounter] = globalByteList[globalCounter]; byteCounter++; globalCounter++; } System.out.println(byteCounter); System.out.println(partByteArray.length); byteList.add(partByteArray); } System.out.println("TOTAL_" + countBytes(byteList)); return byteList; } /** * This method collects and combines the parts of byte-Arrays and * creates a new file at the passed path. * * @param byteList * @param path */ public static void createFile(List<byte[]> byteList, String path) { int globalSize = 0; for (byte[] bytes : byteList) { globalSize += bytes.length; } System.out.println(globalSize); byte[] newFile = new byte[globalSize]; int globalcounter = 0; for (byte[] bytes : byteList) { for (int i = 0; i < bytes.length; i++) { newFile[globalcounter] = bytes[i]; globalcounter++; } } FileOutputStream fos = null; try { fos = new FileOutputStream(path); } catch (FileNotFoundException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } try { fos.write(newFile); } catch (IOException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } try { fos.close(); } catch (IOException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } } protected static byte[] getBytesFromMessage(Message m) { String[] array = m.getContent().split(","); String[] array2 = new String[array.length]; for (int i = 0; i < array.length; i++) { array2[i] = array[i].replaceAll(" |\\[|\\]", ""); } List<byte[]> resultList = new ArrayList<>(); int[] intBuffer = new int[array2.length]; for (int i = 0; i < array2.length; i++) { intBuffer[i] = Integer.decode(array2[i]); } byte[] result = new byte[intBuffer.length]; for (int i = 0; i < intBuffer.length; i++) { result[i] = (byte) intBuffer[i]; } return result; } /** * This method creates a List of Messages which contains the byte-array of the file and the * meta- information of the message. * * @param ownID * @param receiverID * @param filePath * @param fileName * @param amountParts * @param serviceID * @return List of Messages for sending */ public static List<Message> createFileMessages(int ownID, int receiverID, String filePath, String fileName, int amountParts, String serviceID) { List<byte[]> byteList = getPartsOfFile(filePath, amountParts); int counter = 0; List<Message> partList = new ArrayList<>(amountParts); for (byte[] b : byteList) { Message m = new Message(ownID, receiverID, EnumKindOfMessage.FILEPART, Arrays.toString(b), createCustomInformation(counter, fileName, b.length, serviceID)); partList.add(m); counter++; } return partList; } /** * This method creates the Meta- Information for the creation of messages. * @param partID * @param fileName * @param lenOfPart * @param SID * @return Meta- information */ private static String createCustomInformation(int partID, String fileName, int lenOfPart, String SID) { return partID + " " + fileName + " " + lenOfPart + " " + SID; } private static void createDistribution(int globalSize, int parts) { int modulo = globalSize % parts; int amountPerPart = globalSize / parts; int step = amountPerPart; int rest = modulo + step; System.out.println("% = " + modulo); System.out.println("amPP = " + amountPerPart); System.out.println("step = " + step); System.out.println("parts = " + parts); System.out.println("glSize = " + globalSize); int adjustment = parts - 1; // Calculate the Distribution for (int i = 0; i < parts; i++) { if (i == 0) { partDistribution.put(i, step); } else { if (i + 1 == parts) { partDistribution.put(i, step * (i) + rest); } else { partDistribution.put(i, step * (i + 1)); } } } System.out.println(partDistribution.toString()); int range = 0; for (int i = 0; i < parts; i++) { if (i == 0) { range = partDistribution.get(i); partRanges.put(i, new Range(i, range)); } else { range = partRanges.get(i - 1).upperLimit; if (i + 1 != parts) { partRanges.put(i, new Range(range + 1, partDistribution.get(i))); } else { partRanges.put(i, new Range(range + 1, range + rest + adjustment)); } } } System.out.println("Distribution calculated:"); System.out.println("Pattern: [PartID=Range[Start to End]"); System.out.println(partRanges.toString()); } private static int countBytes(List<byte[]> bytes) { int result = 0; for (byte[] b : bytes) { result += b.length; } return result; } /** * Protected inner class for the calculation of the distribution. * */ protected static class Range { private int upperLimit; private int bottomLimit; public Range(int bottomLimit, int upperLimit) { this.upperLimit = upperLimit; this.bottomLimit = bottomLimit; } public int getUpperLimit() { return upperLimit; } public void setUpperLimit(int upperLimit) { this.upperLimit = upperLimit; } public int getBottomLimit() { return bottomLimit; } public void setBottomLimit(int bottomLimit) { this.bottomLimit = bottomLimit; } public int getSize() { return (upperLimit - bottomLimit); } @Override public String toString() { return "[" + this.bottomLimit + " to " + this.upperLimit + " | " + this.getSize() + "]"; } } /** * WaitingService of the clients. * The Service is started with a specific ID and waits for incoming Data * during a defined time. * After all Parts are collected the service creates the file, * else the service stops. */ protected static class WaitingService extends Thread { private String name; private int parts; private boolean live = true; private boolean success = false; private String connectionID; private Message message; private List<Integer> receivedParts; private int nameBuffer; private List<byte[]> byteList = new ArrayList<>(); private byte[] result; private long startTime; private long endTime; private synchronized void tryToAddMessage(Message m) { this.message = m; String[] meta = new String[3]; meta = m.getOthers().split(" "); String partID = meta[0]; String name = meta[1]; String len = meta[2]; String id = meta[3]; if (!receivedParts.contains(Integer.decode(partID))) { System.out.println("-- Service does not contain the PartId: " + partID + ", current: " + receivedParts.toString() + ". Is added."); receivedParts.add(Integer.decode(partID)); byteList.add(FileSubmitService.getBytesFromMessage(m)); MainUI.filePartSubmitted(); System.out.println(receivedParts.size() + " " + parts); if (receivedParts.size() == parts) { doFinish(); } } } protected String getNameOfFile() { return this.name; } private long currentTime; private long timeout; private boolean isTimeoutOccured() { currentTime = System.currentTimeMillis(); System.out.println(currentTime + " --- " + endTime + " ---- " + startTime); return (currentTime > endTime); } public WaitingService(String connectionID, String name, int parts, int timeout) { this.name = name; this.parts = parts; this.timeout = (long) timeout; this.connectionID = connectionID; this.receivedParts = new ArrayList<>(); this.byteList = new ArrayList<>(); this.startTime = System.currentTimeMillis(); this.endTime = startTime + timeout; } private void doFinish() { FileSubmitService.createFile(byteList, name); FileSubmitService.deleteWaitingService(connectionID); MainUI.filePartSubmitEnd(); this.live = false; } private void kill() { System.out.println("Error: Timeout occured"); MainUI.filePartSubmitEnd(); this.live = false; } @Override public void run() { System.out.println("Waiting for incoming data..."); while (live) { if (isTimeoutOccured()) { FileSubmitService.deleteWaitingService(connectionID); kill(); } try { sleep(1000); } catch (InterruptedException ex) { Logger.getLogger(FileSubmitService.class.getName()).log(Level.SEVERE, null, ex); } } System.out.println("WaitingService is died."); } } }