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);
}
}
}
);
}
}
