diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/transfer/transfer.post.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/transfer/transfer.post.desc.xml new file mode 100644 index 0000000000..c6948d8dff --- /dev/null +++ b/config/alfresco/templates/webscripts/org/alfresco/repository/transfer/transfer.post.desc.xml @@ -0,0 +1,8 @@ + + Node Transfer Service + Invoke commands on the Node Transfer Service + /api/transfer/{command} + + admin + required + diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml index 8cdb8197ea..f42a5d4c1f 100644 --- a/config/alfresco/web-scripts-application-context.xml +++ b/config/alfresco/web-scripts-application-context.xml @@ -634,7 +634,52 @@ - + + + ${transferservice.receiver.enabled} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/AbortTransferCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/AbortTransferCommandProcessor.java new file mode 100644 index 0000000000..6b2a76dec9 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/AbortTransferCommandProcessor.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.StringWriter; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This command processor is used to record the start a transfer. No other transfer can be started after this command + * has executed until the started transfer terminates. + * + * @author brian + * + */ +public class AbortTransferCommandProcessor implements CommandProcessor +{ + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private TransferReceiver receiver; + + private static Log logger = LogFactory.getLog(AbortTransferCommandProcessor.class); + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco .web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + String transferRecordId = null; + + //Read the transfer id from the request + HttpServletRequest servletRequest = ((WebScriptServletRequest)req).getHttpServletRequest(); + String transferId = servletRequest.getParameter("transferId"); + + if ((transferId == null)) + { + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + try + { + logger.debug("abort transfer:" + transferId); + + receiver.abort(transferId); + + // return the unique transfer id (the lock id) + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + jsonWriter.startObject(); + jsonWriter.writeValue("transferId", transferRecordId); + jsonWriter.endObject(); + String response = stringWriter.toString(); + + resp.setContentType("application/json"); + resp.setContentEncoding("UTF-8"); + int length = response.getBytes("UTF-8").length; + resp.addHeader("Content-Length", "" + length); + resp.setStatus(Status.STATUS_OK); + resp.getWriter().write(response); + + return Status.STATUS_OK; + + } + catch (Exception ex) + { + logger.debug("caught exception", ex); + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/BeginTransferCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/BeginTransferCommandProcessor.java new file mode 100644 index 0000000000..4579ff31d5 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/BeginTransferCommandProcessor.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.StringWriter; + +import org.alfresco.repo.transfer.RepoTransferReceiverImpl; +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This command processor is used to record the start a transfer. No other transfer can be started after this command + * has executed until the started transfer terminates. + * + * @author brian + * + */ +public class BeginTransferCommandProcessor implements CommandProcessor +{ + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private TransferReceiver receiver; + + private final static Log logger = LogFactory.getLog(BeginTransferCommandProcessor.class); + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco .web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + String transferId = null; + try + { + // attempt to take the transfer lock + transferId = receiver.start(); + + // Create a temporary folder into which we can place transferred files + receiver.getStagingFolder(transferId); + + // return the unique transfer id (the lock id) + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + jsonWriter.startObject(); + jsonWriter.writeValue("transferId", transferId); + jsonWriter.endObject(); + String response = stringWriter.toString(); + + resp.setContentType("application/json"); + resp.setContentEncoding("UTF-8"); + int length = response.getBytes("UTF-8").length; + resp.addHeader("Content-Length", "" + length); + resp.setStatus(Status.STATUS_OK); + resp.getWriter().write(response); + + logger.debug("transfer started" + transferId); + + return Status.STATUS_OK; + + } catch (Exception ex) + { + logger.debug("exception caught", ex); + if(transferId != null) + { + logger.debug("ending transfer", ex); + receiver.end(transferId); + } + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/CommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/CommandProcessor.java new file mode 100644 index 0000000000..39cde3b98d --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/CommandProcessor.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; + +/** + * @author brian + * + */ +public interface CommandProcessor +{ + int process(WebScriptRequest req, WebScriptResponse resp); +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/CommitTransferCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/CommitTransferCommandProcessor.java new file mode 100644 index 0000000000..03902e1f03 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/CommitTransferCommandProcessor.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.StringWriter; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This command processor is used to record the start a transfer. No other transfer can be started after this command + * has executed until the started transfer terminates. + * + * @author brian + * + */ +public class CommitTransferCommandProcessor implements CommandProcessor +{ + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private static Log logger = LogFactory.getLog(CommitTransferCommandProcessor.class); + + private TransferReceiver receiver; + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco .web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + + //Read the transfer id from the request + HttpServletRequest servletRequest = ((WebScriptServletRequest)req).getHttpServletRequest(); + String transferId = servletRequest.getParameter("transferId"); + + if ((transferId == null)) + { + logger.debug("transferId is missing"); + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + try + { + receiver.commit(transferId); + + // return the unique transfer id (the lock id) + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + jsonWriter.startObject(); + jsonWriter.writeValue("transferId", transferId); + jsonWriter.endObject(); + String response = stringWriter.toString(); + + resp.setContentType("application/json"); + resp.setContentEncoding("UTF-8"); + int length = response.getBytes("UTF-8").length; + resp.addHeader("Content-Length", "" + length); + resp.setStatus(Status.STATUS_OK); + resp.getWriter().write(response); + + logger.debug("committed transferId:" + transferId); + + return Status.STATUS_OK; + } + catch (Exception ex) + { + logger.debug("caught exception :" + ex.toString(), ex); + + //TODO Think very carefully about this. + //TODO MER I think we need to roll forward here since we are after prepare. + receiver.end(transferId); + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/MessagesTransferCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/MessagesTransferCommandProcessor.java new file mode 100644 index 0000000000..7c04a5b15c --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/MessagesTransferCommandProcessor.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.StringWriter; + +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; + +/** + * This command processor is used to record the start a transfer. No other transfer can be started after this command + * has executed until the started transfer terminates. + * + * @author brian + * + */ +public class MessagesTransferCommandProcessor implements CommandProcessor +{ + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private TransferReceiver receiver; + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco .web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + String transferRecordId = null; + try + { + // return the unique transfer id (the lock id) + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + + jsonWriter.startValue("data"); + + jsonWriter.startArray(); + jsonWriter.startObject(); + //TODO - clearly a dummy message for now. + jsonWriter.writeValue("message", "hello world"); + jsonWriter.endObject(); + jsonWriter.startObject(); + //TODO - clearly a dummy message for now. + jsonWriter.writeValue("message", "message2"); + jsonWriter.endObject(); + jsonWriter.endArray(); + jsonWriter.endValue(); + String response = stringWriter.toString(); + + resp.setContentType("application/json"); + resp.setContentEncoding("UTF-8"); + int length = response.getBytes("UTF-8").length; + resp.addHeader("Content-Length", "" + length); + resp.setStatus(Status.STATUS_OK); + resp.getWriter().write(response); + + return Status.STATUS_OK; + + } catch (Exception ex) + { + receiver.end(transferRecordId); + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/PostContentCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/PostContentCommandProcessor.java new file mode 100644 index 0000000000..0cd6db4ad8 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/PostContentCommandProcessor.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.alfresco.web.scripts.servlet.FormData.FormField; +import org.apache.commons.fileupload.FileItemIterator; +import org.apache.commons.fileupload.FileItemStream; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This command processor is used to receive one or more content files for a given transfer. + * + * @author brian + * + */ +public class PostContentCommandProcessor implements CommandProcessor +{ + private TransferReceiver receiver; + + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private static Log logger = LogFactory.getLog(PostContentCommandProcessor.class); + + /** + * @param receiver + * the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + logger.debug("post content start"); + if (!WebScriptServletRequest.class.isAssignableFrom(req.getClass())) + { + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + HttpServletRequest servletRequest = ((WebScriptServletRequest) req).getHttpServletRequest(); + + //Read the transfer id from the request + String transferId = servletRequest.getParameter("transferId"); + + if ((transferId == null) || !ServletFileUpload.isMultipartContent(servletRequest)) + { + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + try + { + //TODO - See comments on PostSnapshotCommandProcessor RE WebScript framework + // ServletFileUpload upload = new ServletFileUpload(); + // FileItemIterator iter = upload.getItemIterator(servletRequest); + // while (iter.hasNext()) + // { + // FileItemStream item = iter.next(); + // if (!item.isFormField() && "content".equals(item.getFieldName())) + // { + // receiver.saveContent(transferId, item.getName(), item.openStream()); + // } + // } + // + + WebScriptServletRequest alfRequest = (WebScriptServletRequest)req; + String[] names = alfRequest.getParameterNames(); + for(String name : names) + { + FormField item = alfRequest.getFileField(name); + + if(item != null) + { + logger.debug("got content Mime Part : " + name); + receiver.saveContent(transferId, item.getName(), item.getInputStream()); + } + else + { + //TODO - should this be an exception? + logger.debug("Unable to get content for Mime Part : " + name); + } + } + + logger.debug("success"); + + resp.setStatus(Status.STATUS_OK); + } + catch (Exception ex) + { + logger.debug("exception caught", ex); + if(transferId != null) + { + logger.debug("ending transfer", ex); + receiver.end(transferId); + } + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + + } + + resp.setStatus(Status.STATUS_OK); + return Status.STATUS_OK; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/PostSnapshotCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/PostSnapshotCommandProcessor.java new file mode 100644 index 0000000000..2c2e6f7771 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/PostSnapshotCommandProcessor.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.repo.transfer.TransferCommons; +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.alfresco.web.scripts.servlet.FormData.FormField; +import org.apache.commons.fileupload.FileItemIterator; +import org.apache.commons.fileupload.FileItemStream; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This command processor is used to receive the snapshot for a given transfer. + * + * @author brian + * + */ +public class PostSnapshotCommandProcessor implements CommandProcessor +{ + private TransferReceiver receiver; + + private static Log logger = LogFactory.getLog(PostSnapshotCommandProcessor.class); + + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + + int result = Status.STATUS_OK; + if (!WebScriptServletRequest.class.isAssignableFrom(req.getClass())) + { + logger.debug("bad request, not assignable from"); + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + //We can't use the WebScriptRequest version of getParameter, since that may cause the content stream + //to be parsed. Get hold of the raw HttpServletRequest and work with that. + HttpServletRequest servletRequest = ((WebScriptServletRequest)req).getHttpServletRequest(); + + //Read the transfer id from the request + String transferId = servletRequest.getParameter("transferId"); + + if ((transferId == null) || !ServletFileUpload.isMultipartContent(servletRequest)) + { + logger.debug("bad request, not multipart"); + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + try + { + logger.debug("about to upload manifest file"); + + // OLD implenementation + // ServletFileUpload upload = new ServletFileUpload(); + // FileItemIterator iter = upload.getItemIterator(servletRequest); + // while (iter.hasNext()) + // { + // FileItemStream item = iter.next(); + // if (!item.isFormField() && "manifest".equals(item.getFieldName())) + // { + // logger.debug("save snapshot content item"); + // receiver.saveSnapshot(transferId, item.openStream()); + // // receiver.saveContent(transferId, item.getName(), item.openStream()); + // } + // } + + // Work Around impelemtation with an implementation that uses FormData + // This has the side effect that the content is written to disk and parsed twice. + // Needs reworking but requires changes to the WebScript framework + // MER - Brian and Kevin to discuss + WebScriptServletRequest alfRequest = (WebScriptServletRequest)req; + FormField field = alfRequest.getFileField(TransferCommons.PART_NAME_MANIFEST); + + if(field != null) + { + logger.debug("got manifest file"); + receiver.saveSnapshot(transferId, field.getInputStream()); + } + else + { + logger.debug("manifest is missing"); + } + + logger.debug("success"); + resp.setStatus(Status.STATUS_OK); + } + catch (Exception ex) + { + logger.debug("exception caught", ex); + if(transferId != null) + { + logger.debug("ending transfer", ex); + receiver.end(transferId); + } + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + return result; + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/PrepareTransferCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/PrepareTransferCommandProcessor.java new file mode 100644 index 0000000000..d963932ded --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/PrepareTransferCommandProcessor.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.StringWriter; + +import javax.servlet.http.HttpServletRequest; + +import org.alfresco.repo.transfer.TransferServiceImpl; +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.service.cmr.transfer.TransferReceiver; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; +import org.alfresco.web.scripts.servlet.WebScriptServletRequest; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author mrogers + * + */ +public class PrepareTransferCommandProcessor implements CommandProcessor +{ + private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception"; + + private static Log logger = LogFactory.getLog(PrepareTransferCommandProcessor.class); + + private TransferReceiver receiver; + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco .web.scripts.WebScriptRequest, + * org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + String transferRecordId = null; + + //Read the transfer id from the request + HttpServletRequest servletRequest = ((WebScriptServletRequest)req).getHttpServletRequest(); + String transferId = servletRequest.getParameter("transferId"); + + if (transferId == null) + { + logger.debug("transferId is missing"); + resp.setStatus(Status.STATUS_BAD_REQUEST); + return Status.STATUS_BAD_REQUEST; + } + + try + { + logger.debug("prepare transferId: " + transferId); + receiver.prepare(transferId); + + // return the unique transfer id (the lock id) + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + jsonWriter.startObject(); + jsonWriter.writeValue("transferId", transferRecordId); + jsonWriter.endObject(); + String response = stringWriter.toString(); + + resp.setContentType("application/json"); + resp.setContentEncoding("UTF-8"); + int length = response.getBytes("UTF-8").length; + resp.addHeader("Content-Length", "" + length); + resp.setStatus(Status.STATUS_OK); + resp.getWriter().write(response); + + logger.debug("prepared transferId: " + transferId); + + return Status.STATUS_OK; + } + catch (Exception ex) + { + logger.debug("in exception handler", ex); + receiver.end(transferRecordId); + if (ex instanceof TransferException) + { + throw (TransferException) ex; + } + throw new TransferException(MSG_CAUGHT_UNEXPECTED_EXCEPTION, ex); + } + } + + /** + * @param receiver the receiver to set + */ + public void setReceiver(TransferReceiver receiver) + { + this.receiver = receiver; + } + + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/TestCredentialsCommandProcessor.java b/source/java/org/alfresco/repo/web/scripts/transfer/TestCredentialsCommandProcessor.java new file mode 100644 index 0000000000..bcde3c3cdf --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/TestCredentialsCommandProcessor.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; + +/** + * This command processor is used simply to check that the transfer receiver is enabled and that the supplied + * credentials are correct and identify an admin user. + * + * @author brian + * + */ +public class TestCredentialsCommandProcessor implements CommandProcessor +{ + + /* (non-Javadoc) + * @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public int process(WebScriptRequest req, WebScriptResponse resp) + { + //Since all the checks that are needed are actually carried out by the transfer web script, this processor + //effectively becomes a no-op. + int result = Status.STATUS_OK; + resp.setStatus(result); + return result; + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScript.java b/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScript.java new file mode 100644 index 0000000000..51442fd90f --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScript.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2009-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +package org.alfresco.repo.web.scripts.transfer; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; +import java.util.TreeMap; + +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.transfer.TransferException; +import org.alfresco.web.scripts.AbstractWebScript; +import org.alfresco.web.scripts.Status; +import org.alfresco.web.scripts.WebScriptRequest; +import org.alfresco.web.scripts.WebScriptResponse; +import org.alfresco.web.scripts.json.JSONWriter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author brian + * + */ +public class TransferWebScript extends AbstractWebScript +{ + private static final Log log = LogFactory.getLog(TransferWebScript.class); + + private boolean enabled = true; + private Map processors = new TreeMap(); + + + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + public void setCommandProcessors(Map processors) + { + this.processors = new TreeMap(processors); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScript#execute(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) + */ + public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException + { + if (enabled) + { + log.debug("Transfer webscript invoked by user: " + AuthenticationUtil.getFullyAuthenticatedUser() + + " running as " + AuthenticationUtil.getRunAsAuthentication().getName()); + processCommand(req.getServiceMatch().getTemplateVars().get("command"), req, res); + } + else + { + res.setStatus(Status.STATUS_NOT_FOUND); + } + } + + /** + * @param command + * @param req + * @param res + */ + private void processCommand(String command, WebScriptRequest req, WebScriptResponse res) + { + log.debug("Received request to process transfer command: " + command); + if (command == null || (command = command.trim()).length() == 0) + { + log.warn("Empty or null command received by the transfer script. Returning \"Not Found\""); + res.setStatus(Status.STATUS_NOT_FOUND); + } + else + { + CommandProcessor processor = processors.get(command); + if (processor != null) + { + log.debug("Found appropriate command processor: " + processor); + try + { + processor.process(req, res); + log.debug("command processed"); + } + catch (TransferException ex) + { + try + { + log.debug("transfer exception caught", ex); + res.setStatus(Status.STATUS_INTERNAL_SERVER_ERROR); + String error = writeError(ex); + + res.setContentType("application/json"); + res.setContentEncoding("UTF-8"); + int length = error.getBytes("UTF-8").length; + res.addHeader("Content-Length", "" + length); + + res.getWriter().write(error); + } + catch (Exception e) + { + //nothing to do at this point really. + } + } + } + else + { + log.warn("No processor found for requested command: " + command + ". Returning \"Not Found\""); + res.setStatus(Status.STATUS_NOT_FOUND); + } + } + } + + /** + * @param ex + * @return + */ + private String writeError(TransferException ex) throws IOException + { + StringWriter stringWriter = new StringWriter(300); + JSONWriter jsonWriter = new JSONWriter(stringWriter); + jsonWriter.startObject(); + jsonWriter.writeValue("errorId", ex.getMsgId()); + jsonWriter.startValue("errorParams"); + jsonWriter.startArray(); + writeErrorParams(stringWriter, ex.getMsgParams()); + jsonWriter.endArray(); + jsonWriter.endObject(); + return stringWriter.toString(); + } + + /** + * @param stringWriter + * @param msgParams + */ + private void writeErrorParams(StringWriter writer, Object[] msgParams) + { + if (msgParams == null) return; + + boolean first = true; + for (Object param : msgParams) { + if (!first) { + writer.write(","); + } + if (param != null) { + writer.write("\""); + writer.write(JSONWriter.encodeJSONString(param.toString())); + writer.write("\""); + } else { + writer.write("null"); + } + first = false; + } + } + +} diff --git a/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScriptTest.java b/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScriptTest.java new file mode 100644 index 0000000000..9a658042f6 --- /dev/null +++ b/source/java/org/alfresco/repo/web/scripts/transfer/TransferWebScriptTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.web.scripts.transfer; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.web.scripts.BaseWebScriptTest; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.util.PropertyMap; +import org.alfresco.web.scripts.TestWebScriptServer.PostRequest; +import org.json.JSONObject; + +/** + * Test the transfer web script API + * + * @author brian + */ +public class TransferWebScriptTest extends BaseWebScriptTest +{ + private static final String USERNAME = "noddy.transfer"; + + private AuthenticationService authenticationService; + private AuthenticationComponent authenticationComponent; + private PersonService personService; + private List createdPeople = new ArrayList(5); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); + this.authenticationService = (AuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService"); + this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent"); + this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService"); + + this.authenticationComponent.setSystemUserAsCurrentUser(); + + // Create users + createUser(USERNAME); + } + + private void createUser(String userName) + { + if (this.authenticationService.authenticationExists(userName) == false) + { + this.authenticationService.createAuthentication(userName, "password".toCharArray()); + + PropertyMap personProps = new PropertyMap(); + personProps.put(ContentModel.PROP_USERNAME, userName); + personProps.put(ContentModel.PROP_FIRSTNAME, "myFirstName"); + personProps.put(ContentModel.PROP_LASTNAME, "myLastName"); + personProps.put(ContentModel.PROP_EMAIL, "myFirstName.myLastName@email.com"); + personProps.put(ContentModel.PROP_JOBTITLE, "myJobTitle"); + personProps.put(ContentModel.PROP_JOBTITLE, "myOrganisation"); + + this.personService.createPerson(personProps); + + this.createdPeople.add(userName); + } + } + + @Override + protected void tearDown() throws Exception + { + super.tearDown(); + String adminUser = this.authenticationComponent.getSystemUserName(); + this.authenticationComponent.setCurrentUser(adminUser); + + for (String userName : this.createdPeople) + { + personService.deletePerson(userName); + } + // Clear the list + this.createdPeople.clear(); + } + + + public void testVerify() throws Exception + { + String url = "/api/transfer/test"; + PostRequest req = new PostRequest(url, new JSONObject().toString(), "application/json"); + + //First, we'll try the request as a simple, non-admin user (expect a 401) + AuthenticationUtil.setFullyAuthenticatedUser(USERNAME); + sendRequest(req, 401); + + //Then we'll have a go as the system user (expect a 200) + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.SYSTEM_USER_NAME); + sendRequest(req, 200); + + //Then we'll disable the transfer receiver and try again as the system user (expect a 404) + TransferWebScript webscript = (TransferWebScript)getServer().getApplicationContext().getBean("webscript.org.alfresco.repository.transfer.transfer.post"); + webscript.setEnabled(false); + sendRequest(req, 404); + } + +}