diff --git a/config/alfresco/bootstrap/webScripts2.xml b/config/alfresco/bootstrap/webScripts2.xml
new file mode 100644
index 0000000000..7a78f00f1b
--- /dev/null
+++ b/config/alfresco/bootstrap/webScripts2.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ contentUrl=classpath:alfresco/bootstrap/webscripts/upload.get.desc.xml|mimetype=text/xml|size=|encoding=UTF-8|locale=en_US_
+
+
+ upload.get.desc.xml
+
+
+
+
+
+
+
+
+
+ true
+ contentUrl=classpath:alfresco/bootstrap/webscripts/upload.get.html.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_
+
+
+ upload.get.html.ftl
+
+
+
+
+
+
+
+
+
+ true
+ contentUrl=classpath:alfresco/bootstrap/webscripts/upload.post.desc.xml|mimetype=text/xml|size=|encoding=UTF-8|locale=en_US_
+
+
+ upload.post.desc.xml
+
+
+
+
+
+
+
+
+
+ true
+ contentUrl=classpath:alfresco/bootstrap/webscripts/upload.post.js|mimetype=application/x-javascript|size=|encoding=UTF-8|locale=en_US_
+
+
+ upload.post.js
+
+
+
+
+
+
+
+
+
+ true
+ contentUrl=classpath:alfresco/bootstrap/webscripts/upload.post.html.ftl|mimetype=text/plain|size=|encoding=UTF-8|locale=en_US_
+
+
+ upload.post.html.ftl
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/bootstrap/webscripts/upload.get.desc.xml b/config/alfresco/bootstrap/webscripts/upload.get.desc.xml
new file mode 100644
index 0000000000..cb51741f97
--- /dev/null
+++ b/config/alfresco/bootstrap/webscripts/upload.get.desc.xml
@@ -0,0 +1,6 @@
+
+ File Upload Form Sample
+ Form for uploading file content and meta-data into Repository
+ /sample/upload
+ user
+
\ No newline at end of file
diff --git a/config/alfresco/bootstrap/webscripts/upload.get.html.ftl b/config/alfresco/bootstrap/webscripts/upload.get.html.ftl
new file mode 100644
index 0000000000..4dffeaf35c
--- /dev/null
+++ b/config/alfresco/bootstrap/webscripts/upload.get.html.ftl
@@ -0,0 +1,27 @@
+
+
+
+
+ Upload Web Script Sample
+
+
+
+
+
+  |
+ Upload Web Script Sample |
+
+ | Alfresco ${server.edition} v${server.version}
+ |
+
+
+
+
diff --git a/config/alfresco/bootstrap/webscripts/upload.post.desc.xml b/config/alfresco/bootstrap/webscripts/upload.post.desc.xml
new file mode 100644
index 0000000000..94edc2e90f
--- /dev/null
+++ b/config/alfresco/bootstrap/webscripts/upload.post.desc.xml
@@ -0,0 +1,6 @@
+
+ File Upload Sample
+ Upload file content and meta-data into Repository
+ /sample/upload
+ user
+
\ No newline at end of file
diff --git a/config/alfresco/bootstrap/webscripts/upload.post.html.ftl b/config/alfresco/bootstrap/webscripts/upload.post.html.ftl
new file mode 100644
index 0000000000..aaa4a0e033
--- /dev/null
+++ b/config/alfresco/bootstrap/webscripts/upload.post.html.ftl
@@ -0,0 +1,19 @@
+
+
+
+
+ Upload Web Script Sample
+
+
+
+
+
+  |
+ Upload Web Script Sample |
+
+ | Alfresco ${server.edition} v${server.version}
+ |
|
+ |
| Uploaded ${upload.name} of size ${upload.properties.content.size}.
+ |
+
+
diff --git a/config/alfresco/bootstrap/webscripts/upload.post.js b/config/alfresco/bootstrap/webscripts/upload.post.js
new file mode 100644
index 0000000000..d1337ff1c5
--- /dev/null
+++ b/config/alfresco/bootstrap/webscripts/upload.post.js
@@ -0,0 +1,43 @@
+var filename = null;
+var content = null;
+var title = "";
+var description = "";
+
+// locate file attributes
+for each (field in formdata.fields)
+{
+ if (field.name == "title")
+ {
+ title = field.value;
+ }
+ else if (field.name == "desc")
+ {
+ description = field.value;
+ }
+ else if (field.name == "file" && field.isFile)
+ {
+ filename = field.filename;
+ content = field.content;
+ }
+}
+
+// ensure mandatory file attributes have been located
+if (filename == undefined || content == undefined)
+{
+ status.code = 400;
+ status.message = "Uploaded file cannot be located in request";
+ status.redirect = true;
+}
+else
+{
+ // create document in company home for uploaded file
+ upload = companyhome.createFile("upload" + companyhome.children.length + "_" + filename) ;
+ upload.properties.content.write(content);
+ upload.properties.content.mimetype = "UTF-8";
+ upload.properties.title = title;
+ upload.properties.description = description;
+ upload.save();
+
+ // setup model for response template
+ model.upload = upload;
+}
\ No newline at end of file
diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties
index 5e1046dcc6..6bf835d84e 100644
--- a/config/alfresco/messages/patch-service.properties
+++ b/config/alfresco/messages/patch-service.properties
@@ -147,6 +147,7 @@ patch.AVMGuidPatch.description=Set GUIDs on AVM nodes.
patch.AVMGuidPatch.result=AVM GUIDS set.
patch.webscripts.description=Adds Web Scripts to Data Dictionary.
+patch.webscripts2.description=Adds Web Scripts (second set) to Data Dictionary.
patch.webscriptsExtension.description=Adds Web Scripts Extension to Data Dictionary.
patch.AVMLayeredSnapshot.description=Set indirectionVersion on Layered Nodes.
diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml
index efc47dcf36..d6f849a9e6 100644
--- a/config/alfresco/patch/patch-services-context.xml
+++ b/config/alfresco/patch/patch-services-context.xml
@@ -890,5 +890,22 @@
classpath:alfresco/dbscripts/upgrade/2.1/${db.script.dialect}/AlfrescoSchemaUpdate-2.1-VersionColumns.sql
+
+
+ patch.webscripts2
+ patch.webscripts2.description
+ 0
+ 100
+ 101
+
+
+
+
+
+ /${spaces.company_home.childname}/${spaces.dictionary.childname}
+ alfresco/bootstrap/webScripts2.xml
+
+
+
diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties
index 2ae0d49c0e..04466a502f 100644
--- a/config/alfresco/version.properties
+++ b/config/alfresco/version.properties
@@ -19,4 +19,4 @@ version.build=@build-number@
# Schema number
-version.schema=100
+version.schema=101
diff --git a/source/java/org/alfresco/repo/jscript/ScriptNode.java b/source/java/org/alfresco/repo/jscript/ScriptNode.java
index 3971d32c53..ddffb3d6eb 100644
--- a/source/java/org/alfresco/repo/jscript/ScriptNode.java
+++ b/source/java/org/alfresco/repo/jscript/ScriptNode.java
@@ -24,6 +24,9 @@
*/
package org.alfresco.repo.jscript;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@@ -51,14 +54,13 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
-import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
-import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.search.QueryParameterDefinition;
import org.alfresco.service.cmr.security.AccessPermission;
@@ -77,6 +79,7 @@ import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;
+import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
/**
@@ -2093,10 +2096,63 @@ public class ScriptNode implements Serializable, Scopeable
// ------------------------------------------------------------------------------
// Inner Classes
+
+ /**
+ * Inner class for representing content
+ */
+ public static abstract class ScriptContent implements Serializable
+ {
+ /**
+ * @return the content stream as a string
+ */
+ public abstract String getContent();
+
+ public String jsGet_content()
+ {
+ return getContent();
+ }
+
+ /**
+ * @return the content mimetype
+ */
+ public abstract String getMimetype();
+
+ public String jsGet_mimetype()
+ {
+ return getMimetype();
+ }
+
+ /**
+ * @return the content encoding
+ */
+ public abstract String getEncoding();
+
+ public String jsGet_encoding()
+ {
+ return getEncoding();
+ }
+
+ /**
+ * @return the content size
+ */
+ public abstract long getSize();
+
+ public long jsGet_size()
+ {
+ return getSize();
+ }
+
+ /**
+ * @return input stream onto content
+ */
+ /*package*/ abstract InputStream getInputStream();
+ }
+
+
/**
* Inner class wrapping and providing access to a ContentData property
*/
- public class ScriptContentData implements Serializable
+ public class ScriptContentData extends ScriptContent implements Serializable
{
private static final long serialVersionUID = -7819328543933312278L;
@@ -2111,9 +2167,9 @@ public class ScriptNode implements Serializable, Scopeable
this.contentData = contentData;
this.property = property;
}
-
- /**
- * @return the content stream
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.jscript.ScriptNode.ScriptContent#getContent()
*/
public String getContent()
{
@@ -2123,9 +2179,12 @@ public class ScriptNode implements Serializable, Scopeable
return (reader != null && reader.exists()) ? reader.getContentString() : "";
}
- public String jsGet_content()
+ /*package*/ InputStream getInputStream()
{
- return getContent();
+ ContentService contentService = services.getContentService();
+ ContentReader reader = contentService.getReader(nodeRef, property);
+
+ return (reader != null && reader.exists()) ? reader.getContentInputStream() : null;
}
/**
@@ -2148,7 +2207,24 @@ public class ScriptNode implements Serializable, Scopeable
{
setContent(content);
}
-
+
+ /**
+ * Set the content stream from another content object
+ *
+ * @param content ScriptContent to set
+ */
+ public void write(ScriptContent content)
+ {
+ ContentService contentService = services.getContentService();
+ ContentWriter writer = contentService.getWriter(nodeRef, this.property, true);
+ writer.setMimetype(content.getMimetype());
+ writer.setEncoding(content.getEncoding());
+ writer.putContent(content.getInputStream());
+
+ // update cached variables after putContent()
+ this.contentData = (ContentData) services.getNodeService().getProperty(nodeRef, this.property);
+ }
+
/**
* @return download URL to the content
*/
@@ -2203,28 +2279,22 @@ public class ScriptNode implements Serializable, Scopeable
{
return getDownloadUrl();
}
-
public long getSize()
{
return contentData.getSize();
}
- public long jsGet_size()
- {
- return getSize();
- }
-
public String getMimetype()
{
return contentData.getMimetype();
}
- public String jsGet_mimetype()
+ public String getEncoding()
{
- return getMimetype();
+ return contentData.getEncoding();
}
-
+
public void setMimetype(String mimetype)
{
this.contentData = ContentData.setMimetype(this.contentData, mimetype);
@@ -2244,6 +2314,79 @@ public class ScriptNode implements Serializable, Scopeable
private QName property;
}
+
+ /**
+ * Inner class wrapping and providing access to a Content stream
+ */
+ public static class ScriptContentStream extends ScriptContent implements Serializable
+ {
+ private static final long serialVersionUID = -7819328543933312278L;
+
+ /**
+ * Constructor
+ *
+ * @param stream content input stream
+ * @param mimetype content mimetype
+ */
+ public ScriptContentStream(InputStream stream, String mimetype, String encoding)
+ {
+ this.stream = stream;
+ this.mimetype = mimetype;
+ this.encoding = encoding;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.jscript.ScriptNode.ScriptContent#getContent()
+ */
+ public String getContent()
+ {
+ try
+ {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ FileCopyUtils.copy(stream, os); // both streams are closed
+ byte[] bytes = os.toByteArray();
+ // get the encoding for the string
+ String encoding = getEncoding();
+ // create the string from the byte[] using encoding if necessary
+ String content = (encoding == null) ? new String(bytes) : new String(bytes, encoding);
+ // done
+ return content;
+ }
+ catch (IOException e)
+ {
+ throw new ContentIOException("Failed to copy content to string", e);
+ }
+ }
+
+ /*package*/ InputStream getInputStream()
+ {
+ return stream;
+ }
+
+ public long getSize()
+ {
+ return -1;
+ }
+
+ public String getMimetype()
+ {
+ return mimetype;
+ }
+
+ public String getEncoding()
+ {
+ return encoding;
+ }
+
+
+ private InputStream stream;
+
+ private String mimetype;
+
+ private String encoding;
+ }
+
+
/**
* Interface contract for simple anonymous classes that implement document transformations
*/