Quale sarebbe il codice migliore e più pulito tra le seguenti opzioni? Il codice invia fondamentalmente un file tramite un socket utilizzando un OutputStream che lo crittografa. Il codice non sembra così semplice quando viene letto, ma non ha bisogno di essere compreso a livello tecnico, non è questo il punto della domanda. I commenti dicono cosa sta succedendo a livello generale.
Ovviamente non cerco una risposta obiettiva dato che il design di solito è molto soggettivo e dipende da molti fattori. Voglio solo opinioni che creino feedback costruttivi attorno al problema.
Opzione 1: l'unico metodo. Considero questo WAY più pulito e più facile da leggere, ma ovviamente, frena molti principi OO come la coesione e la modularità.
public class FileSender {
public static final String KEY = "00000000000000000000000000000000";
public static final String ALGORITHM = "AES";
public static final String FILE = "C:\Users\Andres\Desktop\file.txt";
public static final String HASH_ALG = "MD5";
public static void main(String [] args) throws Exception {
CipherOutputStream cipherOut = null;
FileInputStream fileReader = null;
Socket client = null;
FileInputStream fis = null;
try {
System.out.println("Running client ...");
//Connects to serverSocket.
client = new Socket("localhost", 8081);
//Creates MD5 Hash.
MessageDigest md = MessageDigest.getInstance(HASH_ALG);
File file = new File(FILE);
fis = new FileInputStream(file);
byte[] byteArray = new byte[1024];
int bytesCount = 0;
while ((bytesCount = fis.read(byteArray)) != -1)
md.update(byteArray, 0, bytesCount);
byte[] hash = md.digest();
String checksum = String.format("%032x",new BigInteger(1, hash));
fis.close();
//Creates "secret" key and inits the cipher.
SecretKeySpec keySpec = new SecretKeySpec(hex2byte(KEY), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM + "/ECB/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
cipherOut = new CipherOutputStream(client.getOutputStream(), cipher);
//Sends the file.
byte[] fileBuffer = new byte[1024];
fileReader = new FileInputStream(FILE);
int len;
while ((len = fileReader.read(fileBuffer)) != -1)
cipherOut.write(fileBuffer, 0, len);
System.out.println("Ended client .... ");
}catch(IOException e) {
e.printStackTrace();
}finally{
if(fileReader != null) fileReader.close();
if(cipherOut != null) cipherOut.close();
if(client != null) client.close();
if(fis != null) fis.close();
}
}
public static byte[] hex2byte(String s) {
return DatatypeConverter.parseHexBinary(s);
}
}
Opzione 2: il modo modulare, dividendo il codice. Questo è ovviamente il modo corretto nella maggior parte dei casi perché si preoccupa dei principi OO, ma il codice è più pulito?
public class FileSender {
public static final String KEY = "00000000000000000000000000000000";
public static final String ALGORITHM = "AES";
public static final String FILE = "C:\Users\Andres\Desktop\file.txt";
public static final String HASH_ALG = "MD5";
private String fileName;
private String serverMachine;
private int serverPort;
public FileSender(String fileName, String serverMachine, int serverPort){
this.fileName = fileName;
this.serverMachine = serverMachine;
this.serverPort = serverPort;
}
//High level method that uses the class details.
public void sendFile(){
CipherOutputStream cipherOut = null;
Socket client = null;
String checkSum;
try {
System.out.println("Running client ...");
client = connectToServer();
checkSum = getHashChecksum();
cipherOut = initCipherStream(client);
transferData(cipherOut);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
}
}
//Creates MD5 checksum
private String getHashChecksum() {
FileInputStream fis = null;
try {
MessageDigest md = MessageDigest.getInstance(HASH_ALG);
File file = new File(this.fileName);
fis = new FileInputStream(file);
byte[] byteArray = new byte[1024];
int bytesCount = 0;
while ((bytesCount = fis.read(byteArray)) >= 0)
md.update(byteArray, 0, bytesCount);
byte[] hash = md.digest();
fis.close();
return String.format("%032x",new BigInteger(1, hash));
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error in checksum");
} finally {
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(
"Error in checksum. Provided file can't be closed.");
}
}
}
//Connects client to server.
private Socket connectToServer() throws Exception{
try {
Socket client = new Socket(this.serverMachine, this.serverPort);
return client;
} catch (IOException e) {
throw new Exception("Server can't be reached");
}
}
//Creates output stream to send file.
private CipherOutputStream initCipherStream(Socket client) {
//Crea la llave.
SecretKeySpec keySpec = new SecretKeySpec(hex2byte(KEY), ALGORITHM);
Cipher cipher;
try {
cipher = Cipher.getInstance(ALGORITHM + "/ECB/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
return new CipherOutputStream(client.getOutputStream(), cipher);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error in cipher stream initialization.");
}
}
//Sends file
private void transferData(CipherOutputStream cipherOut) {
FileInputStream fileReader = null;
try {
//Missing: send MD5 hash. TODO
fileReader = new FileInputStream(this.fileName);
byte[] fileBuffer = new byte[1024];
int len;
while ((len = fileReader.read(fileBuffer)) != -1)
cipherOut.write(fileBuffer, 0, len);
} catch (Exception e) {
throw new RuntimeException("File " + this.fileName + " not found");
} finally{
try {
if(fileReader != null) fileReader.close();
} catch (IOException e) {
throw new RuntimeException("Socket stream can't be closed");
}
}
}
private byte[] hex2byte(String s) {
return DatatypeConverter.parseHexBinary(s);
}
public static void main(String [] args) throws Exception {
FileSender fileSender = new FileSender(FILE, "localhost", 8081);
fileSender.sendFile();
}
}
Cosa ne pensi di entrambi gli approcci? Consiglieresti un'altra strategia per creare un codice migliore e più leggibile?