Em vários projetos, é necessário integração com legado (sistema antigo que o cliente não quer migrar). E em alguns casos específicos essa integração pode ser um pouco mais complicada do que leitura de arquivos textos, troca de informações em base e afins. Nesse post eu irei explicar como criar um Web Service que faz a autenticação em um servidor Telnet e executa comandos nesse servidor. Essa é mais uma maneira (não tão convencional) de se realizar integração com legado.
Como client de Telnet, iremos utilizar a biblioteca Commons Net da Apache. Faça o download nesse site, descompacte-a e localize o jar da biblioteca. Crie um projeto e adicione as duas libs (jars) no classpath (build path no Eclipse e libraries no JDeveloper e Netbeans). Crie um WebService (JAX-WS) conforme o exemplo abaixo:
package br.com.thiagovespa.ws.telnet; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.SocketException; import javax.jws.*; import org.apache.commons.net.telnet.TelnetClient; @WebService public class TelnetService { private final static String HOST = "192.168.1.100"; private final static String VALID_CHARS = " :-.,!?+=_'\"|\\/;@#$%&*()[]{}"; private final static int TIMEOUT = 150000; @WebMethod public String executeCommand(String user, String password, String delimiter, String command, boolean showLogin) throws SocketException, IOException { if (hasSpecialChar(delimiter)) { return "Não utilize caracteres especiais como delimitador. Caracteres válidos: letras, espaço e números e " + VALID_CHARS; } StringBuilder retorno = new StringBuilder(); TelnetClient telnet = new TelnetClient(); telnet.setDefaultTimeout(TIMEOUT); telnet.connect(HOST); if (!telnet.isConnected()) { return "ERRO: Não foi possível conectar na telnet"; } telnet.setSoTimeout(TIMEOUT); InputStream in = telnet.getInputStream(); PrintStream out = new PrintStream(telnet.getOutputStream()); doLogin(user, password, (showLogin ? retorno : null), in, out); write(command, out); readValues(delimiter, in, retorno); return retorno.toString(); } private void doLogin(String user, String password, StringBuilder retorno, InputStream in, PrintStream out) { readValues("login: ", in, retorno); if (retorno != null) { retorno.append("\n"); } write(user, out); readValues("Password:", in, retorno); if (retorno != null) { retorno.append("\n"); } write(password, out); readValues(">", in, retorno); } private void readValues(String endString, InputStream in, StringBuilder retorno) { try { char lastChar = endString.charAt(endString.length() - 1); StringBuilder sb = new StringBuilder(); char ch = (char) in.read(); while (true) { sb.append(ch); if (ch == lastChar) { if (sb.toString().endsWith(endString)) { if (retorno != null) { retorno.append(removeSpecialChars(sb.toString())); } return; } } ch = (char) in.read(); } } catch (Exception e) { e.printStackTrace(); if (retorno != null) { retorno.append("\nERRO: ").append(e.getMessage()).toString(); } } } private void write(String value, PrintStream out) { try { out.println(value + "\n"); out.flush(); } catch (Exception e) { e.printStackTrace(); } } private boolean isSpecialChar(char ch) { if (Character.isLetterOrDigit(ch) || ch == '\n' || VALID_CHARS.indexOf(ch) >= 0) return false; return true; } private boolean hasSpecialChar(String str) { for (char ch : str.toCharArray()) { if (isSpecialChar(ch)) return true; } return false; } private String removeSpecialChars(String str) { StringBuilder sb = new StringBuilder(); for (char ch : str.toCharArray()) { if (!isSpecialChar(ch)) { sb.append(ch); } } return sb.toString(); } }
O serviço recebe como parâmetro cinco informações: o usuário, senha, um delimitador de comando, o comando a ser executado e um booleano para informar se é pra retornar todos os dados ou somente as informações após fazer o login. A conexão com Telnet é feita na linha 22 e 24. Após à conexão efetuada, informamos o usuário e a senha utilizando o método doLogin(). Na linha 48 utilizamos o caracter ">" como delimitador de fim do comando de login. Você pode substituí-lo pelo correspondente no seu server de Telnet.
Na linha 61 e 17 evitamos o uso de caracteres especiais para não termos problemas com o nosso cliente de WebService. Você pode utilizar outro tratamento, por exemplo: utilizar o CDATA ou realizar escape dos caracteres.
Agora é só executar o serviço passando os parâmetros adequados. O importante é passar corretamente o delimitador. Esse campo indica quando terminou a execução de um comando e quando o serviço pode retornar a resposta. Você pode inclusive executar os comandos com parâmetros e utilizar o operador && para executar mais de um comando. Abaixo temos o exemplo de uma requisição:
usuario senha FIM <![CDATA[ ps && comandoQueImprimiFim ]]> false
Com essa execução, a resposta seria:
ps && comandoQueImprimiFim PID CLS PRI TTY TIME COMD 6626 TS 59 pts134 0:00 ps 5867 TS 70 pts134 0:00 bash FIM
Aí é só utilizar essa resposta em qualquer outro sistema que posso se comunicar via WebService SOAP.
Saudações a partir de Curitiba! Sou bastante apaixonado por
esta área, então eu decidi procurar seu blog no meu iphone durante a pausa para o almoço.
Eu amei a quantidade de informação presente aqui e não pude esperar para dar uma olhada quando eu cheguei em casa.
Também fiquei impressionado como seu website carrega
rápido no meu telefone. Não estou nem usando WiFi, apenas 3G.
De qualquer maneira, muito bom site!
Exelente conteudo