package com.robonobo.midas; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.management.MBeanServer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.remoting.*; import org.jboss.remoting.callback.InvokerCallbackHandler; import org.jboss.remoting.transport.Connector; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import com.robonobo.common.exceptions.SeekInnerCalmException; import com.robonobo.common.remote.RemoteCall; import com.robonobo.core.api.proto.CoreApi.FriendRequestMsg; import com.robonobo.core.api.proto.CoreApi.PlaylistMsg; import com.robonobo.core.api.proto.CoreApi.StreamMsg; import com.robonobo.core.api.proto.CoreApi.UserConfigMsg; import com.robonobo.core.api.proto.CoreApi.UserMsg; import com.robonobo.midas.model.*; import com.robonobo.remote.service.MidasService; /** The server end of a remote midas service (client end is RemoteMidasFacade) TODO Use EJB3s instead... * * @author macavity */ public class RemoteMidasService implements ServerInvocationHandler, InitializingBean, DisposableBean { @Autowired MidasService midas; @Autowired PlatformTransactionManager transactionManager; TransactionTemplate transTemplate; Connector connector; String secret; Log log = LogFactory.getLog(getClass()); /** @param url * The jboss-remoting url on which to listen * @param secret * The sekrit string that must be passed with all calls */ public RemoteMidasService(String url, String secret) throws Exception { this.secret = secret; log.info("Settin up remote midas service on " + url); InvokerLocator locator = new InvokerLocator(url); connector = new Connector(); connector.setInvokerLocator(locator.getLocatorURI()); } @Override public void afterPropertiesSet() throws Exception { transTemplate = new TransactionTemplate(transactionManager); log.info("Starting remote midas service"); connector.start(); connector.addInvocationHandler("midas", this); } @Override public void destroy() throws Exception { log.info("Stopping remote midas service"); connector.stop(); } public Object invoke(InvocationRequest req) throws Throwable { Object obj = req.getParameter(); if (!(obj instanceof RemoteCall)) { log.error("Remote invocation with parameter " + obj.getClass().getName()); throw new IllegalArgumentException("Invalid param"); } final RemoteCall params = (RemoteCall) obj; if (!secret.equals(params.getSecret())) { log.error("Remote invocation with invalid secret '" + params.getSecret() + "'"); throw new IllegalArgumentException("Invalid secret"); } final String method = params.getMethodName(); // Make sure everything happens inside a transaction return transTemplate.execute(new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus ts) { try { if (method.equals("getUserByEmail")) { return getUserByEmail(params); } else if (method.equals("getUserById")) { return getUserById(params); } else if (method.equals("saveUser")) { saveUser(params); return null; } else if (method.equals("getUserAsVisibleBy")) { return getUserAsVisibleBy(params); } else if (method.equals("getPlaylistById")) { return getPlaylistById(params); } else if (method.equals("savePlaylist")) { savePlaylist(params); return null; } else if (method.equals("deletePlaylist")) { deletePlaylist(params); return null; } else if (method.equals("getStreamById")) { return getStreamById(params); } else if (method.equals("saveStream")) { saveStream(params); return null; } else if (method.equals("deleteStream")) { deleteStream(params); return null; } else if (method.equals("countUsers")) { return countUsers(); } else if (method.equals("createUser")) { return createUser(params); } else if (method.equals("getAllUsers")) { return getAllUsers(); } else if (method.equals("deleteUser")) { deleteUser(params); return null; } else if (method.equals("createOrUpdateFriendRequest")) { return createOrUpdateFriendRequest(params); } else if (method.equals("getFriendRequest")) { return getFriendRequest(params); } else if (method.equals("getPendingFriendRequests")) { return getPendingFriendRequests(params); } else if (method.equals("ignoreFriendRequest")) { ignoreFriendRequest(params); return null; } else if (method.equals("acceptFriendRequest")) { return acceptFriendRequest(params); } else if (method.equals("createOrUpdateInvite")) { return createOrUpdateInvite(params); } else if (method.equals("inviteAccepted")) { inviteAccepted(params); return null; } else if (method.equals("getInvite")) { return getInvite(params); } else if(method.equals("getInviteByEmail")) { return getInviteByEmail(params); } else if (method.equals("getUserConfig")) { return getUserConfig(params); } else if (method.equals("putUserConfig")) { putUserConfig(params); return null; } else if (method.equals("addFriends")) { addFriends(params); return null; } else if (method.equals("requestTopUp")) { return requestTopUp(params); } else if(method.equals("getPlaylistByUserIdAndTitle")) { return getPlaylistByUserIdAndTitle(params); } else throw new IllegalArgumentException("Invalid method"); } catch (Exception e) { throw new RuntimeException(e); } } }); } private String acceptFriendRequest(RemoteCall params) throws IOException { FriendRequestMsg msg = FriendRequestMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); return midas.acceptFriendRequest(new MidasFriendRequest(msg)); } private byte[] getFriendRequest(RemoteCall params) { MidasFriendRequest fr = midas.getFriendRequest((String) params.getArg()); return fr.toMsg().toByteArray(); } private byte[][] getPendingFriendRequests(RemoteCall params) { List<MidasFriendRequest> frList = midas.getPendingFriendRequests((Long) params.getArg()); byte[][] result = new byte[frList.size()][]; for (int i = 0; i < frList.size(); i++) { result[i] = frList.get(i).toMsg().toByteArray(); } return result; } private void ignoreFriendRequest(RemoteCall params) throws IOException { FriendRequestMsg msg = FriendRequestMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); midas.ignoreFriendRequest(new MidasFriendRequest(msg)); } private void inviteAccepted(RemoteCall params) { Long acceptedUserId = (Long) params.getArg(); String inviteCode = (String) params.getExtraArgs().get(0); midas.inviteAccepted(acceptedUserId, inviteCode); } private Object getInvite(RemoteCall params) { MidasInvite invite = midas.getInvite((String) params.getArg()); if (invite == null) return null; return invite.toMsg().toByteArray(); } private Object getInviteByEmail(RemoteCall params) { MidasInvite invite = midas.getInviteByEmail((String) params.getArg()); if (invite == null) return null; return invite.toMsg().toByteArray(); } private void addFriends(RemoteCall params) { Long userId = (Long) params.getArg(); if (params.getExtraArgs().size() < 2) throw new SeekInnerCalmException(); // Java won't cast Object[] into Long[] automatically, rubbish Object[] fidArr = (Object[]) params.getExtraArgs().get(0); List<Long> fidList = new ArrayList<Long>(); for (Object o : fidArr) { fidList.add((Long) o); } Object[] strArr = (Object[]) params.getExtraArgs().get(1); List<String> strList = new ArrayList<String>(); for (Object o : strArr) { strList.add((String) o); } midas.addFriends(userId, fidList, strList); } private byte[] requestTopUp(RemoteCall params) { Long userId = (Long) params.getArg(); return midas.requestAccountTopUp(userId).getBytes(); } private Object getUserConfig(RemoteCall params) { MidasUser u = midas.getUserById((Long) params.getArg()); MidasUserConfig uc = midas.getUserConfig(u); return uc.toMsg().toByteArray(); } private void putUserConfig(RemoteCall params) throws IOException { UserConfigMsg ucm = UserConfigMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasUserConfig newMuc = new MidasUserConfig(ucm); MidasUser u = midas.getUserById(newMuc.getUserId()); MidasUserConfig muc = midas.getUserConfig(u); if (muc == null) muc = newMuc; else muc.mergeFrom(newMuc); midas.putUserConfig(muc); } private void deleteStream(RemoteCall params) throws IOException { StreamMsg msg = StreamMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasStream s = new MidasStream(msg); midas.deleteStream(s); } private void saveStream(RemoteCall params) throws IOException { StreamMsg msg = StreamMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasStream s = new MidasStream(msg); midas.saveStream(s); } private Object getStreamById(RemoteCall params) { String sId = (String) params.getArg(); return midas.getStreamById(sId).toMsg().toByteArray(); } private void deletePlaylist(RemoteCall params) throws IOException { PlaylistMsg msg = PlaylistMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasPlaylist pl = new MidasPlaylist(msg); midas.deletePlaylist(pl); } private void savePlaylist(RemoteCall params) throws IOException { PlaylistMsg msg = PlaylistMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasPlaylist pl = new MidasPlaylist(msg); midas.savePlaylist(pl); } private Object getPlaylistById(RemoteCall params) { Long plId = (Long) params.getArg(); MidasPlaylist p = midas.getPlaylistById(plId); if(p == null) return null; return p.toMsg().toByteArray(); } protected Object getPlaylistByUserIdAndTitle(RemoteCall params) { Long uid = (Long) params.getArg(); String title = (String) params.getExtraArgs().get(0); MidasPlaylist p = midas.getPlaylistByUserIdAndTitle(uid, title); if(p == null) return null; return p.toMsg().toByteArray(); } private Object getUserAsVisibleBy(RemoteCall params) throws IOException { UserMsg targetMsg = UserMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); UserMsg reqMsg = UserMsg.newBuilder().mergeFrom((byte[]) params.getExtraArgs().get(0)).build(); MidasUser target = new MidasUser(targetMsg); MidasUser requestor = new MidasUser(reqMsg); return midas.getUserAsVisibleBy(target, requestor).toMsg(true).toByteArray(); } private Object createOrUpdateFriendRequest(RemoteCall params) throws IOException { UserMsg requestorMsg = UserMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); UserMsg requesteeMsg = UserMsg.newBuilder().mergeFrom((byte[]) params.getExtraArgs().get(0)).build(); PlaylistMsg plMsg = PlaylistMsg.newBuilder().mergeFrom((byte[]) params.getExtraArgs().get(1)).build(); return midas.createOrUpdateFriendRequest(new MidasUser(requestorMsg), new MidasUser(requesteeMsg), new MidasPlaylist(plMsg)).toMsg().toByteArray(); } private Object createOrUpdateInvite(RemoteCall params) throws IOException { String email = (String) params.getArg(); UserMsg friendMsg = UserMsg.newBuilder().mergeFrom((byte[]) params.getExtraArgs().get(0)).build(); PlaylistMsg plMsg = PlaylistMsg.newBuilder().mergeFrom((byte[]) params.getExtraArgs().get(1)).build(); return midas.createOrUpdateInvite(email, new MidasUser(friendMsg), new MidasPlaylist(plMsg)).toMsg().toByteArray(); } private void saveUser(RemoteCall params) throws IOException { UserMsg msg = UserMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasUser user = new MidasUser(msg); midas.saveUser(user); } private Object createUser(RemoteCall params) throws IOException { UserMsg msg = UserMsg.newBuilder().mergeFrom((byte[]) params.getArg()).build(); MidasUser user = new MidasUser(msg); return midas.createUser(user).toMsg(true).toByteArray(); } private Object getUserById(RemoteCall params) { Long userId = (Long) params.getArg(); MidasUser user = midas.getUserById(userId); if (user == null) return null; return user.toMsg(true).toByteArray(); } private Object getUserByEmail(RemoteCall params) { String email = (String) params.getArg(); MidasUser user = midas.getUserByEmail(email); if (user == null) return null; return user.toMsg(true).toByteArray(); } private Long countUsers() { return midas.countUsers(); } private Object getAllUsers() { List<MidasUser> allUsers = midas.getAllUsers(); byte[][] arrOfArrs = new byte[allUsers.size()][]; for (int i = 0; i < arrOfArrs.length; i++) { arrOfArrs[i] = allUsers.get(i).toMsg(true).toByteArray(); } return arrOfArrs; } private void deleteUser(RemoteCall params) { midas.deleteUser((Long) params.getArg()); } public void addListener(InvokerCallbackHandler arg0) { // Do nothing } public void removeListener(InvokerCallbackHandler arg0) { // Do nothing } public void setInvoker(ServerInvoker arg0) { // Do nothing } public void setMBeanServer(MBeanServer arg0) { // Do nothing } }