ws-axis-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aj...@apache.org
Subject svn commit: r279230 - in /webservices/axis2/trunk/java/modules: core/src/org/apache/axis2/clientapi/ wsdl/src/org/apache/axis2/wsdl/codegen/ wsdl/src/org/apache/axis2/wsdl/codegen/emitter/ wsdl/src/org/apache/axis2/wsdl/codegen/extension/ wsdl/src/org/...
Date Wed, 07 Sep 2005 03:33:35 GMT
Author: ajith
Date: Tue Sep  6 20:33:10 2005
New Revision: 279230

URL: http://svn.apache.org/viewcvs?rev=279230&view=rev
Log:
Fixed the code generation for the MTOM output case. Now the base64 content is optimized in
sending also
1. modified the XMLBeansExtension.java, codegen/CodeGenConfiguration.java to add the a table
of QNames of the base64 elements.
2.Added an abstract callback supporter (now the generated databind supporters are extended
from this)
3.Modified the template/java/XMLBeansSupporterTemplate.xsl

This still needs some modifications.Need to have a switch to disable MTOMizing

Added:
    webservices/axis2/trunk/java/modules/core/src/org/apache/axis2/clientapi/AbstractCallbackSupporter.java
    webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/
    webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/XPathEvaluator.java
Modified:
    webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/CodeGenConfiguration.java
    webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/XSLTConstants.java
    webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/emitter/MultiLanguageClientEmitter.java
    webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/extension/XMLBeansExtension.java
    webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/template/java/XMLBeansSupporterTemplate.xsl
    webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/attachments/MIMEHelper.java

Added: webservices/axis2/trunk/java/modules/core/src/org/apache/axis2/clientapi/AbstractCallbackSupporter.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/core/src/org/apache/axis2/clientapi/AbstractCallbackSupporter.java?rev=279230&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/core/src/org/apache/axis2/clientapi/AbstractCallbackSupporter.java
(added)
+++ webservices/axis2/trunk/java/modules/core/src/org/apache/axis2/clientapi/AbstractCallbackSupporter.java
Tue Sep  6 20:33:10 2005
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.axis2.clientapi;
+
+import org.apache.axis2.om.OMElement;
+import org.apache.axis2.om.OMNode;
+import org.apache.axis2.om.OMText;
+
+import javax.xml.namespace.QName;
+import java.util.Iterator;
+
+
+public abstract class AbstractCallbackSupporter {
+
+    protected boolean runOptimizer = false;
+
+    /**
+     *
+     * @param element
+     * @param qNames
+     */
+    protected static void optimizeContent(OMElement element, QName[] qNames){
+        int length = qNames.length;
+        QName qName;
+        for (int i = 0; i < length; i++) {
+            qName = qNames[i];
+            markElementsAsOptimized(qName,element);
+        }
+    }
+
+    /**
+     *
+     * @param qName
+     * @param rootElt
+     */
+    private static void markElementsAsOptimized(QName qName,OMElement rootElt){
+        if (rootElt.getQName().equals(qName)){
+            //get the text node and mark it
+            OMNode node = rootElt.getFirstChild();
+            if (node.getType()==OMNode.TEXT_NODE){
+                ((OMText)node).setOptimize(true);
+            }
+
+        }
+        Iterator childElements = rootElt.getChildElements();
+        while (childElements.hasNext()) {
+            markElementsAsOptimized(qName,(OMElement)childElements.next());
+        }
+    }
+}

Modified: webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/CodeGenConfiguration.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/CodeGenConfiguration.java?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/CodeGenConfiguration.java
(original)
+++ webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/CodeGenConfiguration.java
Tue Sep  6 20:33:10 2005
@@ -21,6 +21,7 @@
 
 import java.io.File;
 import java.util.Map;
+import java.util.HashMap;
 
 /**
  * @author chathura@opensource.lk
@@ -50,7 +51,23 @@
     */
     private  int codeGenerationStyle = XSLTConstants.CodegenStyle.AUTOMATIC;
 
+    /*
+    * A hashmap of properties that may be populated on the way. extensions can populate it
+    *
+    */
+    private Map configurationProperties = new HashMap();
+
+    public void put(Object key, Object value){
+        configurationProperties.put(key,value);
+    }
+
+    public Object get(Object key){
+       return configurationProperties.get(key);
+    }
 
+    public Map getProperties(){
+        return configurationProperties;
+    }
     private TypeMapper typeMapper;
 
 
@@ -77,15 +94,15 @@
     public void setDatabindingType(int databindingType) {
         this.databindingType = databindingType;
     }
-    
+
     public void setDatabindingType(String databindingType) {
-    	if (Databinding.XML_BEANS.equalsIgnoreCase(databindingType)) {
-    		this.databindingType = XSLTConstants.DataBindingTypes.XML_BEANS;
-    	}else if(Databinding.JAXB.equalsIgnoreCase(databindingType)){
-    		this.databindingType = XSLTConstants.DataBindingTypes.JAXB;
-    	}else{
-    		throw new UnsupportedOperationException();
-    	}
+        if (Databinding.XML_BEANS.equalsIgnoreCase(databindingType)) {
+            this.databindingType = XSLTConstants.DataBindingTypes.XML_BEANS;
+        }else if(Databinding.JAXB.equalsIgnoreCase(databindingType)){
+            this.databindingType = XSLTConstants.DataBindingTypes.JAXB;
+        }else{
+            throw new UnsupportedOperationException();
+        }
     }
 
     /**
@@ -144,7 +161,7 @@
         CommandLineOption dataBindingOption = (CommandLineOption) optionMap.get(
                 DATA_BINDING_TYPE_OPTION);
         if(dataBindingOption != null){
-        	setDatabindingType(dataBindingOption.getOptionValue());
+            setDatabindingType(dataBindingOption.getOptionValue());
         }
     }
 

Modified: webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/XSLTConstants.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/XSLTConstants.java?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/XSLTConstants.java
(original)
+++ webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/XSLTConstants.java
Tue Sep  6 20:33:10 2005
@@ -1,5 +1,7 @@
 package org.apache.axis2.wsdl.codegen;
 
+import javax.xml.namespace.QName;
+
 /*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
@@ -20,7 +22,8 @@
 
 public interface XSLTConstants {
     String DEFAULT_PACKAGE_NAME = "codegen";
-
+    QName BASE_64_CONTENT_QNAME= new QName("http://www.w3.org/2001/XMLSchema","base64Binary");
+    String BASE_64_PROPERTY_KEY = "base64map";
     /**
      * Language constants
      */

Modified: webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/emitter/MultiLanguageClientEmitter.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/emitter/MultiLanguageClientEmitter.java?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/emitter/MultiLanguageClientEmitter.java
(original)
+++ webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/emitter/MultiLanguageClientEmitter.java
Tue Sep  6 20:33:10 2005
@@ -47,7 +47,7 @@
 *
 * Abstract Client emitter
 * the XML will look like the following
-* todo Add references to relevant shcemas !
+* todo Add references to relevant schemas !
 */
 
 
@@ -1018,16 +1018,47 @@
             }
         }
 
-        //Now run through the parameters and ad them to the root element
+        //add the names of the elements that have base 64 content
+        //if the base64 name list is missing then this whole step is skipped
+        rootElement.appendChild(getBase64Elements(doc));
+
+        //Now run through the parameters and add them to the root element
         Collection parameters = parameterMap.values();
         for (Iterator iterator = parameters.iterator(); iterator.hasNext();) {
             rootElement.appendChild((Element)iterator.next());
         }
 
         doc.appendChild(rootElement);
+        ///////////////////////////////////////////////////
+        //System.out.println("rootElement = " + rootElement);
+        ///////////////////////////////////////////////////
         return doc;
     }
 
+    /**
+     * Get the base64 types. If not available this will be empty!!!
+     * @param doc
+     * @return element
+     */
+    private Element getBase64Elements(Document doc){
+        Element root = doc.createElement("base64Elements");
+        Element elt;
+        QName qname;
+        //this is a list of QNames
+        List list = (List)configuration.getProperties().get(XSLTConstants.BASE_64_PROPERTY_KEY);
+        if (list!=null && !list.isEmpty()){
+            int count = list.size();
+            for (int i = 0; i < count; i++) {
+              qname = (QName)list.get(i);
+              elt = doc.createElement("name") ;
+              addAttribute(doc,"ns-url",qname.getNamespaceURI(),elt);
+              addAttribute(doc,"localName",qname.getLocalPart(),elt);
+              root.appendChild(elt);
+            }
+        }
+
+        return root;
+    }
     /**
      * Creates the DOM tree for implementations
      *

Modified: webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/extension/XMLBeansExtension.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/extension/XMLBeansExtension.java?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/extension/XMLBeansExtension.java
(original)
+++ webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/codegen/extension/XMLBeansExtension.java
Tue Sep  6 20:33:10 2005
@@ -41,6 +41,7 @@
     private static final String DEFAULT_STS_NAME = "foo";
 
 
+
     public void init(CodeGenConfiguration configuration) {
         this.configuration = configuration;
     }
@@ -106,6 +107,8 @@
             }
 
             // add the third party schemas
+            //todo pehaps checking the namespaces would be a good idea to
+            //make the generated code work efficiently
             for (int i = 0; i < additionalSchemas.length; i++) {
                 xmlObjectsVector.add(XmlObject.Factory.parse(
                         additionalSchemas[i]
@@ -119,6 +122,10 @@
                     new Axis2Filer(),
                     null);
 
+            // prune the generated schema type system and add the list of base64 types
+            FindBase64Types(sts);
+
+            //get the schematypes and add the document types to the type mapper
             SchemaType[] schemaType = sts.documentTypes();
             SchemaType type;
             for (int j = 0; j < schemaType.length; j++) {
@@ -132,6 +139,30 @@
             throw new RuntimeException(e);
         }
 
+    }
+
+    /**
+     * Populate the base64 types
+     * @param sts
+     */
+    private void FindBase64Types(SchemaTypeSystem sts) {
+        List allSeenTypes = new ArrayList();
+        List base64ElementQNamesList = new ArrayList();
+        //add the document types and global types
+        allSeenTypes.addAll(Arrays.asList(sts.documentTypes()));
+        allSeenTypes.addAll(Arrays.asList(sts.globalTypes()));
+        for (int i = 0; i < allSeenTypes.size(); i++){
+            SchemaType sType = (SchemaType)allSeenTypes.get(i);
+            if (sType.getContentType()==SchemaType.SIMPLE_CONTENT) {
+                if (XSLTConstants.BASE_64_CONTENT_QNAME.equals(sType.getPrimitiveType().getName())){
+                    base64ElementQNamesList.add(sType.getOuterType().getDocumentElementName());
+                }
+            }
+            //add any of the child types if there are any
+            allSeenTypes.addAll(Arrays.asList(sType.getAnonymousTypes()));
+        }
+
+        configuration.put(XSLTConstants.BASE_64_PROPERTY_KEY,base64ElementQNamesList);
     }
 
     /**

Modified: webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/template/java/XMLBeansSupporterTemplate.xsl
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/template/java/XMLBeansSupporterTemplate.xsl?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/template/java/XMLBeansSupporterTemplate.xsl
(original)
+++ webservices/axis2/trunk/java/modules/wsdl/src/org/apache/axis2/wsdl/template/java/XMLBeansSupporterTemplate.xsl
Tue Sep  6 20:33:10 2005
@@ -1,69 +1,82 @@
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>
     <xsl:template match="/class">
-    package <xsl:value-of select="@package"/>;
+        package <xsl:value-of select="@package"/>;
 
-    /**
-     *  Auto generated supporter class for XML beans by the Axis code generator
-     */
-
-    public class <xsl:value-of select="@name"/> {
-             <xsl:apply-templates />
-
-          public static org.apache.xmlbeans.XmlObject fromOM(org.apache.axis2.om.OMElement
param,
-               java.lang.Class type){
-                try{
-                    <xsl:for-each select="param">
-                    <xsl:if test="@type!=''">
-                    if (<xsl:value-of select="@type"/>.class.equals(type)){
-                        //////////////////////////////////////////////////
-                        /////////// Temporary hack to solve some streaming problems
-                        param.build();
-                        /////////////////////////////////////////////////
-                        return <xsl:value-of select="@type"/>.Factory.parse(param.getXMLStreamReader())
;
-                    }
-                     </xsl:if>
-                    </xsl:for-each>
-                 }catch(java.lang.Exception e){
-                    throw new RuntimeException("Data binding error",e);
+        /**
+        *  Auto generated supporter class for XML beans by the Axis code generator
+        */
+
+        public class <xsl:value-of select="@name"/> extends org.apache.axis2.clientapi.AbstractCallbackSupporter{
+        <xsl:variable name="base64"><xsl:value-of select="base64Elements/name"/></xsl:variable>
+        <xsl:if test="$base64">
+            private static javax.xml.namespace.QName[] qNameArray = {
+            <xsl:for-each select="base64Elements/name">
+                <xsl:if test="position()>1">,</xsl:if>new javax.xml.namespace.QName("<xsl:value-of
select="@ns-url"/>","<xsl:value-of select="@localName"/>")
+            </xsl:for-each>
+            };
+        </xsl:if>
+
+        <xsl:for-each select="param">
+            <xsl:if test="@type!=''">
+        public  static org.apache.axis2.om.OMElement  toOM(<xsl:value-of select="@type"/>
param){
+        org.apache.axis2.om.impl.llom.builder.StAXOMBuilder builder = new org.apache.axis2.om.impl.llom.builder.StAXOMBuilder
+        (org.apache.axis2.om.OMAbstractFactory.getOMFactory(),new org.apache.axis2.clientapi.StreamWrapper(param.newXMLStreamReader()))
;
+        org.apache.axis2.om.OMElement documentElement = builder.getDocumentElement();
+        ///////Building the element is needed to avoid certain stream errors!
+        documentElement.build();
+        //////////////////////////////
+        <xsl:if test="$base64">optimizeContent(documentElement,qNameArray);</xsl:if>
+        return documentElement;
+        }
+            </xsl:if>
+        </xsl:for-each>
+
+        public static org.apache.xmlbeans.XmlObject fromOM(org.apache.axis2.om.OMElement
param,
+        java.lang.Class type){
+        try{
+        <xsl:for-each select="param">
+            <xsl:if test="@type!=''">
+                if (<xsl:value-of select="@type"/>.class.equals(type)){
+                //////////////////////////////////////////////////
+                /////////// Temporary hack to solve some streaming problems
+                param.build();
+                /////////////////////////////////////////////////
+                return <xsl:value-of select="@type"/>.Factory.parse(param.getXMLStreamReader())
;
                 }
-             return null;
-          }
+            </xsl:if>
+        </xsl:for-each>
+        }catch(java.lang.Exception e){
+        throw new RuntimeException("Data binding error",e);
+        }
+        return null;
+        }
 
         //Generates an empty object for testing
         // Caution - need some manual editing to work properly
-         public static org.apache.xmlbeans.XmlObject getTestObject(java.lang.Class type){
-                try{
-                   <xsl:for-each select="param">
-                    <xsl:if test="@type!=''">
-                    if (<xsl:value-of select="@type"/>.class.equals(type)){
-                        <xsl:value-of select="@type"/> emptyObject= <xsl:value-of
select="@type"/>.Factory.newInstance();
-                        ////////////////////////////////////////////////
-                        // TODO
-                        // Fill in the empty object with necessaey values. Empty XMLBeans
objects do not generate proper events
-                        ////////////////////////////////////////////////
-                        return emptyObject;
-                    }
-                     </xsl:if>
-                    </xsl:for-each>
-                 }catch(java.lang.Exception e){
-                   throw new RuntimeException("Test object creation failure",e);
+        public static org.apache.xmlbeans.XmlObject getTestObject(java.lang.Class type){
+        try{
+        <xsl:for-each select="param">
+            <xsl:if test="@type!=''">
+                if (<xsl:value-of select="@type"/>.class.equals(type)){
+                <xsl:value-of select="@type"/> emptyObject= <xsl:value-of select="@type"/>.Factory.newInstance();
+                ////////////////////////////////////////////////
+                // TODO
+                // Fill in the empty object with necessaey values. Empty XMLBeans objects
do not generate proper events
+                ////////////////////////////////////////////////
+                return emptyObject;
                 }
-             return null;
-          }
-     }
+            </xsl:if>
+        </xsl:for-each>
+        }catch(java.lang.Exception e){
+        throw new RuntimeException("Test object creation failure",e);
+        }
+        return null;
+        }
+        }
     </xsl:template>
-    
+
     <xsl:template match="param">
-        <xsl:if test="@type!=''">
-          public  static org.apache.axis2.om.OMElement  toOM(<xsl:value-of select="@type"/>
param){
-		    org.apache.axis2.om.impl.llom.builder.StAXOMBuilder builder = new org.apache.axis2.om.impl.llom.builder.StAXOMBuilder
-            (org.apache.axis2.om.OMAbstractFactory.getOMFactory(),new org.apache.axis2.clientapi.StreamWrapper(param.newXMLStreamReader()))
;
-		    org.apache.axis2.om.OMElement documentElement = builder.getDocumentElement();
-            //Building the element is needed to avoid certain stream errors!
-            documentElement.build();
-            return documentElement;
-          }
-       </xsl:if>
+
     </xsl:template>
- </xsl:stylesheet>
\ No newline at end of file
+</xsl:stylesheet>
\ No newline at end of file

Modified: webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/attachments/MIMEHelper.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/attachments/MIMEHelper.java?rev=279230&r1=279229&r2=279230&view=diff
==============================================================================
--- webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/attachments/MIMEHelper.java
(original)
+++ webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/attachments/MIMEHelper.java
Tue Sep  6 20:33:10 2005
@@ -88,7 +88,7 @@
      * @param fileCacheEnable
      * @param attachmentRepoDir
      * @throws OMException
-     * @see Will move the pointer to the begining of the first MIME part. Will
+     * Will move the pointer to the begining of the first MIME part. Will
      *      read till first MIME boundary is found or end of stream reached.
      */
     public MIMEHelper(InputStream inStream, String contentTypeString,
@@ -152,7 +152,7 @@
      * @param inStream
      * @param contentTypeString
      * @throws OMException
-     * @see Will set file cache to false
+     * Will set file cache to false
      */
     public MIMEHelper(InputStream inStream, String contentTypeString)
             throws OMException {
@@ -259,9 +259,9 @@
      * @param blobContentID
      * @return The Part refered by the content-Id
      * @throws OMException
-     * @see First checks whether the MIME part is already parsed by checking the
-     *      parts HashMap. If it is not parsed yet then call the getNextPart()
-     *      till we find the required part.
+     * First checks whether the MIME part is already parsed by checking the
+     * parts HashMap. If it is not parsed yet then call the getNextPart()
+     * till we find the required part.
      */
     public Part getPart(String blobContentID) {
         Part bodyPart;

Added: webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/XPathEvaluator.java
URL: http://svn.apache.org/viewcvs/webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/XPathEvaluator.java?rev=279230&view=auto
==============================================================================
--- webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/XPathEvaluator.java
(added)
+++ webservices/axis2/trunk/java/modules/xml/src/org/apache/axis2/om/util/XPathEvaluator.java
Tue Sep  6 20:33:10 2005
@@ -0,0 +1,29 @@
+package org.apache.axis2.om.util;
+
+import org.apache.axis2.om.xpath.AXIOMXPath;
+import org.jaxen.NamespaceContext;
+import org.jaxen.SimpleNamespaceContext;
+
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: Ajith
+ * Date: Sep 6, 2005
+ * Time: 8:02:51 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class XPathEvaluator {
+
+    public List evaluateXpath(String xpathExpression, Object element, String nsURI) throws
Exception{
+        AXIOMXPath xpath = new AXIOMXPath(xpathExpression);
+        if (nsURI!=null){
+            SimpleNamespaceContext nsContext = new SimpleNamespaceContext();
+            nsContext.addNamespace(null,nsURI);
+            xpath.setNamespaceContext(nsContext);
+        }
+        return xpath.selectNodes(element);
+    }
+
+
+}



Mime
View raw message