package com.stacksync.syncservice.rpc; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; import java.util.UUID; import omq.common.broker.Broker; import omq.exception.RemoteException; import org.apache.log4j.Logger; import com.stacksync.commons.models.CommitInfo; import com.stacksync.commons.models.Item; import com.stacksync.commons.models.ItemMetadata; import com.stacksync.commons.models.User; import com.stacksync.commons.models.Workspace; import com.stacksync.commons.notifications.CommitNotification; import com.stacksync.commons.notifications.ShareProposalNotification; import com.stacksync.commons.notifications.UnshareNotification; import com.stacksync.commons.omq.RemoteClient; import com.stacksync.commons.omq.RemoteWorkspace; import com.stacksync.syncservice.db.ConnectionPool; import com.stacksync.syncservice.handler.SQLAPIHandler; import com.stacksync.syncservice.handler.Handler.Status; import com.stacksync.syncservice.rpc.messages.APICommitResponse; import com.stacksync.syncservice.rpc.messages.APICreateFolderResponse; import com.stacksync.syncservice.rpc.messages.APIDeleteResponse; import com.stacksync.syncservice.rpc.messages.APIGetFolderMembersResponse; import com.stacksync.syncservice.rpc.messages.APIGetMetadata; import com.stacksync.syncservice.rpc.messages.APIGetVersions; import com.stacksync.syncservice.rpc.messages.APIGetWorkspaceInfoResponse; import com.stacksync.syncservice.rpc.messages.APIResponse; import com.stacksync.syncservice.rpc.messages.APIRestoreMetadata; import com.stacksync.syncservice.rpc.messages.APIShareFolderResponse; import com.stacksync.syncservice.rpc.messages.APIUnshareFolderResponse; import com.stacksync.syncservice.rpc.parser.IParser; import com.stacksync.syncservice.util.Constants; public class XmlRpcSyncHandler { private static final Logger logger = Logger.getLogger(XmlRpcSyncHandler.class.getName()); private SQLAPIHandler apiHandler; private IParser parser; private Broker broker; public XmlRpcSyncHandler(Broker broker, ConnectionPool pool) { try { this.apiHandler = new SQLAPIHandler(pool); this.broker = broker; this.parser = Reader.getInstance("com.stacksync.syncservice.rpc.parser.JSONParser"); logger.info("XMLRPC server set up done."); } catch (Exception e) { logger.error("XMLRPC server could not initiliaze."); } } public String getMetadata(String strUserId, String strItemId, String strIncludeChunks, String strVersion, String strIsFolder) { logger.debug(String.format("XMLRPC Request. getMetadata [userId: %s, fileId: %s, chunks: %s, version: %s]", strUserId, strItemId, strIncludeChunks, strVersion)); Long fileId = null; try { fileId = Long.parseLong(strItemId); } catch (NumberFormatException ex) { } Boolean isFolder = Boolean.parseBoolean(strIsFolder); Boolean includeChunks = Boolean.parseBoolean(strIncludeChunks); Long version = null; try { version = Long.parseLong(strVersion); } catch (NumberFormatException ex) { } User user = new User(); user.setId(UUID.fromString(strUserId)); APIGetMetadata response = this.apiHandler.getMetadata(user, fileId, includeChunks, version, isFolder); logger.debug(String.format("XMLRPC Response. %s", response.toString())); return response.toString(); } public String getFolderContents(String strUserId, String strFolderId, String strIncludeDeleted) { Boolean includeList = true; logger.debug(String.format("XMLRPC Request. getMetadata [userId: %s, fileId: %s, includeList: %s]", strUserId, strFolderId, includeList, strIncludeDeleted)); Long folderId = null; try { folderId = Long.parseLong(strFolderId); } catch (NumberFormatException ex) { } Boolean includeDeleted = Boolean.parseBoolean(strIncludeDeleted); User user = new User(); user.setId(UUID.fromString(strUserId)); APIGetMetadata response = this.apiHandler.getFolderContent(user, folderId, includeDeleted); logger.debug(String.format("XMLRPC Response. %s", response.toString())); return response.toString(); } public String getVersions(String strUserId, String strFileId) { Long itemId = null; try { itemId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } // TODO: filtrar versiones borradas!! logger.debug("XMLRPC -> get_versions -->[User:" + strUserId + ", itemId:" + itemId + "]"); User user = new User(); user.setId(UUID.fromString(strUserId)); ItemMetadata item = new ItemMetadata(); item.setId(itemId); APIGetVersions response = this.apiHandler.getVersions(user, item); logger.debug("XMLRPC -> resp -->[" + response.toString() + "]"); return response.toString(); } public String newFolder(String strUserId, String strFolderName, String strParentId) { logger.debug(String.format("XMLRPC Request. createFolder [userId: %s, folderName: %s, parentId: %s]", strUserId, strFolderName, strParentId)); Long parentId = null; try { parentId = Long.parseLong(strParentId); } catch (NumberFormatException ex) { } if (strFolderName.length() == 0) { APIResponse response = new APICreateFolderResponse(null, false, 400, "Folder name cannot be empty."); String strResponse = this.parser.createResponse(response); return strResponse; } User user = new User(); user.setId(UUID.fromString(strUserId)); ItemMetadata item = new ItemMetadata(); item.setFilename(strFolderName); item.setIsFolder(true); item.setParentId(parentId); APIResponse response = this.apiHandler.createFolder(user, item); String workspace = response.getItem().getMetadata().getWorkspaceId().toString(); if (response.getSuccess()) { this.sendMessageToClients(workspace, response); } logger.debug("XMLRPC -> resp -->[" + response.toString() + "]"); return response.toString(); } public String newFile(String strUserId, String strFileName, String strParentId, String strChecksum, String strFileSize, String strMimetype, List<String> chunks) { Long parentId = null; try { parentId = Long.parseLong(strParentId); } catch (NumberFormatException ex) { } Long checksum = null; try { checksum = Long.parseLong(strChecksum); } catch (NumberFormatException ex) { } Long fileSize = null; try { fileSize = Long.parseLong(strFileSize); } catch (NumberFormatException ex) { } logger.debug("XMLRPC -> put_metadata_file -->[User:" + strUserId + ", FileName:" + strFileName + ", parentId: " + strParentId + "]"); UUID userId = UUID.fromString(strUserId); APIGetMetadata metadataResponse = getParentMetadata(userId, parentId); APICommitResponse parentResponse = checkParentMetadata(parentId, metadataResponse); if (!parentResponse.getSuccess()) {// error logger.debug("XMLRPC -> Error resp -->[" + parentResponse.toString() + "]"); return parentResponse.toString(); } ItemMetadata item = new ItemMetadata(); item.setId(null); item.setParentId(parentId); item.setTempId(new Random().nextLong()); item.setVersion(1L); item.setDeviceId(Constants.API_DEVICE_ID); item.setIsFolder(false); item.setStatus(Status.NEW.toString()); item.setFilename(strFileName); item.setSize(fileSize); item.setChecksum(checksum); item.setMimetype(strMimetype); item.setModifiedAt(new Date()); item.setChunks(chunks); User user = new User(); user.setId(userId); APICommitResponse response = this.apiHandler.createFile(user, item); if (response.getSuccess()) { this.sendMessageToClients(response.getMetadata().getWorkspaceId().toString(), response); } String strResponse = this.parser.createResponse(response); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String updateData(String strUserId, String strFileId, String strChecksum, String strFileSize, String strMimetype, List<String> chunks) { logger.debug("XMLRPC -> update data -->[User:" + strUserId + ", Checksum: " + strChecksum + ", Filesize: " + strFileSize + ", Mimetype: " + strMimetype + ", Chunks: " + chunks + "]"); Long fileId = null; try { fileId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } Long checksum = null; try { checksum = Long.parseLong(strChecksum); } catch (NumberFormatException ex) { } Long fileSize = null; try { fileSize = Long.parseLong(strFileSize); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); ItemMetadata item = new ItemMetadata(); item.setId(fileId); item.setSize(fileSize); item.setChecksum(checksum); item.setMimetype(strMimetype); item.setChunks(chunks); item.setStatus(Status.CHANGED.toString()); User user = new User(); user.setId(userId); APICommitResponse response = this.apiHandler.updateData(user, item); if (response.getSuccess()) { this.sendMessageToClients(response.getMetadata().getWorkspaceId().toString(), response); } String strResponse = this.parser.createResponse(response); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String updateMetadata(String strUserId, String strFileId, String strNewFileName, String strNewParentId, String strNameUpdated, String strParentUpdated) { logger.debug("XMLRPC -> put_metadata_file -->[User:" + strUserId + ", FileName:" + strNewFileName + ", parentId: " + strNewParentId + "]"); Long parentId = null; try { parentId = Long.parseLong(strNewParentId); } catch (NumberFormatException ex) { } Long fileId = null; try { fileId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); User user = new User(); user.setId(userId); ItemMetadata file = new ItemMetadata(); file.setId(fileId); Boolean newName = Boolean.parseBoolean(strNameUpdated); if (newName){ file.setFilename(strNewFileName); } Boolean parentUpdated = Boolean.parseBoolean(strParentUpdated); if (parentUpdated) { file.setParentId(parentId); } APICommitResponse response = this.apiHandler.updateMetadata(user, file, parentUpdated); if (response.getSuccess()) { this.sendMessageToClients(response.getMetadata().getWorkspaceId().toString(), response); } String strResponse = this.parser.createResponse(response); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String deleteItem(String strUserId, String strFileId, String strIsFolder) { Long fileId = null; try { fileId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } Boolean isFolder = Boolean.parseBoolean(strIsFolder); logger.debug("XMLRPC -> delete_metadata_file -->[User:" + strUserId + ", fileId:" + fileId + "]"); ItemMetadata object = new ItemMetadata(); object.setId(fileId); object.setIsFolder(isFolder); User user = new User(); user.setId(UUID.fromString(strUserId)); APIDeleteResponse response = this.apiHandler.deleteItem(user, object); if (response.getSuccess()) { this.sendMessageToClients(response.getMetadata().getWorkspaceId().toString(), response); } logger.debug("XMLRPC -> resp -->[" + response.toString() + "]"); return response.toString(); } // necessary? public String restoreMetadata(UUID userId, String strRequestId, String strFileId, String strVersion) { Long fileId = null; try { fileId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } Long version = null; try { version = Long.parseLong(strVersion); } catch (NumberFormatException ex) { } logger.debug("XMLRPC -> restore_file -->[User:" + userId + ", Request:" + strRequestId + ", fileId:" + strFileId + ", version: " + strVersion + "]"); String workspace = userId + "/"; ItemMetadata object = new ItemMetadata(); object.setId(fileId); object.setVersion(version); User user = new User(); user.setId(userId); APIRestoreMetadata response = this.apiHandler.restoreMetadata(user, object); String strResponse = this.parser.createResponse(response); if (response.getSuccess()) { this.sendMessageToClients(workspace, response); } logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String shareFolder(String strUserId, String strFolderId, List<String> emails) { logger.debug("XMLRPC -> share_folder -->[User:" + strUserId + ", Folder ID:" + strFolderId + ", Emails: " + emails.toString() + "]"); Long folderId = null; try { folderId = Long.parseLong(strFolderId); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); User user = new User(); user.setId(userId); Item item = new Item(); item.setId(folderId); APIShareFolderResponse response = this.apiHandler.shareFolder(user, item, emails); if (response.getSuccess()) { // FIXME: Do the user-workspace bindings before this.bindUsersToWorkspace(response.getWorkspace(), folderId); } String strResponse = response.toString(); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String unshareFolder(String strUserId, String strFolderId, List<String> emails) { logger.debug("XMLRPC -> unshare_folder --> [User:" + strUserId + ", Folder ID:" + strFolderId + ", Emails: " + emails.toString() + "]"); Long folderId = null; try { folderId = Long.parseLong(strFolderId); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); User user = new User(); user.setId(userId); Item item = new Item(); item.setId(folderId); APIUnshareFolderResponse response = this.apiHandler.unshareFolder(user, item, emails); if (response.getSuccess()) { //FIXME: Do the user-workspace unbindings before this.unBindUsersToWorkspace(response.getWorkspace(), response.getUsersToRemove(), response.isUnshared(), folderId); //this.sendMessageToClients(response.getWorkspace().getId().toString(), response); } String strResponse = response.toString(); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String getFolderMembers(String strUserId, String strFolderId) { logger.debug("XMLRPC -> get_folder_members -->[User:" + strUserId + ", Folder ID:" + strFolderId + "]"); Long folderId = null; try { folderId = Long.parseLong(strFolderId); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); User user = new User(); user.setId(userId); Item item = new Item(); item.setId(folderId); APIGetFolderMembersResponse response = this.apiHandler.getFolderMembers(user, item); String strResponse = response.toString(); logger.debug("XMLRPC -> resp -->[" + strResponse + "]"); return strResponse; } public String getWorkspaceInfo(String strUserId, String strFileId) { logger.debug("XMLRPC -> get workspace info -->[User:" + strUserId + ", File ID: " + strFileId + "]"); Long fileId = null; try { fileId = Long.parseLong(strFileId); } catch (NumberFormatException ex) { } UUID userId = UUID.fromString(strUserId); ItemMetadata item = new ItemMetadata(); item.setId(fileId); User user = new User(); user.setId(userId); APIGetWorkspaceInfoResponse response = this.apiHandler.getWorkspaceInfo(user, item); logger.debug("XMLRPC -> resp --> [" + response.toString() + "]"); return response.toString(); } private APIGetMetadata getParentMetadata(UUID userId, Long parentId) { Boolean includeDeleted = true; User user = new User(); user.setId(userId); APIGetMetadata metadataResponse = this.apiHandler.getFolderContent(user, parentId, includeDeleted); return metadataResponse; } private APICommitResponse checkParentMetadata(Long parentId, APIGetMetadata metadataResponse) { APICommitResponse response = new APICommitResponse(null, true, 0, null); ItemMetadata parentMetadata = metadataResponse.getItemMetadata(); if (parentId != null && parentMetadata == null) { response = new APICommitResponse(null, false, 404, "Parent not found."); } else if (!parentMetadata.isFolder()) { response = new APICommitResponse(null, false, 400, "Incorrect parent."); } else if (!parentMetadata.isRoot() && parentMetadata.getStatus().equals("DELETED")) { response = new APICommitResponse(null, false, 400, "Parent is deleted."); } else if (!metadataResponse.getSuccess()) { response = new APICommitResponse(null, metadataResponse.getSuccess(), metadataResponse.getErrorCode(), metadataResponse.getDescription()); } return response; } private void bindUsersToWorkspace(Workspace workspace, Long folderId) { // Create notification ShareProposalNotification notification = new ShareProposalNotification(workspace.getId(), workspace.getName(), folderId, workspace.getOwner().getId(), workspace.getOwner().getName(), workspace.getSwiftContainer(), workspace.getSwiftUrl(), workspace.isEncrypted()); notification.setRequestId(""); // Send notification to owner RemoteClient client; try { client = broker.lookupMulti(workspace.getOwner().getId().toString(), RemoteClient.class); client.notifyShareProposal(notification); } catch (RemoteException e1) { logger.error(String.format("Could not notify user: '%s'", workspace.getOwner().getId()), e1); } // Send notifications to users for (User addressee : workspace.getUsers()) { try { client = broker.lookupMulti(addressee.getId().toString(), RemoteClient.class); client.notifyShareProposal(notification); } catch (RemoteException e) { logger.error(String.format("Could not notify user: '%s'", addressee.getId()), e); } } } private void unBindUsersToWorkspace(Workspace workspace, List<User> usersToRemove, boolean isUnshared, Long folderId) { // Create notification UnshareNotification notification = new UnshareNotification(workspace.getId(), workspace.getName(), folderId, workspace.getOwner().getId(), workspace.getOwner().getName(), workspace.getSwiftContainer(), workspace.getSwiftUrl(), workspace.isEncrypted()); notification.setRequestId(""); RemoteClient client; // Send notification to owner if (isUnshared) { try { client = broker.lookupMulti(workspace.getOwner().getId().toString(), RemoteClient.class); client.notifyUnshare(notification); } catch (RemoteException e1) { logger.error(String.format("Could not notify user: '%s'", workspace.getOwner().getId()), e1); } } // Send notifications to users for (User addressee : usersToRemove) { try { client = broker.lookupMulti(addressee.getId().toString(), RemoteClient.class); client.notifyUnshare(notification); } catch (RemoteException e) { logger.error(String.format("Could not notify user: '%s'", addressee.getId()), e); } } } private void sendMessageToClients(String workspaceName, APIResponse generalResponse) { CommitInfo info = generalResponse.getItem(); List<CommitInfo> responseObjects = new ArrayList<CommitInfo>(); responseObjects.add(info); CommitNotification result = new CommitNotification("", responseObjects, generalResponse.getQuotaLimit(), generalResponse.getQuotaUsed()); RemoteWorkspace commitNotifier; try { commitNotifier = broker.lookupMulti(workspaceName, RemoteWorkspace.class); commitNotifier.notifyCommit(result); } catch (RemoteException e) { // e.printStackTrace(); logger.error("Error sending the notification to the clients: " + e); } } }