Transformar programa console em JSP ( E ganhe chat do facebook em java de brinde)

3 respostas
S

Fala galera, bom dia pra todo mundo [:

Eu to fazendo uma rede social que faz integração com facebook e
uma das suas funcionalidades é a usar o chat do face ( e Google+) .

Eu reuní vários exemplos e montei um programinha simples em console pra usar o XMPP, que é o protocolo que
o face usa para chat e tá funcionando até que legal.

O problema é que eu to apanhando mais que marido quando chega bêbado com marca de batom de madrugada
pra transformar isso em JSP. Perdoem esse jovem Padawan, eu faço direito e me aventuro nessas Terras
de java por teimosia ou por maldição, e queria poder contar com uma ajuda de vocês.

Vou jogar o programa aí, usando as duas formas de autenticação DIGEST-MD5 quanto X-FACEBOOK-PLATAFORM . A X-FACEBOOK-PLATAFORM deu um trabalhão
mas fica de presente pra vocês.

O exemplo que implementei é com DIGEST-MD5: só pra quem não conhecer a API do face não ficar perdido.
Pra quem se interessar pelo X-FACEBOOK-PLATAFORM como método de login é basicamente um jeito de obter
um access token do face que vale como uma chave que identifica o usuário. Igual aqueles tokens de banco.
Aí ele não precisa ficar entrando com usuário e senha o tempo todo: o face confia no access token e o usuário
confia em você ao deixar o access token ser gravado no seu banco, e a coisa toda funciona.

Funcionamento:

Vou deixar o Listener rodando na página do perfil do cara.
Ao receber uma mensagem, esse listener alimenta o FacebookMessageBean que é o objeto que representa a mensagem
e depois insere no banco de dados usando o FacebookMessageDAO.
Vai ter um processo rodando ativamente em javascript para ir no banco e pegar o que tiver no banco e jogar na tela
dentro da caixinha de chat do cara;

Você deve estar se perguntando porque simplesmente não jogo na tela, sem toda essa volta do Bean e do DAO.
Bem, é uma questão técnica: porque se eu fizer isso eu não tenho como saber se a mensagem chegou
e nem posso ler as mensagens que eu mesmo enviei ( depois que desloguei).

O que acontece de errado:
Quando eu tento transformar isso em JSP ele entra em um loop demoníaco e não sai nunca. Aí, consequentemente eu olho lá pro banco e não chega nada.

Gostaria de saber como seria o JSP de vocês. ( ignorem a GUI, pensem apenas no funcional).

Agradeço a grande ajuda de todos, qualquer colaboração é muito bem vinda. Quero terminar uma versão funcional até sexta ,posto aqui
pra ver se vcs curtem.

//principal FBConsoleChatApp.java
package com.fb.xmppchat.app;

import com.fb.xmppchat.helper.CustomSASLDigestMD5Mechanism;
import com.fb.xmppchat.helper.FBMessageListener;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.DualHashBidiMap;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;

public class FBConsoleChatApp {

   public static final String FB_XMPP_HOST = "chat.facebook.com";
   public static final int FB_XMPP_PORT = 5222;

   private ConnectionConfiguration config;
   private XMPPConnection connection;
   private BidiMap friends = new DualHashBidiMap();
   private FBMessageListener fbml;

   public String connect() throws XMPPException {
      config = new ConnectionConfiguration(FB_XMPP_HOST, FB_XMPP_PORT);
    // esse X-FACEBOOK-PLATAFORM é outro jeito de autenticar. Em vez de passar usuario e senha,
      // você se loga no face uma vez e ganha uma chave de acesso temporária.

    //  SASLAuthentication.registerSASLMechanism("X-FACEBOOK-PLATFORM", SASLXFacebookPlatformMechanism.class);
    //  SASLAuthentication.supportSASLMechanism("X-FACEBOOK-PLATFORM", 0);
    SASLAuthentication.registerSASLMechanism("DIGEST-MD5"
        , CustomSASLDigestMD5Mechanism.class);
      config.setSASLAuthenticationEnabled(true);
      config.setDebuggerEnabled(false);
      connection = new XMPPConnection(config);
      connection.connect();
      fbml = new FBMessageListener(connection);
      return connection.getConnectionID();
   }

   public void disconnect() {
      if ((connection != null) && (connection.isConnected())) {
         Presence presence = new Presence(Presence.Type.unavailable);
         presence.setStatus("offline");
         connection.disconnect(presence);
      }
   }

   public boolean login(String userName, String password)
     throws XMPPException {
      if ((connection != null) && (connection.isConnected())) {
         connection.login(userName, password);
         return true;
      }
      return false;
   }



   public String readInput() throws IOException {
      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      return br.readLine();
   }

   public void showMenu() {
      System.out.println("Escolha uma opção.");
      System.out.println("1. Ver amigos online");
      System.out.println("2. Mandar mensagem");
      System.out.println("3. SAIR");
      System.out.print("Escolha: ");
   }

   public void getFriends() {
      if ((connection != null) && (connection.isConnected())) {
         Roster roster = connection.getRoster();
         int i = 1;
         for (RosterEntry entry : roster.getEntries()) {
            Presence presence = roster.getPresence(entry.getUser());
            if ((presence != null)
               && (presence.getType() != Presence.Type.unavailable)) {
               friends.put(entry.getUser(), entry);
               System.out.println(entry.getName() + "(#" + entry.getUser() + ")");
               i++;
            }
         }
         fbml.setFriends(friends);
      }
   }

   public void sendMessage() throws XMPPException
     , IOException {
      System.out.println("Escreva o código do seu amigo ( em números) para enviar uma mensagem");
      String friendKey = null;
      String text = null;
      System.out.print("Codigo do seu amigo: ");
      friendKey = readInput();
      System.out.print("Mensagem: ");
      text = readInput();
      sendMessage((RosterEntry) friends.get(friendKey), text);
   }

   public void sendMessage(final RosterEntry friend, String text)
     throws XMPPException {
      if ((connection != null) && (connection.isConnected())) {
         ChatManager chatManager = connection.getChatManager();
         Chat chat = chatManager.createChat(friend.getUser(), fbml);
         chat.sendMessage(text);
         System.out.println("Mensagem enviada para "
            + friend.getName());
      }
   }

   public static void main(String[] args) {
 
//o usuário é o que aparece na página depois do www.facebook.com
//http://www.facebook.com/eduardo.pacheco.587 no meu caso é eduardo.pacheco.587
      String username = "eduardo.pacheco.587";
      String password = "minhasenha"; //senha


       System.out.println("recebeu parametros");
      FBConsoleChatApp app = new FBConsoleChatApp();

      try {
         app.connect();

         if (!app.login(username, password)) {

            System.out.println("Acesso Negado...");
            System.exit(-2);
         }
         app.showMenu();
         String data = null;
         menu:
         while((data = app.readInput().trim()) != null) {
            if (!Character.isDigit(data.charAt(0))) {
               System.out.println("Entrada inválida, use apenas 1-3 !");
               app.showMenu();
               continue;
            }
            int choice = Integer.parseInt(data);
            if ((choice != 1) && (choice != 2) && (choice != 3)) {
               System.out.println("Entrada inválida, use apenas 1-3 !");
               app.showMenu();
               continue;
            }
            switch (choice) {
               case 1: app.getFriends();
                       app.showMenu();
                       continue menu;
               case 2: app.sendMessage();
                       app.showMenu();
                       continue menu;
               default: break menu;
            }
         }
         app.disconnect();
      } catch (XMPPException e) {
        if (e.getXMPPError() != null) {
           System.out.println("ERROR-CODE : " + e.getXMPPError().getCode());
           System.out.println("ERROR-CONDITION : " + e.getXMPPError().getCondition());
           System.out.println("ERROR-MESSAGE : " + e.getXMPPError().getMessage());
           System.out.println("ERROR-TYPE : " + e.getXMPPError().getType());
        }
        app.disconnect();
      } catch (IOException e) {
        System.out.println(e.getMessage());
        app.disconnect();
      }
  }
}


//SASLXFacebookPlatformMechanism.java
package com.fb.xmppchat.app;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import javax.security.sasl.Sasl;

import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;
import org.jivesoftware.smack.util.Base64;

public class SASLXFacebookPlatformMechanism extends SASLMechanism {

    public static final String NAME = "X-FACEBOOK-PLATFORM";
    private String apiKey = "";
        private String accessToken = "";


    /**
     * Constructor.
     */
    public SASLXFacebookPlatformMechanism(SASLAuthentication saslAuthentication) {
            super(saslAuthentication);
    }

    @Override
    protected void authenticate() throws IOException, XMPPException {
        // Send the authentication to the server
        getSASLAuthentication().send(new AuthMechanism(getName(), ""));
    }

    @Override
    public void authenticate(String apiKey, String host, String accessToken) throws IOException, XMPPException {
        this.apiKey = apiKey;
        this.accessToken = accessToken;
        this.hostname = host;

        String[] mechanisms = { "DIGEST-MD5" };
        Map<String, String> props = new HashMap<String, String>();
        this.sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
        authenticate();
    }

    @Override
    protected String getName() {
            return NAME;
    }

    @Override
    public void challengeReceived(String challenge) throws IOException {
        byte[] response = null;

        if (challenge != null) {
                    String decodedChallenge = new String(Base64.decode(challenge));
                    Map<String, String> parameters = getQueryMap(decodedChallenge);

                    String version = "1.0";
                    String nonce = parameters.get("nonce");
                    String method = parameters.get("method");

                    long callId = new GregorianCalendar().getTimeInMillis() / 1000L;

                    String composedResponse = "api_key=" + URLEncoder.encode(apiKey, "utf-8")
                                                                            + "&call_id=" + callId
                                                                            + "&method=" + URLEncoder.encode(method, "utf-8")
                                                                            + "&nonce=" + URLEncoder.encode(nonce, "utf-8")
                                                                            + "&access_token=" + URLEncoder.encode(accessToken, "utf-8")
                                                                            + "&v=" + URLEncoder.encode(version, "utf-8");

                    response = composedResponse.getBytes("utf-8");
        }

        String authenticationText = "";

        if (response != null){
                    authenticationText = Base64.encodeBytes(response, Base64.DONT_BREAK_LINES);
                }
        // Send the authentication to the server
        getSASLAuthentication().send(new Response(authenticationText));
    }

    private Map<String, String> getQueryMap(String query) {
            Map<String, String> map = new HashMap<String, String>();
            String[] params = query.split("\\&");

            for (String param : params) {
                    String[] fields = param.split("=", 2);
                    map.put(fields[0], (fields.length > 1 ? fields[1] : null));
            }
            return map;
    }
    }

//CustomSASLDigestMD5Mechanism.java
package com.fb.xmppchat.helper;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.Sasl;

import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.sasl.SASLMechanism;

public class CustomSASLDigestMD5Mechanism extends SASLMechanism {

   public CustomSASLDigestMD5Mechanism(SASLAuthentication saslAuthentication) {
      super(saslAuthentication);
   }

   @Override
   public void authenticate(String username, String host, String password)
     throws IOException, XMPPException {
      this.authenticationId = username;
      this.password = password;
      this.hostname = host;

      String[] mechanisms = { getName() };
      Map<String, String> props = new HashMap<String, String>();
      sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, this);
      super.authenticate();
   }

   @Override
   public void authenticate(String username, String host, CallbackHandler cbh)
     throws IOException, XMPPException {
      String[] mechanisms = { getName() };
      Map<String, String> props = new HashMap<String, String>();
      sc = Sasl.createSaslClient(mechanisms, null, "xmpp", host, props, cbh);
      super.authenticate();
   }

   protected String getName() {
     return "DIGEST-MD5";
   }
}

//FBMessageListener.java
package com.fb.xmppchat.helper;

import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.MapIterator;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;

public class FBMessageListener implements MessageListener, Runnable {

   private FBMessageListener fbml = this;
   private XMPPConnection conn;
   private BidiMap friends;

   public FBMessageListener(XMPPConnection conn) {
      this.conn = conn;
      new Thread(this).start();
   }

   public void setFriends(BidiMap friends) {
      this.friends = friends;
   }

   public void processMessage(Chat chat, Message message) {
      System.out.println();
      MapIterator it = friends.mapIterator();
      String key = null;
      RosterEntry entry = null;
      while (it.hasNext()) {
         key = (String) it.next();
         entry = (RosterEntry) it.getValue();
         if (entry.getUser().equalsIgnoreCase(chat.getParticipant())) {
            break;
         }
      }
      if ((message != null) && (message.getBody() != null)) {
         System.out.println(  entry.getName()+"( "+entry.getUser()+" )");
         System.out.println(message.getBody() );
         System.out.print("Sua escolha[1-3]: ");
      }
   }

   public void run() {
      conn.getChatManager().addChatListener(
         new ChatManagerListener() {
            public void chatCreated(Chat chat, boolean createdLocally) {
               if (!createdLocally) {
                  chat.addMessageListener(fbml);
               }
            }
         }
      );
   }
}

3 Respostas

S

Ah, precisa das bibliotecas Smack ( xmpp para java)
http://www.igniterealtime.org/projects/smack/

e usar o Bidmap do Apache commons-collections, baixa aqui
http://commons.apache.org/collections/download_collections.cgi

obrigado!

S

:confused:

K

Olá shamanpyro,

Estou executando seu código e estou obtendo o seguinte erro:

SASL authentication X-FACEBOOK-PLATFORM failed: not-authorized:

Você tem alguma ideia do que pode ser este problema?

Estou iniciando na api do facebook.

Obrigado.

Criado 14 de janeiro de 2013
Ultima resposta 19 de jul. de 2013
Respostas 3
Participantes 2