Enviar um objeto da máquina do cliente para o servidor, tem como?

Olá pessoal.

Estou ferrado hehe, não faço a minima idéia de como fazer isso, acho que nem vou conseguir explicar. Mas vou tentar. A minha aplicação faz o ponto eletrônico da pessoa. E pra fazer a validação, é preciso que a digital do cara que acabou de colocar, seja comparada com todas que estão cadastradas no banco de dados, até que ache uma que combine. Quando ele encontrar, para o laço e faz o restante do processo. Isso funciona perfeitamente, mas se torna lento por 2 fatores. Primeiro que a conexão do cliente tem que ser boa para resultar numa consulta rápida e o servidor precisa ser especialmente para esse tipo de aplicação. E nenhuma dessas condições estão a meu favor hehe. Então estavamos discutindo sobre o assunto e vimos que a melhor solução seria, enviar esse objeto para o servidor e com um JSP lá no servidor, fazer a mesma coisa que faz localmente.

A pergunta é, como eu faço pra enviar um objeto para o servidor?

Agradeço a ajuda.

Depende; como você disse, várias coisas estão contra você.
No seu caso, mandar um objeto serializado para o servidor parece uma boa idéia, mas não é adequada na prática porque as versões das classes no software do cliente e do servidor têm de ser mantidas sempre sincronizadas, o que pode ser complicado por exemplo se as versões do Java no cliente e no servidor são diferentes por algum motivo.
Você pode fazer o objeto implementar Externalizable e criar o seu próprio formato de serialização para evitar alguns problemas relativos ao uso de classes que têm versões e representações diferentes de uma versão para outra do Java. Isso parece um pouco melhor.
Ou então você pode separar os dados importantes do seu objeto, e usar um formato padrão (como XML e Web Services usando REST, como o pessoal costuma fazer). É que não sei qual é o tamanho do seu objeto; dá a impressão que você precisa mandar cerca de 10 KBytes de dados, o que não é nenhum problema hoje em dia.
No seu caso (em que você tem de ficar checando uma digital contra várias digitais diferentes no banco de dados) isso realmente deve ser deixado a cargo do servidor, porque acesso remoto a banco de dados simplesmente não funciona bem.

Olá thingol, opbrigado pela rsposta. Então, esse objeto é um template que é gerado pelo leitor biométrico, o tamanho dele fica entre 90Kb e 110Kb. Chegamos a conclusão que se existem 500 funcionários, isso ia gerar uma banda relativamente alta.

Bom, o jeito então é enviar o objeto serializado? Por enquanto as versões do Java são iguais. Vou pesquisar sobre isso.

Obrigado.

Só uma pequena dúvida que me surgiu. Eu teria que usar RMI para essa situação?

Quanto a banda, nada que um bom java.util.zip não faça por você.
Esses dados podem ser comprimidos antes de serem mandados?
Não recomendaria RMI, mas o que o pessoal lhe sugeriu (um servlet). É que é mais fácil você fazer um servlet funcionar em ambiente Extranet e Internet (você sabe, aplicações costumam ser vítimas de seu próprio sucesso, então não pense que só vai funcionar dentro da sua empresa… seu chefe vai querer usar e demonstrar isso com o servidor na empresa e um notebook na Internet, fora da empresa) que RMI (que mal e mal funciona em ambiente Intranet devido à necessidade de abrir um monte de portas no firewall).

Também não recomendo objetos serializados. Digamos que você queira usar a JRE que normalmente vêm nos computadores hoje em dia (JRE 6.0). Ela é atualizada automaticamente, e duvido que o servidor fique atualizando automaticamente na mesma velocidade que os clientes (que podem estar atualizados automaticamente ou não). A menos que você customize a serialização, talvez seja melhor usar algo com Web Services com REST ou coisa parecida, e para mandar os dados você precisa provavelmente ver se os templates podem ser bem comprimidos pelo algoritmo do java.util.zip. (Pegue um template, copie-o para um arquivo, e monte um arquivo .zip com o seu software de compressão preferido, como o zip.exe, jar.exe, PKZIP ou WinZip (formato Zip é claro). Veja se a compressão é boa para você.

Sendo a imagem média de 110kb, daria por volta de uns 55 megas diários, tendo na média de 500 funcionários como você abordou.

Acredito que o que thigol falou é mais sensato, com compactação esses dados devem diminuir consideravelmente, provavelmente você irá ocupagar a média de 30%-40% menos de banda do que o previsto.

Serializar ocorre o problema que thigol mostrou, você precisar enviar via UDP ou outro protocolo?

thigol, nesse caso UDP não daria “consistência” certa nos dados, não?

Eu preciso enviar por UDP mesmo!!!

UDP só é legal se você tiver dados que não ultrapassem muito 1 KB (como seus dados têm cerca de 100 KB…)
Mais que isso você precisa montar um protocolo (incluindo retransmissão de dados e outras coisas complexas) que não valem a pena implementar você mesmo.
Fora isso normalmente firewalls costumam bloquear a maior parte das portas UDP.

Hum, a reunião acabou e decidi que vou usar um servlet e receber o objeto, e depois retornar uma classe com os resultados!!! Bem mais pratico hehe, só falta saber como fazer hehe.

Obrigado pela ajuda.

Abraços.

Dica para serializar corretamente seu objeto:
a) Se você acha que pode ter problemas de versão de objetos, então implemente a interface Externalizable.
b) Em vez de pegar o OutputStream do objeto URLConnection (que você obtém se fizer um POST) e já encapsular com um ObjectOutputStream, é melhor fazer o seguinte: crie um ByteArrayOutputStream, encapsule-o em um ObjectOutputStream, e então escreva o objeto e feche o stream. Então você terá um array de bytes, que poderá escrever sem problemas no OutputStream do URLConnection (é adequado, para evitar problemas, encapsular o OutputStream do URLConnection em um DataOutputStream, e mandar o tamanho do array de bytes, usando writeInt, antes do próprio array de bytes.)
c) No lado do servidor, faça o processo inverso. (DataInputStream, ByteArrayInputStream, ObjectInputStream).

[quote=thingol]Dica para serializar corretamente seu objeto:
a) Se você acha que pode ter problemas de versão de objetos, então implemente a interface Externalizable.
b) Em vez de pegar o OutputStream do objeto URLConnection (que você obtém se fizer um POST) e já encapsular com um ObjectOutputStream, é melhor fazer o seguinte: crie um ByteArrayOutputStream, encapsule-o em um ObjectOutputStream, e então escreva o objeto e feche o stream. Então você terá um array de bytes, que poderá escrever sem problemas no OutputStream do URLConnection (é adequado, para evitar problemas, encapsular o OutputStream do URLConnection em um DataOutputStream, e mandar o tamanho do array de bytes, usando writeInt, antes do próprio array de bytes.)
c) No lado do servidor, faça o processo inverso. (DataInputStream, ByteArrayInputStream, ObjectInputStream).
[/quote]

Nossa, valeu cara!!! Já estou começando a por a mão na massa.

Abraços.

Os problema com versões de objetos que vocês disseram, por um acaso são esses?

[quote]java.io.StreamCorruptedException: invalid stream header: 3C68746D
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:783)
RETORNOU OUTRA COISA null
at java.io.ObjectInputStream.(ObjectInputStream.java:280)
at classes.ObjAuth.validaPeao(ObjAuth.java:67)
at classes.ObjAuth.main(ObjAuth.java:23)[/quote]

Olá Amigo,
estou acompanhando este post, e talvez possa te ajudar. Eu já realizei uma implementacao para um problema parecido com o seu. Eu tinha um applet que integrava-se a biblioteca Finger [da empresa Griaule] (biblioteca de captura e reconhecimento de digital). Esse applet capturava a digital e enviava o template para uma Servlet processar. O trecho de codigo abaixo mostra como realizei isso no applet e no server.

applet:

			URL url = new URL(urlBusca);  
			URLConnection conn = url.openConnection();  
	
			//Prepare for both input and output  
			conn.setDoInput(true);  
			conn.setDoOutput(true);  
			  
			//Turn off caching  
			conn.setUseCaches(false);  
			  
			//Set the content type to be java-internal/classname  
			conn.setRequestProperty("Content-type", "application/x-java-serialized-object");  
			  
			 
			ObjectOutputStream out = new ObjectOutputStream(conn.getOutputStream());  
			
			//emvia template
			out.writeObject(template);

			out.flush();  
			out.close();  

			//recupera o retorno vindo do server
			InputStream ins = conn.getInputStream();  
			ObjectInputStream objin = new ObjectInputStream(ins);  
			
			//le a resposta do server
			cidadaoId = (Integer)objin.readObject();  

No server, utilizo uma Servlet que faz o inverso:

servlet.doPost

			ObjectInputStream objin = new ObjectInputStream(request.getInputStream());  
			
			//recupera template
			Template template = (Template) objin.readObject();
			
			//AQUI VC TEM O TEMPLATE... basta utilizar a biblioteca para valida-lo
			
			ObjectOutputStream out = new ObjectOutputStream(response.getOutputStream());  
			out.writeObject(cidadaoId);  
			out.flush();  
			out.close();

Nao tive problemas com versao de JRE (talvez por sorte, nao sei…), nem tive problemas por criar um ObjectOutputStream diretamente do OutputStream vindo do URLConnection (idem…rs).

Mas acho que as dicas do thingol sao uteis e podem ser adaptadas facilmente ao codigo que estou postando.

Se vc nao estiver utilizando a biblioteca da Griaule, entao talvez tenha que realizar outras adaptaçoes… Caso nao esteja utilizando, vc poderia me dizer qual biblioteca utiliza? Eu só conheco a Finger, e gostaria de conhecer outras…

Espero ter ajudado!

[quote=Insônia]Olá Amigo,
estou acompanhando este post, e talvez possa te ajudar. Eu já realizei uma implementacao para um problema parecido com o seu. Eu tinha um applet que integrava-se a biblioteca Finger [da empresa Griaule] (biblioteca de captura e reconhecimento de digital). Esse applet capturava a digital e enviava o template para uma Servlet processar. O trecho de codigo abaixo mostra como realizei isso no applet e no server.

applet:

			URL url = new URL(urlBusca);  
			URLConnection conn = url.openConnection();  
	
			//Prepare for both input and output  
			conn.setDoInput(true);  
			conn.setDoOutput(true);  
			  
			//Turn off caching  
			conn.setUseCaches(false);  
			  
			//Set the content type to be java-internal/classname  
			conn.setRequestProperty("Content-type", "application/x-java-serialized-object");  
			  
			 
			ObjectOutputStream out = new ObjectOutputStream(conn.getOutputStream());  
			
			//emvia template
			out.writeObject(template);

			out.flush();  
			out.close();  

			//recupera o retorno vindo do server
			InputStream ins = conn.getInputStream();  
			ObjectInputStream objin = new ObjectInputStream(ins);  
			
			//le a resposta do server
			cidadaoId = (Integer)objin.readObject();  

No server, utilizo uma Servlet que faz o inverso:

servlet.doPost

			ObjectInputStream objin = new ObjectInputStream(request.getInputStream());  
			
			//recupera template
			Template template = (Template) objin.readObject();
			
			//AQUI VC TEM O TEMPLATE... basta utilizar a biblioteca para valida-lo
			
			ObjectOutputStream out = new ObjectOutputStream(response.getOutputStream());  
			out.writeObject(cidadaoId);  
			out.flush();  
			out.close();

Nao tive problemas com versao de JRE (talvez por sorte, nao sei…), nem tive problemas por criar um ObjectOutputStream diretamente do OutputStream vindo do URLConnection (idem…rs).

Mas acho que as dicas do thingol sao uteis e podem ser adaptadas facilmente ao codigo que estou postando.

Se vc nao estiver utilizando a biblioteca da Griaule, entao talvez tenha que realizar outras adaptaçoes… Caso nao esteja utilizando, vc poderia me dizer qual biblioteca utiliza? Eu só conheco a Finger, e gostaria de conhecer outras…

Espero ter ajudado![/quote]

Olá Insonia,

Exatamente, eu uso a biblioteca da Griaule, Eu tive que deixar de usar Applet porque eu tive muito problema, então acabei fazendo uma aplicação desktop e como eu disse antes, está dando mais problemas também hehe. Vou testar o seu código mas parece que está igual o meu. Eu apenas fiz um de teste retornando uma lista que é modificada pelo servlet e retorna pra aplicação com essa alteração. Veja:

Swing:

package classes;

import java.io.*;
import java.net.*;
import java.util.*;

public class ObjAuth {

	public static void main(String[] args) {
            String urlName = "http://localhost:8084/TesteServlet/";
            Object inObj = null; // objeto enviado da entrada
            Object outObj = null; // objecto que sera enviado a saida

            List<String> lista = new ArrayList<String>();

            lista.add("XIKO BRASILEIRO");
            lista.add("MANOEL SERIAL KILLER");
            lista.add("POG MASTER");
            lista.add("ALGUMA COISA");
            lista.add("LAUDIVINO VIEIRA");
            inObj = lista;

            outObj = validaPeao(inObj, urlName); // faz a coisa 

            if (outObj instanceof List) {
                List retornoLista = (List)outObj;
                System.out.println("====================");
                System.out.println(" RETORNOU UMA LISTA");
                System.out.println("====================\n");

                for(Object obj: retornoLista) {
                    System.out.println(" " + obj);
                }
            } else {
                System.out.println("RETORNOU OUTRA COISA "+ outObj);
            }
	}
	
	
	public static Object validaPeao(Object inObj, String urlName) {	
            Object outObj = null; // objecto que sera enviado a saida		
            
            try {
                URL url = new URL(urlName);
                HttpURLConnection connection = (HttpURLConnection)url.openConnection();		
                connection.setDoOutput(true);
                
                ObjectOutputStream out = new ObjectOutputStream(connection.getOutputStream());			
                out.writeUnshared(inObj);
                out.flush();
                out.close();		
                
                byte buffer[] = new byte[1024];			
                ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
                
                int size = connection.getInputStream().read(buffer);	
                
                while(size > 0) {			
                    byteOutput.write(buffer,0,size);
                    size = connection.getInputStream().read(buffer);
                }
                
                connection.getInputStream().close();			
                connection.disconnect();
                
                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOutput.toByteArray());
                ObjectInputStream in = new ObjectInputStream(byteIn);
                
                outObj = in.readUnshared();			
                byteOutput.close();
                byteOutput.flush();
                byteIn.close();
                in.close();	
            } catch (Exception e) {
                e.printStackTrace();
            }
            
            return outObj;
	}

}

Servlet:

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ObjServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException {		
            ObjectInputStream in = new ObjectInputStream(request.getInputStream());
            ObjectOutputStream out = null;
            
            try {
                // lendo da entrada
                Object inObj = in.readUnshared(); // objeto enviado da entrada					
                Object outObj = null; // objecto que sera enviado a saida

                // manipulando os objetos
                outObj = validarPeao(inObj);

                // escrevendo na saida
                out = new ObjectOutputStream(response.getOutputStream());
                out.writeUnshared(outObj);			
            } catch (Exception e) { 
                e.printStackTrace();
            } finally {
                in.close();
                out.flush();			
                out.close();
            }
	}

	@Override
	protected void doPost(HttpServletRequest arg0, HttpServletResponse arg1) 
                throws ServletException, IOException {
            doGet(arg0, arg1);
	}
	
	
	private static Object validarPeao(Object inObj) {
            Object outObj = null;
            
            if (inObj instanceof List) {
                List entradaLista = (List)inObj;
                String[] auxLista = new String[entradaLista.size()];
                
                for(int i=0; i<entradaLista.size(); i++) {
                    auxLista[i] = entradaLista.get(i).toString();
                }		

                Arrays.sort(auxLista);
                List<String> retornoList = new ArrayList<String>();
                
                for(int i=0; i<auxLista.length; i++) {
                    retornoList.add("[POGGER] " + auxLista[i]);
                }		
                
                outObj = retornoList;
            }
            
            return outObj;
	}
}

Eu também gostaria de saber se existe outra biblioteca pra trabalhar além da Finger.

Testei seu código e deu o mesmo erro!!! Será que estou declarando a Servlet certo? Eu uso o Netbeans.

Resolvido o problema hehe, eu não tinha colocado o endereco do Servlet correto. :blush:

Valeu pela ajuda galera.

Abraços.

eu faria como disseram!

via web service !

encapsularia o template em um xml aplicando compactacao na imagem!

no tier server

ele faria o processo e retornaria um xml com o resultado

bem portavel e pratico não?

Que bom que deu certo… tentei achar o erro e nao consegui.

Titôsca, a grande dificuldade de utilizar web service neste caso, é que o objeto a ser enviado não é uma imagem, e sim um objeto proprietário que nao temos acesso ao código fonte.

Serializar e “deserializar” ele na unha daria certo? Como fazer isso?

Pilantra, se vc conseguir transformar o Template para enviar via xml, seria bem mais portável mesmo. E vc nao teria problema com versao de JRE :slight_smile:

Vale a tentativa…