Como sobrescribir o añadir un nuevo protocolo a Java.net.URL y cambiar el cliente FTP
Si utilizas el java.net.URL y en algunos casos quieres añadir un nuevo protocolo o si quieres usar otra API para que maneje ciertos protocolos en este ejemplo se muestra como. En este ejemplo sobreescribo el protocolo FTP para que sea manejado por la librería FTP org.apache.commons.net.ftp.FTPClient de apache.
En el ejemplo se cubren las siguientes características.
- Cargar un FTP con con el java.net.URL
- Implementar un nuevo URLStreamHandlerFactory
- Cargar un archivo con el Apache org.apache.commons.net.ftp.FTPClient
- Sobrescribir o añadir un nuevo protocolo al java.net.URL
Ejemplo de Código 1
Este ejemplo muestra como cargar el mismo archivo dos veces. La primera vez lo maneja la API FTP por defecto y en el segundo el FTPClient de apache.
package net.custom.streamhandler.apacheftp; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URI; import java.net.URL; public class FTPClass { private static final String FTP_URL = "ftp://ftp.adobe.com/lbtest.txt"; public static void main(String[] args) { loadFTP(); URL.setURLStreamHandlerFactory(new ApacheURLStreamHandlerFactory()); loadFTP(); } private static void loadFTP(){ try { URI uri = new URI(FTP_URL); URL ftpFile = uri.toURL(); BufferedReader in = new BufferedReader(new InputStreamReader( ftpFile.openStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } catch (Exception e) { e.printStackTrace(); } } }
Cambia tu FTP_URL por la tuya. En este caso se usa el usuario anónimo para el ftp de adobe ftp://
user:
password@
host:
port/
path e.g. ftp://john:mypassword@mydomain.com:21/logs/mylog.log
Ejemplo de Código 2
Este ejemplo muestra como crear un URLStreamHanlderFactory personalizado, las clases implicadas y como se implemente. El CustomURLConnection extiende de URLConnection y usa Apache FTPClient para conectar al FTP.
package net.custom.streamhandler.apacheftp; import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPReply; public class ApacheURLStreamHandlerFactory implements URLStreamHandlerFactory { public URLStreamHandler createURLStreamHandler(String protocol) { //this will only override the chosen protocol if ( protocol.equalsIgnoreCase("ftp") ) return new CustomHandler(); else return null; } } class CustomHandler extends URLStreamHandler { protected URLConnection openConnection(URL url) throws IOException { return new CustomURLConnection(url); } } class CustomURLConnection extends URLConnection { int reply; FTPClient ftp = new FTPClient(); InputStream in; static int defaultPort = 21; static String defaultPath = "/"; CustomURLConnection ( URL url) throws IOException { super( url ); } synchronized public void connect() throws IOException { try { int port; if ((port = url.getPort()) == -1 ) port = defaultPort; ftp.connect(url.getHost(), port); String login = "anonymous"; String password = ""; if(url.getAuthority().indexOf(':')>-1 && url.getAuthority().indexOf('@')>-1){ String []auxArray = url.getAuthority().replaceAll("@", ":").split(":"); login = auxArray[0]; password = auxArray[1]; } ftp.login(login, password); reply = ftp.getReplyCode(); if (FTPReply.isPositiveCompletion(reply)) { System.out.println("*********Connected Apache Success*********"); } else { System.out.println("*********Connection Apache Failed*********"); ftp.disconnect(); } in = ftp.retrieveFileStream(url.getFile()); } catch (SocketException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } connected = true; } synchronized public InputStream getInputStream() throws IOException { if (!connected) connect(); return ( in ); } }
Importa las librerías.
En este ejemplo uso el Apache Commons 2.0. Vete a la página de apache y descarga las librerías si lo necesitas. Con maven son:
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>2.0</version>
</dependency>
Ejecuta el código
Deberías ver un *********Connected Apache Success********* entre las 2 conexiones. Esto quiere decir en la segunda llamada al ftp se esta usando el FTPClient de Apache.
Para crear tu protocolo personalizado
Cambia los ejemplos 1 y 2 por...
public class FTPClass { private static final String FTP_URL = "ftpapache://ftp.adobe.com/lbtest.txt"; public static void main(String[] args) { URL.setURLStreamHandlerFactory(new ApacheURLStreamHandlerFactory()); loadFTP(); }
....
public class ApacheURLStreamHandlerFactory implements URLStreamHandlerFactory { public URLStreamHandler createURLStreamHandler(String protocol) { //this will only override the chosen protocol if ( protocol.equalsIgnoreCase("ftpapache") ) return new CustomHandler(); else return null; }
Ahora cada vez que intentas cargar una url con tu "protocolo" ftpapache se utilizará el FTPClient de apache.