Estou desenvolvendo uma aplicação Client-Server, onde o servidor mantem uma coleção de objetos (Funcionários) e a distribui esta coleção atualizada para todos os clientes toda vez que algum cliente se conecta no servidor.
Porém meu problema está em enviar a coleção que na verdade é um ArrayList. Se eu não atualizar a List e enviar do jeito que ela foi montada vai certinho, mas eu preciso alterar o status de um Funcionário para depois repassar a List atualizada, quando faço esta atualização gera a seguinte Exception: java.io.NotSerializableException: java.io.PrintStream.
Segue abaixo o trecho de código com problema:
OutputStream out = conexao.getOutputStream();
ObjectOutputStream oout=new ObjectOutputStream(out);
List envio = new ArrayList();
for (Iterator I = usuarios.iterator(); I.hasNext();){
Funcionario func = ((Funcionario) I.next());
if ((func.getUserName().substring(16)).equals(meuNome)){
func.setID(saida);
func.setStatus("Presente");
System.out.println((func.getUserName().substring(16))+" --> Funcionário logado");
System.out.println(func.getStatus());
System.out.println(func.getID());
}
envio.add(func);
}
oout.writeObject(envio);
oout.flush();
Se eu comentar as linhas:
func.setID(saida);
func.setStatus("Presente");
e enviar o objeto usuarios, vai certinho porém o objeto usuarios não está atualizado.
Verifique as variáveis de instância da classe que não está conseguindo ser serializada (por exemplo, deve ser Funcionario) e veja se alguma delas é uma PrintStream. Se for, então use o modificador “transient” nessa variável de instância.
Olá entanglement ,
Muito obrigado pela ajuda, problema resolvido. Era uma variável dentro da classe Funcionario realmente que não possuia esse modificador transient, não conhecia esse modificador, pelo que li a respeito ele não permite que a variavel seja enviada pela rede e realmente nesse caso a variável só é utilizada no lado do servidor.
Fala kenneth, então segue parte do código onde tive que colocar o “transient”:
public class Funcionario extends Pessoa implements Serializable{
public Funcionario(){
}
private String departamento;
private String subGrupo;
private String cargo;
private String email;
private String ramal;
private String celular;
private String status;//Presente/Ausente/Reunião na sala/Reunião fora da sala/Desconectado
private String mensagem;
private String userName;
private transient ObjectOutputStream ID;
Depois dessa alteração na classe Funcionário consegui enviar a coleção via socket, porém ainda estou com um probleminha na atualização da coleção, logo mais vou postar o código.
Já estou ficando meio charope de tanto alterar minhas classes e não consigo resolver o problema, vamos ver se alguém consegue me ajudar, a situação é a seguinte:
Eu tenho uma aplicação server que monta uma lista de usuários a partir de uma conexão LDAP, estou armazenando esses usuários em objetos "Funcionarios" e colocados um a um dentro de uma List "ArrayList", depois de montar a coleção a aplicação fica ouvindo uma determinada porta no ServerSocket, quando recebe alguma conexão direciono essa conexão para uma Thread e continuo ouvindo a porta para receber outras conexões, a thread por sua vez percorre a minha coleção de Funcionários até achar o Funcionário que seja igual ao nome do usuário que se conectou quando encontra atualizo alguns campos do objeto Funcionário "que está dentra da coleção"… tipo altero o status dele para presente, depois de alterar o staus, eu envio a coleção agora atualizada para todos os outros usuários que já estavam conectados antes. Por sua vez a aplicação Client se conecta no server, envia o nome do usuário conectado na máquina e fica aguardando o servidor enviar a coleção de Funcionários, quando recebe imprimo tudo na tela. Quando conecto o primeiro usuário fica lindo certinho, mas quando conecto o segundo fica certinho também, mas nesse momento a tela do primeiro usuário é atualizada com a nova lista ou seja deveria aparecer na tela do primeiro usuário que o segundo usuário está "Presente", mas pelo que eu estou entendendo a lista não está atualizando no cliente, segue os códigos:
public class Client extends Thread implements Serializable {
// Flag que indica quando se deve terminar a execução.
private static boolean done = false;
//public static void main(String args[]) {
public Client() {
try {
Socket conexao = new Socket("192.000.0.000", 9999);
PrintStream saida = new PrintStream(conexao.getOutputStream());
BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in));
Thread t = new Client(conexao);
t.start();
String linha;
while (true) {
// ler a linha digitada no teclado
System.out.print("> ");
linha = teclado.readLine();
// antes de enviar, verifica se a conexão não foi fechada
if (done) {break;}
// envia para o servidor - Na verdade esse trecho de código só serve para quando enviar uma String vazia o server fecha a conexão.
saida.println(linha);
}
}catch (IOException e) {
// Caso ocorra alguma excessão de E/S, mostre qual foi.
System.out.println("IOException: " + e);
}
}
// parte que controla a recepção de mensagens deste cliente
private Socket conexao;
// construtor que recebe o socket deste cliente
public Client (Socket s) {
conexao = s;
}
// execução da thread
public void run() {
try {
ObjectInputStream oIn;
InputStream in;
in = conexao.getInputStream();
oIn = new ObjectInputStream(in);
while (true) {
try{
Object obj = new Object();
obj = oIn.readObject();
if (obj == null) {
System.out.println("Conexão encerrada!");
break;
}
List usr = new ArrayList();
if (obj instanceof Resposta) {//Resposta é um objeto que o server retorna quando a conexão é bem sucedida
PrintStream saidaTemp = new PrintStream(conexao.getOutputStream());
saidaTemp.println(System.getProperty("user.name"));//Envia o nome do usuário
System.out.println("CONECTADO");
}else if(obj instanceof List) {//Aqui recebo a Lista de Funcionários
usr = (ArrayList) obj;
System.out.println("Recebeu a coleção");
for (Iterator I = usr.iterator(); I.hasNext();){
Funcionario func = ((Funcionario) I.next());
System.out.println((func.getUserName().substring(16)));
System.out.println(func.getStatus());//O problema é que este campo não é atualizado, traz sempre o mesmo valor, mas lá no server está sendo enviado corretamente
}
}
}catch(ClassNotFoundException cnfe){
System.out.println("not found");
}
}
}catch (IOException e) {
// caso ocorra alguma exceção de E/S, mostre qual foi.
done = true;
System.out.println("IOException: " + e);
}
// sinaliza para o main que a conexão encerrou.
done = true;
}
}
Agora o código do Server:
public class Main extends Thread{
// socket deste cliente
private Socket conexao;
private static Vector clientes;
// nome deste cliente
private String meuNome;
private static List usuarios = new ArrayList();
public static void main(String[] args) {
try{
montaLista();
// criando um socket que fica escutando a porta 9999.
ServerSocket s = new ServerSocket(9999);
//Monta serviço
System.out.println("Montando serviço de escuta.");
try {
// Loop principal.
while (true) {
// aguarda algum cliente se conectar. A execução do
// servidor fica bloqueada na chamada do método accept da
// classe ServerSocket. Quando algum cliente se conectar
// ao servidor, o método desbloqueia e retorna com um
// objeto da classe Socket, que é porta da comunicação.
System.out.print("Esperando alguem se conectar...");
Socket conexao = s.accept();
System.out.println(" Conectou!");
// cria uma nova thread para tratar essa conexão
Thread t = new Main(conexao);
t.start();
// voltando ao loop, esperando mais alguém se conectar.
}
}catch (IOException e) {
// caso ocorra alguma excessão de E/S, mostre qual foi.
System.out.println("IOException: " + e);
}
}catch (IOException e) {
// caso ocorra alguma excessão de E/S, mostre qual foi.
System.out.println("IOException: " + e);
}
}//Fim do Main
public static void montaLista(){
/**
* Monta a coleção de Funcionários/usuários
*/
String grupo;
String subGrupo;
grupo = "";
subGrupo = "";
System.out.println("Criando instância de conexão com servidor LDAP.");
DomainCon dominio = new DomainCon();
System.out.println("Tentativa de conexão com servidor LDAP.");
dominio.montaColecao();
System.out.println("Conexão com servidor LDAP bem sucedida.");
System.out.println("Obtendo coleção de dados.");
usuarios = dominio.GetColecao(); // Traz a lista de usuários
clientes = new Vector();
//Aqui é uma simples conferência dos dados
for (Iterator I = usuarios.iterator(); I.hasNext();){
Funcionario func = ((Funcionario) I.next());
if (!grupo.equals(func.getDepartamento())){
grupo = func.getDepartamento();
System.out.println("* "+grupo);
}
if (!subGrupo.equals(func.getSubGrupo())){
subGrupo = func.getSubGrupo();
System.out.println("** "+subGrupo);
}
System.out.println("*** "+func.getNome());
}
}
public Main(Socket s) {
conexao = s;
}
// execução da thread
public void run() {
try {
// objetos que permitem controlar fluxo de comunicação
BufferedReader entrada = new BufferedReader(new InputStreamReader(conexao.getInputStream()));
//PrintStream saida = new PrintStream(conexao.getOutputStream());
OutputStream out = conexao.getOutputStream();
ObjectOutputStream oout=new ObjectOutputStream(out);
//Confirma para o cliente a conexão
Resposta rsp = new Resposta();
rsp.setRsposta("CONSYSTEM");
oout.writeObject((Object)rsp);
oout.flush();
// Aguarda o nome do usuário conectado (nome da conta)
meuNome = entrada.readLine();
Funcionario func = new Funcionario();
for (Iterator I = usuarios.iterator(); I.hasNext();){
func = ((Funcionario) I.next());
if ((func.getUserName().substring(16)).equals(meuNome)){
func.setID(oout);
func.setStatus("Presente");
System.out.println((func.getUserName().substring(16))+" --> Funcionário logado");
System.out.println(func.getStatus());
System.out.println(func.getID());
}
}
oout.flush();
oout.writeObject((Serializable) usuarios);// Responde para o usuário que conectou, enviando a lista de Funcionários
oout.flush();
clientes.add(oout);//Adiciona a conexão atual à coleção
if (meuNome == null) {return;}
sendToAll(oout);//Envia a coleção atualizada para todos os clientes já conectados
String linha = entrada.readLine();
while (linha != null && !(linha.trim().equals(""))) { //Fica no Loop até que o cliente envie uma String vazia
linha = entrada.readLine();
}
for (Iterator I = usuarios.iterator(); I.hasNext();){// Aqui Atuaiza o usuário para o status "Desconectado"
func = ((Funcionario) I.next());
if ((func.getUserName().substring(16)).equals(meuNome)){
func.setID(null);
func.setStatus("Desconectado");
System.out.println((func.getUserName().substring(16))+" --> Funcionário desconectado");
}
}
sendToAll(oout);//Envia a lista atualizada para todos os Clientes
clientes.remove(oout);
conexao.close();
}catch (IOException e) {
// Caso ocorra alguma excessão de E/S, mostre qual foi.
System.out.println("IOException: " + e);
}
}
// enviar a lista para todos
public void sendToAll(ObjectOutputStream saida) throws IOException {
Enumeration e = clientes.elements();
while (e.hasMoreElements()) {
//OutputStream out = conexao.getOutputStream();
ObjectOutputStream mandaBala = (ObjectOutputStream) e.nextElement();
mandaBala.flush();
mandaBala.writeObject((Serializable) usuarios);
mandaBala.flush();
System.out.println("Atualizando "+mandaBala);
}
}
}