cancel
Showing results for 
Search instead for 
Did you mean: 

Upload webscript not waiting for completion

kmartino
Champ in-the-making
Champ in-the-making
Hello,

We are having an issue uploading files using a Webscript and accesing them immediately afterwards.

We are using Enterprise 3.1 and the WCM. 

The Webscript uploads an assset (in this scenario - an image) to a user's sandbox.

Immediately following recieving a 200 response code we call an out of the box Alfresco Webscript to download
the image to the client.

This second webscript returns a 404 sometimes and upon subsequent calls returns a 200 with the image.

It *appears* that there is a timing issue - that the upload Webscript is returning a 200 to the client, even
though it has not yet completed.

Here is the configuration for the upload Webscript (note that the type and mode arguments are "file" and that we are doing additional computation to determine a prefix to the file name path):

<webscript>
   <shortname>Add/Update Content</shortname>
   <description>Upload file content into Repository</description>
   <url>/comcast/webprojects/{webprojectref}/sandboxes/{sandboxref}/upload/{path}</url>
   <format default="xml">argument</format>
   <authentication>user</authentication>
   <transaction>required</transaction>
   <family>CIM Repository</family>
</webscript>

Here is the Webscript Javascript:

/*
* classpath extension import
   <import resource="/Company Home/Data Dictionary/Web Scripts Extensions/net/comcast/cim/cms/wcm/associate.lib.js">
   <import resource="classpath:alfresco/extension/templates/webscripts/net/comcast/cim/cms/wcm/associate.lib.js"> */

function main() {

   // parse the query string parameters
   var urlElements = url.extension.split("/");
   var shortName = urlElements[0];
   var boxName = urlElements[2];
   var pathArray = urlElements.slice(4);
   var path = pathArray.join("/");

   // get the specified web project
   var webproject = webprojects.getWebProject(shortName);
   if (webproject == null) {
      // web project cannot be found
      status.setCode(status.STATUS_NOT_FOUND, "The webproject, " + shortName + ", does not exist.");
      return;
   }

   // get the specified sandbox
   var sandbox = webproject.getSandbox(boxName);
   if (sandbox == null) {
      // sandbox cannot be found
      status.setCode(status.STATUS_NOT_FOUND, "The sandbox, " + boxName + ", in webproject, "  +  shortName + ", does not exist.");
      return;
   }

   // instantiate objects for form request parameters
   var filename_f = "";
   var filename_d = "";
   var content = "";
   var overwrite = false;
   var webApp = "";
   var type = "file";
   var mode = "file";
   var foldername = "";
   var data = "";

   // variable indicates whether the content contains feed injection on publish
   var feed = false;
   // variable indicates the guid prefix for the content to be stored.
   // default format is [timestamp]-[userid]
   var guid = "";
   
   // parse form request parameters
   for each (field in formdata.fields) {
      if (field.name == "guid") {
         if (field.value != "") {
            guid = field.value;
         } else {
            guid = (new Date()).getTime() + "-" + person.properties.userName;
         }
      } else if (field.name == "feed") {
         if (field.value == "true") {
            feed = true;
         }
      } else if (field.name == "webApp") {
         webApp = field.value;
      } else if (field.name == "overwrite") {
         if (field.value == "true") {
            overwrite = true;
         }
      } else if (field.name == "file" && field.isFile) {
         filename_f = field.filename;
         content = field.content;
      } else if (field.name == "type") {
         if (field.value == "folder") {
            type = "folder";
         } else if (field.value == "content") {
            type = "content";
         }
      } else if (field.name == "mode") {
         if (field.value == "file") {
            mode = "file";
         } else if (field.value == "data") {
            mode = "data";
         }
      } else if (field.name == "filename") {
         filename_d = field.value;
      } else if (field.name == "data") {
         data = field.value;
      } else if (field.name == "foldername") {
         foldername = field.value;
      }
   }

   var prefix = "";

   if (type != "file") {
      prefix = "content";
      if (feed) {
         guid = guid + "-f";
      }
      if (path == "") {
         path = "/" + prefix + "/" + guid;
      } else {
         path = "/" + prefix + "/" + guid + "/" + path;
      }
   }

   if (path == "") {
      path = "/";
   }

   // get the parent object
   var parent = null;
   if (webApp != null) {
      parent = sandbox.getAssetWebApp(webApp, path);
   } else {
      parent = sandbox.getAsset(path);
   }

   // make sure the parent exists, if not create the folder structure
   if (parent == null) {
      var p = "/";
      var pNode = sandbox.getAssetWebApp(webApp, p);

      if (type != "file") {
         var tempNode = sandbox.getAssetWebApp(webApp, p + prefix);
         if (tempNode == null) {
            pNode.createFolder(prefix);
         }
         
         p = p + prefix;
         pNode = sandbox.getAssetWebApp(webApp, p);
         tempNode = sandbox.getAssetWebApp(webApp, p + "/" + guid);
         if (tempNode == null) {
            pNode.createFolder(guid);
         }
         
         p = p + "/" + guid;      
         pNode = sandbox.getAssetWebApp(webApp, p);
      }
      
      for (i = 0; i < pathArray.length; i++) {
         tempNode = sandbox.getAssetWebApp(webApp, p + "/" + pathArray[i]);         
         if (tempNode == null) {
            pNode.createFolder(pathArray[i]);
         }

         p = p + "/" + pathArray[i];
         pNode = sandbox.getAssetWebApp(webApp, p);
      }      
      parent = pNode;
  }

   // determine if need to create a file or folder
   if (type == "file" || (type == "content" && mode == "file")) {
      var filename = filename_f;
      
      // ensure mandatory file attributes have been specified
      if (filename == undefined || content == undefined) {
         status.setCode(status.STATUS_BAD_REQUEST, "Posted file cannot be located in request");
         return;
      } else {
         // ensure folder or file with the same name does not exist
         var file = avm.lookupNode(boxName + ":/" + parent.path + "/" + filename);   
         if (file != null) {
            if (!file.isFile()) {
               status.setCode(status.STATUS_FORBIDDEN, "A non-file content with the same name exists.");
               return;
            } else if (!overwrite) {
               status.setCode(status.STATUS_FORBIDDEN, "Cannot overwrite existing file.");
               return;
            }
         } else {
            // create an empty file
            parent.createFile(filename, "");
            file = avm.lookupNode(boxName + ":/" + parent.path + "/" + filename)
         }

         // update the new file with relevant content and properties
         file.properties.content.write(content);
         file.properties.content.guessMimetype(filename);
         file.properties.content.setEncoding("UTF-8");
         file.save();

         // put the newly created file into the model
         model.node = file;
         model.guid = guid;
         model.feed = feed;
      }

   } else if (type == "content" && mode == "data") {

      var filename = filename_d;
      
      // ensure mandatory file attributes have been specified
      if (filename == undefined || data == undefined) {
         status.setCode(status.STATUS_BAD_REQUEST, "Posted filename or data cannot be located in request");
         return;
      } else {
         // ensure folder or file with the same name does not exist
         var file = avm.lookupNode(boxName + ":/" + parent.path + "/" + filename);   
         if (file != null) {
            if (!file.isFile()) {
               status.setCode(status.STATUS_FORBIDDEN, "A non-file content with the same name exists.");
               return;
            } else if (!overwrite) {
               status.setCode(status.STATUS_FORBIDDEN, "Cannot overwrite existing file.");
               return;
            }
         } else {
            // create file with data
            parent.createFile(filename, "");
            file = avm.lookupNode(boxName + ":/" + parent.path + "/" + filename)
         }

         // update the new file with relevant content and properties
         file.content = data;
         file.properties.content.guessMimetype(filename);
         file.properties.content.setEncoding("UTF-8");
         file.save();

         model.node = file;
         model.guid = guid;
         model.feed = feed;
      }

   } else if (type == "folder") {
      // endure mandatory folder attributes have been specified
      if (foldername == "") {
         status.setCode(status.STATUS_BAD_REQUEST, "Folder Name is not specified");
         return;
      } else {
         // ensure folder or file with the same name does not exist
         var folder = avm.lookupNode(boxName + ":/" + parent.path + "/" + foldername);
         if (folder != null) {
            status.setCode(status.STATUS_FORBIDDEN, "Folder/File with the same name already exists.");
            return;
         }

         // create the folder
         parent.createFolder(foldername);
         // put the newly created folder into the model
         folder = avm.lookupNode(boxName + ":/" + parent.path + "/" + foldername);         
         model.node = folder;
      }
   }
}

main()

Here is the freemarker output (and form - although we are calling this from an external client):

<?xml version="1.0" encoding="UTF-8"?>
<node>
   <properties>
      <name>${node.name}</name>
      <id>${node.id}</id>
      <url>${node.displayPath}/${node.name}</url>
      <isFolder>${node.isContainer?string("true", "false")}</isFolder>
      <#if !node.isContainer>
         <#if guid?exists><guid>${guid}</guid></#if>
         <#if feed?exists><feed>${feed?string("true", "false")}</feed></#if>
         <mimetype>${node.mimetype}</mimetype>
         <encoding>${node.encoding}</encoding>
         <size>${node.size}</size>
         <downloadUrl>${url.serviceContext}/api/path/content/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}${node.displayPath}/${node.name}</downloadUrl>
      </#if>
   </properties>
</node>

The first Webscript call, the one to upload, returns a 200 as mentioned.  Here is a sample response:

<node> 
   <properties>
      <name>0c49ff9002c309713a8e26210b6c37fc.jpg</name>
      <id>-1;www;avm_webapps;ROOT;rendition;1111111111111-images;cachesvc;api;assets;bin-201002;0c49ff9002c309713a8e26210b6c37fc.jpg</id>
      <url>/www/avm_webapps/ROOT/rendition/1111111111111-images/cachesvc/api/assets/bin-201002/0c49ff9002c309713a8e26210b6c37fc.jpg</url>
      <isFolder>false</isFolder>
      <guid />
      <feed>false</feed>
      <mimetype>image/jpeg</mimetype>
      <encoding>UTF-8</encoding>
      <size>993,681</size>
      <downloadUrl>/alfresco/service/api/path/content/avm/cim–kmartino/www/avm_webapps/ROOT/rendition/1111111111111-images/cachesvc/api/assets/bin-201002/0c49ff9002c309713a8e26210b6c37fc.jpg</downloadUrl>
   </properties>
</node>

We then use the downloadUrl to call that Webscript to get the file.

Here goes a call sample using the above downloadURL:

http://local.comcast.net:8080/alfresco/service/api/path/content/avm/cim--kmartino/www/avm_webapps/RO...

It could be on a local machine or on a dev server - makes no difference.  This call will return a 404 sometimes, and sometimes it will return the image. 

On 404's - if you call it again a few seconds later - you get the image and a 200.

Any help you could provide would be appreciated,

Thank you,

Karl
2 REPLIES 2

kevinr
Star Contributor
Star Contributor
Hi,

I've had a poke around in the svn archives, and the fix for that issue is in 3.2 Community and 3.2 Enterprise.

Although webscripts supported transactions in 3.1, it was possible to "break" it with a large response size - and the result begin to return before the transaction had committed OR rolled back. This was fixed by buffering the response if required. If this is the issue you are seeing it might be worth trying your code on 3.2.

Thanks,

Kevin

kmartino
Champ in-the-making
Champ in-the-making
Hello Kevin,

Thanks for looking into this.  I'll give 3.2 a shot and report back.

Karl