package net.thesocialos.server; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Properties; import javax.servlet.http.HttpSession; import net.thesocialos.shared.ChannelApiEvents.ChApiChatUserChngState; import net.thesocialos.shared.ChannelApiEvents.ChApiChatUserChngState.STATETYPE; import net.thesocialos.shared.ChannelApiEvents.ChApiContactNew; import net.thesocialos.shared.ChannelApiEvents.ChApiContactPetition; import net.thesocialos.shared.ChannelApiEvents.ChApiEvent; import net.thesocialos.shared.ChannelApiEvents.ChApiPushDisconnect; import net.thesocialos.shared.ChannelApiEvents.ChApiShareChange; import net.thesocialos.shared.model.User; import com.google.appengine.api.channel.ChannelFailureException; import com.google.appengine.api.channel.ChannelMessage; import com.google.appengine.api.channel.ChannelService; import com.google.appengine.api.channel.ChannelServiceFactory; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.server.rpc.RPC; import com.google.gwt.user.server.rpc.SerializationPolicy; import com.googlecode.objectify.Key; public class ChannelApiHelper { private static Properties props = System.getProperties(); // private static final boolean USE_CHANNEL_API = setChannelAPIEnabled(); private static final String APP_KEY = "SOS-"; private static final Method dummyMethod = getDummyMethod(); // final names; private final static String sessionN = "session"; private final static String userN = "user"; private final static String OBJECITIFY = "objetify"; /** * Create a channel for a user. Returns the channel id that the client must use to connect for receiving push * messages. * * @param userUniqueId * @return the client channel id */ public static String createChannel(HttpSession httpsession) throws ChannelFailureException { String userEmail = UserHelper.getUserHttpSession(httpsession); return getChannelService().createChannel(APP_KEY + userEmail); } /** * Send a message to one specific user * * @param userEmail * The user to send the message to * @param encodedString * The message codified * @throws ChannelFailureException */ public static void sendMessage(String userEmail, String encodedString) throws ChannelFailureException { getChannelService().sendMessage(new ChannelMessage(getAppKeyForUser(userEmail), encodedString)); } public static String encodeMessage(ChApiEvent channelApiEvent) { try { return RPC.encodeResponseForSuccess(dummyMethod, channelApiEvent, new SerializationPolicy() { @Override public boolean shouldDeserializeFields(Class<?> clazz) { return false; // TODO Auto-generated method stub return false; } @Override public boolean shouldSerializeFields(Class<?> clazz) { return false; // TODO Auto-generated method stub return false; } @Override public void validateDeserialize(Class<?> clazz) throws SerializationException { // TODOAuto-generated // method stub } @Override public void validateSerialize(Class<?> clazz) throws SerializationException { // TODOAuto-generated // method stub } }); // return RPC.encodeResponseForSuccess(dummyMethod, channelApiEvent, // //MergedSerializationPolicy.createPushSerializationPolicy()); } catch (SerializationException e) { throw new RuntimeException("Unable to encode a message for push.\n" + channelApiEvent, e); } } private static boolean setChannelAPIEnabled() { String skey = props.getProperty("com.metadot.connectr.enable-channelapi"); if (skey != null) { if (skey.equalsIgnoreCase("true")) // logger.info("channel API is enabled"); return true; if (skey.equalsIgnoreCase("false")) return false; } return false; } private static ChannelService getChannelService() { return ChannelServiceFactory.getChannelService(); } private static String getAppKeyForUser(String userUniqueId) { return APP_KEY + userUniqueId; } /** * Split the String in two parts * * @param appKeyUser * @return */ public static String getUserForAppkey(String appKeyUser) { String[] stringSplit = appKeyUser.split("-"); return stringSplit[1]; } public static Method getDummyMethod() { try { return ChannelApiHelper.class.getDeclaredMethod("dummyMethod"); } catch (NoSuchMethodException e) { throw new RuntimeException("Unable to find the dummy RPC method."); } } /** * This method exists to make GWT RPC happy. * <p> * {@link RPC#encodeResponseForSuccess(java.lang.reflect.Method, Object)} insists that we pass it a Method that has * a return type equal to the object we're encoding. What we really want to use is * {@link RPC#encodeResponse(Class, Object, boolean, int, com.google.gwt.user.server.rpc.SerializationPolicy)} , but * it is unfortunately private. */ @SuppressWarnings("unused") private ChApiEvent dummyMethod() { throw new UnsupportedOperationException("This should never be called."); } /** * Send the user state for all contacts if are connected * * @param contacts * @param state * @param custom * @param email */ public static void sendStateToContacts(Iterator<User> contacts, STATETYPE state, String custom, Key<User> userKey) { while (contacts.hasNext()) { User user = contacts.next(); if (user.isConnected) ChannelApiHelper.sendMessage(user.getEmail(), ChannelApiHelper.encodeMessage(new ChApiChatUserChngState(state, custom, userKey))); } } /** * * @param user * @param userEmail */ public static void sendPetitionContactToUser(User user, String userEmail) { if (user.isConnected) ChannelApiHelper.sendMessage(user.getEmail(), ChannelApiHelper.encodeMessage(new ChApiContactPetition(userEmail))); } /** * * @param user * @param userEmail */ public static void sendContactToUser(User user, String userEmail) { if (user.isConnected) ChannelApiHelper.sendMessage(user.getEmail(), ChannelApiHelper.encodeMessage(new ChApiContactNew(userEmail))); } /** * * @param user * @param userEmail */ public static void sendSharetoUser(User user) { if (user.isConnected) ChannelApiHelper.sendMessage(user.getEmail(), ChannelApiHelper.encodeMessage(new ChApiShareChange())); } public static void disconnectUser(User user) { ChannelApiHelper.sendMessage(user.getEmail(), ChannelApiHelper.encodeMessage(new ChApiPushDisconnect())); } }