You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by bi...@apache.org on 2008/01/22 15:14:17 UTC

svn commit: r614203 - in /incubator/cxf/trunk/rt/javascript/src: main/java/org/apache/cxf/javascript/ main/java/org/apache/cxf/javascript/types/ main/resources/org/apache/cxf/javascript/ test/java/org/apache/cxf/javascript/

Author: bimargulies
Date: Tue Jan 22 06:14:16 2008
New Revision: 614203

URL: http://svn.apache.org/viewvc?rev=614203&view=rev
Log:
Read MTOM attachments for text/plain in Javascript.

Modified:
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java
    incubator/cxf/trunk/rt/javascript/src/main/resources/org/apache/cxf/javascript/cxf-utils.js
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/MtoMTest.java

Modified: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java?rev=614203&r1=614202&r2=614203&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java Tue Jan 22 06:14:16 2008
@@ -31,12 +31,14 @@
 
 import org.apache.cxf.aegis.type.mtom.AbstractXOPType;
 import org.apache.cxf.common.xmlschema.SchemaCollection;
+import org.apache.cxf.common.xmlschema.XmlSchemaConstants;
 import org.apache.cxf.databinding.source.mime.MimeAttribute;
 import org.apache.cxf.wsdl.WSDLConstants;
 import org.apache.ws.commons.schema.XmlSchemaComplexType;
 import org.apache.ws.commons.schema.XmlSchemaElement;
 import org.apache.ws.commons.schema.XmlSchemaObject;
 import org.apache.ws.commons.schema.XmlSchemaSimpleContent;
+import org.apache.ws.commons.schema.XmlSchemaSimpleContentExtension;
 import org.apache.ws.commons.schema.XmlSchemaSimpleType;
 import org.apache.ws.commons.schema.XmlSchemaType;
 import org.apache.ws.commons.schema.constants.Constants;
@@ -269,6 +271,34 @@
         return type instanceof XmlSchemaSimpleType 
                || (type instanceof XmlSchemaComplexType 
                    && ((XmlSchemaComplexType)type).getContentModel() instanceof XmlSchemaSimpleContent);
+    }
+
+    /**
+     * Return true for xsd:base64Binary or simple restrictions of it, as in the xmime stock type.
+     * @param type
+     * @return
+     */
+    public static boolean mtomCandidateType(XmlSchemaType type) {
+        if (XmlSchemaConstants.BASE64BINARY_QNAME.equals(type.getQName())) {
+            return true;
+        }
+        // there could be some disagreement whether the following is a good enough test.
+        // what if 'base64binary' was extended in some crazy way? At runtime, either it has
+        // an xop:Include or it doesn't.
+        if (type instanceof XmlSchemaComplexType) {
+            XmlSchemaComplexType complexType = (XmlSchemaComplexType)type; 
+            if (complexType.getContentModel() instanceof XmlSchemaSimpleContent) {
+                XmlSchemaSimpleContent content = (XmlSchemaSimpleContent)complexType.getContentModel();
+                if (content.getContent() instanceof XmlSchemaSimpleContentExtension) {
+                    XmlSchemaSimpleContentExtension extension = 
+                        (XmlSchemaSimpleContentExtension)content.getContent();
+                    if (XmlSchemaConstants.BASE64BINARY_QNAME.equals(extension.getBaseTypeName())) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /**

Modified: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java?rev=614203&r1=614202&r2=614203&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java Tue Jan 22 06:14:16 2008
@@ -558,6 +558,7 @@
         XmlSchemaType itemType = itemInfo.getType();
         boolean simple = itemType instanceof XmlSchemaSimpleType
             || JavascriptUtils.notVeryComplexType(itemType);
+        boolean mtomCandidate = JavascriptUtils.mtomCandidateType(itemType);
         String accessorName = "set" + StringUtils.capitalize(itemInfo.getJavascriptName());
         utils.appendLine("cxfjsutils.trace('processing " + itemInfo.getJavascriptName() + "');");
         XmlSchemaElement element = (XmlSchemaElement) itemInfo.getParticle();
@@ -597,10 +598,14 @@
             // use our utility
             utils.appendLine(valueTarget + " = org_apache_cxf_deserialize_anyType(cxfjsutils, curElement);");
         } else if (simple) {
-            utils.appendLine("value = cxfjsutils.getNodeText(curElement);");
-            utils.appendLine(valueTarget 
-                             + " = " 
-                             + utils.javascriptParseExpression(itemType, "value") + ";");
+            if (mtomCandidate) {
+                utils.appendLine(valueTarget + " = cxfjsutils.deserializeBase64orMom(curElement);");
+            } else {
+                utils.appendLine("value = cxfjsutils.getNodeText(curElement);");
+                utils.appendLine(valueTarget 
+                                 + " = " 
+                                 + utils.javascriptParseExpression(itemType, "value") + ";");
+            }
         } else {
             XmlSchemaComplexType complexType = (XmlSchemaComplexType)itemType;
             QName baseQName = complexType.getQName();

Modified: incubator/cxf/trunk/rt/javascript/src/main/resources/org/apache/cxf/javascript/cxf-utils.js
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/resources/org/apache/cxf/javascript/cxf-utils.js?rev=614203&r1=614202&r2=614203&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/resources/org/apache/cxf/javascript/cxf-utils.js (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/resources/org/apache/cxf/javascript/cxf-utils.js Tue Jan 22 06:14:16 2008
@@ -268,6 +268,243 @@
 
 CxfApacheOrgUtil.prototype.endSoap11Message = org_apache_cxf_end_soap11_message;
 
+const org_apache_cxf_base64_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+function org_apache_cxf_base64_encode64array(input) {
+	var output = "";
+	var chr1, chr2, chr3;
+	var enc1, enc2, enc3, enc4;
+	var i = 0;
+
+	do {
+		var count = 1;
+		chr1 = chr2 = chr3 = 0;
+
+		chr1 = input[i++];
+		if (i < input.length) {
+			chr2 = input[i++];
+			count++;
+		}
+
+		if (i < input.length) {
+			chr3 = input[i++];
+			count++;
+		}
+
+		enc1 = chr1 >> 2;
+		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+		if (count > 1) {
+			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+			if (count > 2)
+				enc4 = chr3 & 63;
+			else
+				enc4 = 64;
+		} else
+			enc3 = enc4 = 64;
+
+		output = output + org_apache_cxf_base64_keyStr.charAt(enc1)
+				+ org_apache_cxf_base64_keyStr.charAt(enc2)
+				+ org_apache_cxf_base64_keyStr.charAt(enc3)
+				+ org_apache_cxf_base64_keyStr.charAt(enc4);
+	} while (i < input.length);
+
+	return output;
+}
+
+function org_apache_cxf_base64_encode64Unicode(input) {
+	var data = new Array(2 + (input.length * 2));
+	data[0] = 0xff;
+	data[1] = 0xfe;
+	for (var x = 0;x < input.length; x++) {
+		var c = input.charCodeAt(x);
+		data[2 + (x * 2)] = c & 0xff;
+		data[3 + (x * 2)] = (c >> 8) & 0xff;
+	}
+	return encode64array(data);
+}
+
+// we may be able to do this more cleanly with unescape( encodeURIComponent(
+// input ) );
+function org_apache_cxf_base64_encode64UTF8(input) {
+
+	// determine how many bytes are needed for the complete conversion
+	var bytesNeeded = 0;
+	for (var i = 0;i < input.length; i++) {
+		if (input.charCodeAt(i) < 0x80) {
+			++bytesNeeded;
+		} else if (input.charCodeAt(i) < 0x0800) {
+			bytesNeeded += 2;
+		} else if (input.charCodeAt(i) < 0x10000) {
+			bytesNeeded += 3;
+		} else {
+			bytesNeeded += 4;
+		}
+	}
+
+	// allocate a byte[] of the necessary size
+	var data = new Array(bytesNeeded);
+	// do the conversion from character code points to utf-8
+	var bytes = 0;
+	for (var i = 0;i < input.length; i++) {
+		if (input.charCodeAt(i) < 0x80) {
+			data[bytes++] = input.charCodeAt(i);
+		} else if (input.charCodeAt(i) < 0x0800) {
+			data[bytes++] = ((input.charCodeAt(i) >> 6) | 0xC0);
+			data[bytes++] = ((input.charCodeAt(i) & 0x3F) | 0x80);
+		} else if (input.charCodeAt(i) < 0x10000) {
+			data[bytes++] = ((input.charCodeAt(i) >> 12) | 0xE0);
+			data[bytes++] = (((input.charCodeAt(i) >> 6) & 0x3F) | 0x80);
+			data[bytes++] = ((input.charCodeAt(i) & 0x3F) | 0x80);
+		} else {
+			data[bytes++] = ((input.charCodeAt(i) >> 18) | 0xF0);
+			data[bytes++] = (((input.charCodeAt(i) >> 12) & 0x3F) | 0x80);
+			data[bytes++] = (((input.charCodeAt(i) >> 6) & 0x3F) | 0x80);
+			data[bytes++] = ((input.charCodeAt(i) & 0x3F) | 0x80);
+		}
+	}
+	return encode64array(data);
+}
+
+function org_apache_cxf_base64_decode64array(input) {
+	var output = new Array();
+	var chr1, chr2, chr3;
+	var enc1, enc2, enc3, enc4;
+	var i = 0;
+
+	// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
+	input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+	do {
+		enc1 = org_apache_cxf_base64_keyStr.indexOf(input.charAt(i++));
+		enc2 = org_apache_cxf_base64_keyStr.indexOf(input.charAt(i++));
+		enc3 = org_apache_cxf_base64_keyStr.indexOf(input.charAt(i++));
+		enc4 = org_apache_cxf_base64_keyStr.indexOf(input.charAt(i++));
+
+		chr1 = (enc1 << 2) | (enc2 >> 4);
+		chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+		chr3 = ((enc3 & 3) << 6) | enc4;
+
+		output[output.length] = chr1;
+
+		if (enc3 != 64) {
+			output[output.length] = chr2;
+		}
+		if (enc4 != 64) {
+			output[output.length] = chr3;
+		}
+	} while (i < input.length);
+
+	return output;
+}
+
+const org_apache_cxf_base64_hD = "0123456789ABCDEF";
+function org_apache_cxf_base64_d2h(d) {
+	var h = org_apache_cxf_base64_hD.substr(d & 15, 1);
+	while (d > 15) {
+		d >>= 4;
+		h = org_apache_cxf_base64_hD.substr(d & 15, 1) + h;
+	}
+	return h;
+}
+
+function org_apache_cxf_base64_decode64Unicode(input) {
+	var bytes = org_apache_cxf_base64_decode64array(input);
+	var swap;
+	var output = "";
+	if (bytes[0] == 0xff && bytes[1] == 0xfe) {
+		swap = true;
+	} else if (bytes[0] == 0xfe && bytes[1] == 0xff) {
+		swap = false;
+	} else {
+		confirm("Problem with decoding utf-16");
+	}
+	for (var x = 2;x < bytes.length; x = x + 2) {
+		var c;
+		if (swap)
+			c = (bytes[x + 1] << 8) | bytes[x];
+		else
+			c = (bytes[x] << 8) | bytes[x + 1];
+
+		output = output + String.fromCharCode(c);
+	}
+	return output;
+}
+
+// we may be able to do this more cleanly with decodeURIComponent( escape( input
+// ) );
+function org_apache_cxf_base64_decode64UTF8(input) {
+	var utftext = org_apache_cxf_base64_decode64array(input);
+	var plaintext = "";
+	var cRay = new Array();
+	var i = 0;
+	var c;
+	var c2;
+	var c3;
+	while (i < utftext.length) {
+		c = utftext[i];
+		if (c < 128) {
+			plaintext += String.fromCharCode(c);
+			i++;
+		} else if ((c > 191) && (c < 224)) {
+			c2 = utftext[i + 1];
+			plaintext += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+			i += 2;
+		} else {
+			c2 = utftext[i + 1];
+			c3 = utftext[i + 2];
+			plaintext += String.fromCharCode(((c & 15) << 12)
+					| ((c2 & 63) << 6) | (c3 & 63));
+			i += 3;
+		}
+	}
+	return plaintext;
+}
+
+// var placeholder = '<xop:Include
+// xmlns:xop="http://www.w3.org/2004/08/xop/include" '
+// + 'href="cid:' + uuid + '" />';
+// var mtomObject = 'Content-Type: text/plain; charset="utf-8";\r\nContent-ID:
+// <'
+// + uuid + '>\r\n\r\n' + value + '\r\n';
+
+const org_apache_cxf_XOP_NS = 'http://www.w3.org/2004/08/xop/include';
+
+function org_apache_cxf_deserialize_MTOM_or_base64(element) {
+	var elementChild = this.getFirstElementChild(element);
+	if (elementChild == null) { // no MTOM, assume base64
+		var base64Text = this.getNodeText(element);
+		// we assume this is text/plain;charset=utf-8. We could check for the
+		// xmime attribute.
+		return org_apache_cxf_base64_decode64UTF8(base64Text);
+	}
+	// 
+	if (!org_apache_cxf_isNodeNamedNS(elementChild, org_apache_cxf_XOP_NS, 'Include')) {
+		this.trace('Invalid child element of base64 element');
+		return ''; // we don't knoww what this is, so we throw it out. We could
+					// throw.
+	}
+	var href = elementChild.getAttribute('href');
+	if(!href) {
+		this.trace('missing href for xop:Include');
+		return ''; // we don't knoww what this is, so we throw it out. We could
+					// throw.
+	}
+	// we only support cid:, not URLs.
+	if(href.length < 4 || href.substr(0, 4) != 'cid:') {
+		this.trace('Non-cid href in xop:Include: ' + href);
+		return ''; 
+	}
+	var cid = href.substr(4);
+	var partobject = this.client.parts[cid];
+	if(!partobject) {
+		this.trace('xop:Include href points to missing attachment: ' + href);
+		return ''; 
+	}
+	// success.
+	return partobject.data;
+}
+
+CxfApacheOrgUtil.prototype.deserializeBase64orMom = org_apache_cxf_deserialize_MTOM_or_base64;
 /*
  * Client object sends requests and calls back with responses.
  */
@@ -471,15 +708,15 @@
 	for (var x = 1;x < strings.length; x = x + 1) {
 		var str = strings[x];
 		var valequal = str.indexOf("=");
-		if(valequal != -1) {
+		if (valequal != -1) {
 			var k = str.substr(0, valequal);
-			var v = str.substr(valequal+1);
+			var v = str.substr(valequal + 1);
 			v = org_apache_cxf_trim_string(v);
-			if(v.charAt(0) == '"') {
-				v = v.substr(1, v.length-2);
+			if (v.charAt(0) == '"') {
+				v = v.substr(1, v.length - 2);
 			}
-			if(v.charAt(0) == "'") {
-				v = v.substr(1, v.length-2);
+			if (v.charAt(0) == "'") {
+				v = v.substr(1, v.length - 2);
 			}
 
 			result[org_apache_cxf_trim_string(k.toLowerCase())] = v;
@@ -517,21 +754,22 @@
 	if (!boundary)
 		return false;
 	boundary = "--" + boundary; // the annoying 'extra-dash' convention.
-	//var boundarySplitter = org_apache_cxf_regexp_escape(boundary);
+	// var boundarySplitter = org_apache_cxf_regexp_escape(boundary);
 	var text = this.req.responseText;
 	// we are willing to use a lot of memory here.
 	var parts = text.split(boundary);
 	// now we have the parts.
 	// now we have to pull headers off the parts.
 	this.parts = [];
-	// the first one is noise due to the initial boundary. The last will just be -- due to MIME.
-	for (var px = 1;px < parts.length-1; px++) {
+	// the first one is noise due to the initial boundary. The last will just be
+	// -- due to MIME.
+	for (var px = 1;px < parts.length - 1; px++) {
 		var seenOneHeader = false;
 		var x = 0; // misc index.
 		var parttext = parts[px];
 		var headers = [];
-		nextHeaderLine:
-		for(var endX = parttext.indexOf('\r', x); endX != -1; x = endX + 1, endX = parttext.indexOf('\r', x)) {
+		nextHeaderLine : for (var endX = parttext.indexOf('\r', x);endX != -1; x = endX
+				+ 1, endX = parttext.indexOf('\r', x)) {
 			var headerLine = parttext.slice(x, endX);
 			if (headerLine == "") {
 				if (parttext.charAt(endX + 1) == '\n')
@@ -547,8 +785,7 @@
 			headers[hparts[0].toLowerCase()] = org_apache_cxf_trim_string(hparts[1]);
 			if (parttext.charAt(endX + 1) == '\n')
 				endX++;
-		} 
-		
+		}
 
 		// Now, see about the mime type (if any) and the ID.
 		var thispart = new Object(); // a constructor seems excessive.
@@ -560,7 +797,7 @@
 		if (px > 1) {
 			var cid = headers['content-id'];
 			// take of < and >
-			cid = cid.substr(1, cid.length-2);
+			cid = cid.substr(1, cid.length - 2);
 			thispart.cid = cid;
 			this.parts[cid] = thispart;
 		} else {

Modified: incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/MtoMTest.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/MtoMTest.java?rev=614203&r1=614202&r2=614203&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/MtoMTest.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/MtoMTest.java Tue Jan 22 06:14:16 2008
@@ -90,7 +90,8 @@
         String errorText = testUtilities.rhinoEvaluateConvert("globalErrorStatusText", String.class);
         assertNull(errorStatus);
         assertNull(errorText);
-        // read out the result string and check it.
+        String unpacked = testUtilities.rhinoEvaluateConvert("globalResponseObject._notXml10", String.class);
+        assertNotNull(unpacked);
         return null;
     }