package es.um.redes.nanoFiles.udp.message; import es.um.redes.nanoFiles.application.Directory; import es.um.redes.nanoFiles.application.NanoFiles; import es.um.redes.nanoFiles.util.FileInfo; /** * Clase que modela los mensajes del protocolo de comunicación entre pares para * implementar el explorador de ficheros remoto (servidor de ficheros). Estos * mensajes son intercambiados entre las clases DirectoryServer y * DirectoryConnector, y se codifican como texto en formato "campo:valor". * * @author rtitos * */ public class DirMessage { public static final int PACKET_MAX_SIZE = 65507; // 65535 - 8 (UDP header) - 20 (IP header) private static final char DELIMITER = ':'; // Define el delimitador private static final char END_LINE = '\n'; // Define el carácter de fin de línea /** * Nombre del campo que define el tipo de mensaje (primera línea) */ private static final String FIELDNAME_OPERATION = "operation"; /* * TODO: (Boletín MensajesASCII) Definir de manera simbólica los nombres de * todos los campos que pueden aparecer en los mensajes de este protocolo * (formato campo:valor) */ private static final String FIELDNAME_FILENAME = "filename"; private static final String FIELDNAME_FILESIZE = "size"; private static final String FIELDNAME_FILEHASH = "hash"; private static final String FIELDNAME_FILEPATH = "path"; private static final String FIELDNAME_PROTOCOL = "protocol"; /** * Tipo del mensaje, de entre los tipos definidos en PeerMessageOps. */ private String operation = DirMessageOps.OPERATION_INVALID; /** * Identificador de protocolo usado, para comprobar compatibilidad del directorio. */ private String protocolId; private FileInfo[] fileList; /* * TODO: (Boletín MensajesASCII) Crear un atributo correspondiente a cada uno de * los campos de los diferentes mensajes de este protocolo. */ public DirMessage(String op) { operation = op; } public DirMessage(String op, String nick, String ip, int puerto) { this(op); } /* * TODO: (Boletín MensajesASCII) Crear diferentes constructores adecuados para * construir mensajes de diferentes tipos con sus correspondientes argumentos * (campos del mensaje) */ public String getOperation() { return operation; } /* * TODO: (Boletín MensajesASCII) Crear métodos getter y setter para obtener los * valores de los atributos de un mensaje. Se aconseja incluir código que * compruebe que no se modifica/obtiene el valor de un campo (atributo) que no * esté definido para el tipo de mensaje dado por "operation". */ public void setProtocolID(String protocolIdent) { if (!operation.equals(DirMessageOps.OPERATION_PING)) { throw new RuntimeException( "DirMessage: setProtocolId called for message of unexpected type (" + operation + ")"); } protocolId = protocolIdent; } public String getProtocolId() { return protocolId; } public FileInfo[] getFileList () { return fileList; } public void setFileList(FileInfo f) { if (!operation.equals(DirMessageOps.OPERATION_REQUEST_DIRFILES)) { throw new RuntimeException ( "DirMessage: setFileList called for message of type " + operation ); } } /** * Método que convierte un mensaje codificado como una cadena de caracteres, a * un objeto de la clase PeerMessage, en el cual los atributos correspondientes * han sido establecidos con el valor de los campos del mensaje. * * @param message El mensaje recibido por el socket, como cadena de caracteres * @return Un objeto PeerMessage que modela el mensaje recibido (tipo, valores, * etc.) */ public static DirMessage fromString(String message) { System.out.println(message); /* * TODO: (Boletín MensajesASCII) Usar un bucle para parsear el mensaje línea a * línea, extrayendo para cada línea el nombre del campo y el valor, usando el * delimitador DELIMITER, y guardarlo en variables locales. */ // System.out.println("DirMessage read from socket:"); // System.out.println(message); String[] lines = message.split(END_LINE + ""); // Local variables to save data during parsing DirMessage m = null; String filename = null; long filesize = 0; String filehash = null; String filepath = null; // de alguna forma tengo que hacer un array de FileInfo // ArrayList y de ahí a array? for (String line : lines) { int idx = line.indexOf(DELIMITER); // Posición del delimitador String fieldName = line.substring(0, idx).toLowerCase(); // minúsculas String value = line.substring(idx + 1).trim(); switch (fieldName) { case FIELDNAME_OPERATION: { assert (m == null); m = new DirMessage(value); break; } case FIELDNAME_PROTOCOL: { m.setProtocolID(value); break; } case FIELDNAME_FILENAME: { filename = value; break; } case FIELDNAME_FILESIZE: { filesize = Long.parseLong(value); break; } case FIELDNAME_FILEHASH: { filehash = value; FileInfo f = new FileInfo(filehash, filename, filesize, filepath); // fileList += f; // y esto que, muchas gracias iniesta } default: System.err.println("PANIC: DirMessage.fromString - message with unknown field name " + fieldName); System.err.println("Message was:\n" + message); System.exit(-1); } } return m; } /** * Método que devuelve una cadena de caracteres con la codificación del mensaje * según el formato campo:valor, a partir del tipo y los valores almacenados en * los atributos. * * @return La cadena de caracteres con el mensaje a enviar por el socket. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append(FIELDNAME_OPERATION + DELIMITER + operation + END_LINE); // Construimos el campo /* * TODO: (Boletín MensajesASCII) En función de la operación del mensaje, crear * una cadena la operación y concatenar el resto de campos necesarios usando los * valores de los atributos del objeto. */ switch (operation) { case DirMessageOps.OPERATION_PING: sb.append(FIELDNAME_PROTOCOL + DELIMITER + NanoFiles.PROTOCOL_ID + END_LINE); break; case DirMessageOps.OPERATION_DIRFILES: FileInfo[] filelist = FileInfo.loadFilesFromFolder(Directory.DEFAULT_DIRECTORY_FILES_PATH); sb.append(FIELDNAME_OPERATION + DELIMITER + operation + END_LINE); for (FileInfo f : filelist) { sb.append(FIELDNAME_FILENAME + DELIMITER + f.fileName + END_LINE); sb.append(FIELDNAME_FILESIZE + DELIMITER + f.fileSize + END_LINE); sb.append(FIELDNAME_FILEHASH + DELIMITER + f.fileHash + END_LINE); sb.append(FIELDNAME_FILEPATH + DELIMITER + f.filePath + END_LINE); } break; default: break; } sb.append(END_LINE); // Marcamos el final del mensaje return sb.toString(); } }