servicemix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gno...@apache.org
Subject svn commit: r391395 - in /incubator/servicemix/trunk/servicemix-http/src: main/java/org/apache/servicemix/http/ main/java/org/apache/servicemix/http/processors/ main/java/org/apache/servicemix/http/tools/ test/java/org/apache/servicemix/http/
Date Tue, 04 Apr 2006 20:00:27 GMT
Author: gnodet
Date: Tue Apr  4 13:00:24 2006
New Revision: 391395

URL: http://svn.apache.org/viewcvs?rev=391395&view=rev
Log:
SM-380:Expose a non-standalone WSDL when the target endpoint description has a port type in
a namespace that do not match the http endpoint service namespace
SM-379: Wrong transportURI when usnig the servicemix-http with a JSR181 endpoint.

Added:
    incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/
    incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/PortTypeDecorator.java
Modified:
    incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
    incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/ServerManager.java
    incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/processors/ConsumerProcessor.java
    incubator/servicemix/trunk/servicemix-http/src/test/java/org/apache/servicemix/http/HttpXBeanDeployerTest.java

Modified: incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
URL: http://svn.apache.org/viewcvs/incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/HttpEndpoint.java?rev=391395&r1=391394&r2=391395&view=diff
==============================================================================
--- incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
(original)
+++ incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/HttpEndpoint.java
Tue Apr  4 13:00:24 2006
@@ -15,23 +15,26 @@
  */
 package org.apache.servicemix.http;
 
-import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.jbi.servicedesc.ServiceEndpoint;
+import javax.wsdl.Binding;
 import javax.wsdl.Definition;
 import javax.wsdl.Port;
+import javax.wsdl.PortType;
 import javax.wsdl.Service;
 import javax.wsdl.extensions.ExtensibilityElement;
 import javax.wsdl.extensions.http.HTTPAddress;
-import javax.wsdl.extensions.soap.SOAPAddress;
+import javax.xml.namespace.QName;
 
 import org.apache.servicemix.common.ExchangeProcessor;
 import org.apache.servicemix.http.processors.ConsumerProcessor;
 import org.apache.servicemix.http.processors.ProviderProcessor;
+import org.apache.servicemix.http.tools.PortTypeDecorator;
 import org.apache.servicemix.soap.SoapEndpoint;
 
 import com.ibm.wsdl.extensions.http.HTTPAddressImpl;
-import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
 
 /**
  * 
@@ -45,6 +48,7 @@
 
     protected ExtensibilityElement binding;
     protected String locationURI;
+    protected Map wsdls = new HashMap();
     
     public ExtensibilityElement getBinding() {
         return binding;
@@ -70,45 +74,93 @@
         super.setRoleAsString(role);
     }
 
-    protected void overrideDefinition(Definition def) {
-        Service svc = null;
-        Port port = null;
-        if (targetService != null && targetEndpoint != null) {
-            svc = def.getService(targetService);
-            port = (svc != null) ? svc.getPort(targetEndpoint) : null;
-        } else if (targetService != null) {
-            svc = def.getService(targetService);
-            if (svc != null) {
-                Iterator it = svc.getPorts().values().iterator();
-                port = (it.hasNext()) ? (Port) it.next() : null;
-            }
+    protected PortType getTargetPortType(Definition def) {
+        PortType portType = null;
+        // If the WSDL description only contain one PortType, use it
+        if (def.getServices().size() == 0 && def.getPortTypes().size() == 1) {
+            portType = (PortType) def.getPortTypes().values().iterator().next();
         } else if (targetInterfaceName != null) {
-            Iterator it = def.getServices().values().iterator();
-            svc = it .hasNext() ? (Service) it.next() : null;
-            if (svc != null) {
-                it = svc.getPorts().values().iterator();
-                port = (it.hasNext()) ? (Port) it.next() : null;
+            portType = def.getPortType(targetInterfaceName);
+        } else if (targetService != null && targetEndpoint != null) {
+            Service svc = def.getService(targetService);
+            Port port = (svc != null) ? svc.getPort(targetEndpoint) : null;
+            portType = (port != null) ? port.getBinding().getPortType() : null;
+        } else if (targetService != null) {
+            Service svc = def.getService(targetService);
+            if (svc != null && svc.getPorts().size() == 1) {
+                Port port = (Port) svc.getPorts().values().iterator().next();
+                portType = (port != null) ? port.getBinding().getPortType() : null;
             }
+        } else if (interfaceName != null) {
+            portType = def.getPortType(interfaceName);
         } else {
-            svc = def.getService(service);
-            port = (svc != null) ? svc.getPort(endpoint) : null;
+            Service svc = def.getService(service);
+            Port port = (svc != null) ? svc.getPort(endpoint) : null;
+            portType = (port != null && port.getBinding() != null) ? port.getBinding().getPortType()
: null;
         }
-        if (port != null) {
-            port.getExtensibilityElements().clear();
-            if (isSoap()) {
-                SOAPAddress address = new SOAPAddressImpl();
-                address.setLocationURI(getLocationURI());
-                port.addExtensibilityElement(address);
-                def.addNamespace("soap", "http://schemas.xmlsoap.org/wsdl/soap/");
+        return portType;
+    }
+    
+    protected void overrideDefinition(Definition def) throws Exception {
+        PortType portType = getTargetPortType(def);
+        if (portType != null) {
+            QName[] names = (QName[]) def.getPortTypes().keySet().toArray(new QName[0]);
+            for (int i = 0; i < names.length; i++) {
+                if (!names[i].equals(portType.getQName())) {
+                    def.removePortType(names[i]);
+                }
+            }
+            names = (QName[]) def.getServices().keySet().toArray(new QName[0]);
+            for (int i = 0; i < names.length; i++) {
+                def.removeService(names[i]);
+            }
+            names = (QName[]) def.getBindings().keySet().toArray(new QName[0]);
+            for (int i = 0; i < names.length; i++) {
+                def.removeBinding(names[i]);
+            }
+            if (portType.getQName().getNamespaceURI().equals(service.getNamespaceURI()))
{
+                if (isSoap()) {
+                    PortTypeDecorator.decorate(
+                            def, 
+                            portType, 
+                            getLocationURI(), 
+                            endpoint + "Binding",
+                            service.getLocalPart(),
+                            endpoint);       
+                    definition = def;
+                    wsdls.put("main.wsdl", def);
+                } else {
+                    Binding binding = def.createBinding();
+                    binding.setPortType(portType);
+                    binding.setQName(new QName(service.getNamespaceURI(), endpoint + "Binding"));
+                    binding.setUndefined(false);
+                    def.addBinding(binding);
+                    Port port = def.createPort();
+                    port.setName(endpoint);
+                    port.setBinding(binding);
+                    HTTPAddress address = new HTTPAddressImpl();
+                    address.setLocationURI(getLocationURI());
+                    port.addExtensibilityElement(address);
+                    def.addNamespace("http", "http://schemas.xmlsoap.org/wsdl/http/");
+                    Service svc = def.createService();
+                    svc.setQName(service);
+                    svc.addPort(port);
+                    def.addService(svc);
+                    definition = def;
+                    wsdls.put("main.wsdl", def);
+                }
             } else {
-                HTTPAddress address = new HTTPAddressImpl();
-                address.setLocationURI(getLocationURI());
-                port.addExtensibilityElement(address);
-                def.addNamespace("http", "http://schemas.xmlsoap.org/wsdl/http/");
+                definition = PortTypeDecorator.createImportDef(def, service.getNamespaceURI(),
"porttypedef.wsdl");
+                PortTypeDecorator.decorate(
+                        definition, 
+                        portType, 
+                        getLocationURI(), 
+                        endpoint + "Binding",
+                        service.getLocalPart(),
+                        endpoint);       
+                wsdls.put("main.wsdl", definition);
+                wsdls.put("porttypedef.wsdl", def);
             }
-            svc.getPorts().clear();
-            svc.addPort(port);
-            definition = def;
         }
     }
 
@@ -122,6 +174,13 @@
 
     protected ServiceEndpoint createExternalEndpoint() {
         return new HttpExternalEndpoint(this);
+    }
+
+    /**
+     * @return Returns the wsdls.
+     */
+    public Map getWsdls() {
+        return wsdls;
     }
 
 }

Modified: incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/ServerManager.java
URL: http://svn.apache.org/viewcvs/incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/ServerManager.java?rev=391395&r1=391394&r2=391395&view=diff
==============================================================================
--- incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/ServerManager.java
(original)
+++ incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/ServerManager.java
Tue Apr  4 13:00:24 2006
@@ -96,6 +96,9 @@
         if (!path.startsWith("/")) {
             path = "/" + path;
         }
+        if (path.endsWith("/")) {
+            path = path.substring(0, path.length() - 1);
+        }
         // Check that context does not exist yet
         Handler[] handlers = server.getHandlers();
         if (handlers != null) {

Modified: incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/processors/ConsumerProcessor.java
URL: http://svn.apache.org/viewcvs/incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/processors/ConsumerProcessor.java?rev=391395&r1=391394&r2=391395&view=diff
==============================================================================
--- incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/processors/ConsumerProcessor.java
(original)
+++ incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/processors/ConsumerProcessor.java
Tue Apr  4 13:00:24 2006
@@ -27,10 +27,8 @@
 import javax.jbi.messaging.NormalizedMessage;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
+import javax.wsdl.Definition;
+import javax.wsdl.factory.WSDLFactory;
 
 import org.apache.servicemix.JbiConstants;
 import org.apache.servicemix.common.BaseLifeCycle;
@@ -49,7 +47,6 @@
 import org.mortbay.jetty.handler.ContextHandler;
 import org.mortbay.util.ajax.Continuation;
 import org.mortbay.util.ajax.ContinuationSupport;
-import org.w3c.dom.Document;
 
 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 
@@ -105,7 +102,21 @@
         if ("GET".equals(request.getMethod())) {
             String query = request.getQueryString();
             if (query != null && query.trim().equalsIgnoreCase("wsdl")) {
-                generateWSDL(response);
+                String uri = request.getRequestURI();
+                if (!uri.endsWith("/")) {
+                    uri += "/";
+                }
+                uri += "main.wsdl";
+                response.sendRedirect(uri);
+                return;
+            }
+            String path = request.getPathInfo();
+            if (path.startsWith("/")) {
+                path = path.substring(1);
+            }
+            if (path.endsWith(".wsdl")) {
+                Definition def = (Definition) endpoint.getWsdls().get(path);
+                generateWSDL(response, def);
                 return;
             }
         }
@@ -207,16 +218,14 @@
         return lf.getServer();
     }
     
-    protected void generateWSDL(HttpServletResponse response) throws Exception {
-        Document doc = endpoint.getDescription();
-        if (doc == null) {
+    protected void generateWSDL(HttpServletResponse response, Definition def) throws Exception
{
+        if (def == null) {
             response.sendError(HttpServletResponse.SC_NOT_FOUND, "No wsdl is available for
this service");
             return;
         }
         response.setStatus(200);
         response.setContentType("text/xml");
-        Transformer transformer = TransformerFactory.newInstance().newTransformer();
-        transformer.transform(new DOMSource(doc), new StreamResult(response.getOutputStream()));
+        WSDLFactory.newInstance().newWSDLWriter().writeWSDL(def, response.getOutputStream());
     }
 
 }

Added: incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/PortTypeDecorator.java
URL: http://svn.apache.org/viewcvs/incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/PortTypeDecorator.java?rev=391395&view=auto
==============================================================================
--- incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/PortTypeDecorator.java
(added)
+++ incubator/servicemix/trunk/servicemix-http/src/main/java/org/apache/servicemix/http/tools/PortTypeDecorator.java
Tue Apr  4 13:00:24 2006
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2005-2006 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.servicemix.http.tools;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.wsdl.Binding;
+import javax.wsdl.BindingFault;
+import javax.wsdl.BindingInput;
+import javax.wsdl.BindingOperation;
+import javax.wsdl.BindingOutput;
+import javax.wsdl.Definition;
+import javax.wsdl.Fault;
+import javax.wsdl.Import;
+import javax.wsdl.Operation;
+import javax.wsdl.Port;
+import javax.wsdl.PortType;
+import javax.wsdl.Service;
+import javax.wsdl.extensions.soap.SOAPAddress;
+import javax.wsdl.extensions.soap.SOAPBinding;
+import javax.wsdl.extensions.soap.SOAPBody;
+import javax.wsdl.extensions.soap.SOAPFault;
+import javax.wsdl.factory.WSDLFactory;
+import javax.xml.namespace.QName;
+
+import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
+import com.ibm.wsdl.extensions.soap.SOAPBindingImpl;
+import com.ibm.wsdl.extensions.soap.SOAPBodyImpl;
+import com.ibm.wsdl.extensions.soap.SOAPFaultImpl;
+
+public class PortTypeDecorator {
+
+    public static Definition createImportDef(Definition definition,
+                                             String targetNamespace,
+                                             String importUri) throws Exception {
+        // Create definition
+        Definition def = WSDLFactory.newInstance().newDefinition();
+        def.setTargetNamespace(targetNamespace);
+        
+        // Add namespaces
+        Map namespaces = definition.getNamespaces();
+        for (Iterator iter = namespaces.keySet().iterator(); iter.hasNext();) {
+            String prefix = (String) iter.next();
+            String uri = definition.getNamespace(prefix);
+            def.addNamespace(prefix, uri);
+        }
+        def.addNamespace("tns", targetNamespace);
+        def.addNamespace("tnspt", definition.getTargetNamespace());
+        
+        // Create import
+        Import imp = def.createImport();
+        imp.setNamespaceURI(definition.getTargetNamespace());
+        imp.setLocationURI(importUri);
+        def.addImport(imp);
+        
+        return def;
+    }
+    
+    public static void decorate(Definition def,
+                                PortType portType,
+                                String locationUri) throws Exception {
+        decorate(def,
+                 portType,
+                 locationUri,
+                 portType.getQName().getLocalPart() + "Binding",
+                 portType.getQName().getLocalPart() + "Service",
+                 "JBI");
+    }
+    
+    public static void decorate(Definition def,
+                                PortType portType,
+                                String locationUri,
+                                String bindingName,
+                                String serviceName,
+                                String portName) throws Exception {
+        def.addNamespace("wsdlsoap", "http://schemas.xmlsoap.org/wsdl/soap/");
+        // Create binding
+        Binding binding = def.createBinding();
+        binding.setQName(new QName(def.getTargetNamespace(), bindingName));
+        binding.setPortType(portType);
+        binding.setUndefined(false);
+        // Create soap extension
+        SOAPBinding soap = new SOAPBindingImpl();
+        soap.setTransportURI("http://schemas.xmlsoap.org/soap/http");
+        soap.setStyle("document");
+        binding.addExtensibilityElement(soap);
+        // Create operations
+        List operations = portType.getOperations();
+        for (Iterator iter = operations.iterator(); iter.hasNext();) {
+            Operation operation = (Operation) iter.next();
+            BindingOperation bindingOp = def.createBindingOperation();
+            bindingOp.setName(operation.getName());
+            if (operation.getInput() != null) {
+                BindingInput in = def.createBindingInput();
+                in.setName(operation.getInput().getName());
+                SOAPBody body = new SOAPBodyImpl();
+                body.setUse("literal");
+                in.addExtensibilityElement(body);
+                bindingOp.setBindingInput(in);
+            }
+            if (operation.getOutput() != null) {
+                BindingOutput out = def.createBindingOutput();
+                out.setName(operation.getOutput().getName());
+                SOAPBody body = new SOAPBodyImpl();
+                body.setUse("literal");
+                out.addExtensibilityElement(body);
+                bindingOp.setBindingOutput(out);
+            }
+            for (Iterator itf = operation.getFaults().values().iterator(); itf.hasNext();)
{
+                Fault fault = (Fault) itf.next();
+                BindingFault bindingFault = def.createBindingFault();
+                bindingFault.setName(fault.getName());
+                SOAPFault soapFault = new SOAPFaultImpl();
+                soapFault.setUse("literal");
+                soapFault.setName(fault.getName());
+                bindingFault.addExtensibilityElement(soapFault);
+                bindingOp.addBindingFault(bindingFault);
+            }
+            binding.addBindingOperation(bindingOp);
+        }
+        def.addBinding(binding);
+        // Create service
+        Service service = def.createService();
+        service.setQName(new QName(def.getTargetNamespace(), serviceName));
+        Port port = def.createPort();
+        port.setName(portName);
+        port.setBinding(binding);
+        SOAPAddress address = new SOAPAddressImpl();
+        address.setLocationURI(locationUri);
+        port.addExtensibilityElement(address);
+        service.addPort(port);
+        def.addService(service);
+    }
+    
+    public static Definition decorate(Definition definition,
+                                      String importUri,
+                                      String targetNamespace,
+                                      String locationUri) throws Exception {
+        // Create definition
+        Definition def = createImportDef(definition, targetNamespace, importUri);
+        
+        // Iterator through port types
+        for (Iterator it = definition.getPortTypes().values().iterator(); it.hasNext();)
{
+            PortType portType = (PortType) it.next();
+            decorate(def, portType, locationUri);
+        }
+        return def;
+    }
+    
+    public static void main(String[] args) throws Exception {
+        File file = new File(args[0]);
+        Definition def = WSDLFactory.newInstance().newWSDLReader().readWSDL(file.getParent(),
file.getName());
+        Definition newDef = decorate(def, file.getName(), "urn:target", "http://localhost");
+        WSDLFactory.newInstance().newWSDLWriter().writeWSDL(newDef, new FileOutputStream(args[1]));
+        
+    }
+    
+}

Modified: incubator/servicemix/trunk/servicemix-http/src/test/java/org/apache/servicemix/http/HttpXBeanDeployerTest.java
URL: http://svn.apache.org/viewcvs/incubator/servicemix/trunk/servicemix-http/src/test/java/org/apache/servicemix/http/HttpXBeanDeployerTest.java?rev=391395&r1=391394&r2=391395&view=diff
==============================================================================
--- incubator/servicemix/trunk/servicemix-http/src/test/java/org/apache/servicemix/http/HttpXBeanDeployerTest.java
(original)
+++ incubator/servicemix/trunk/servicemix-http/src/test/java/org/apache/servicemix/http/HttpXBeanDeployerTest.java
Tue Apr  4 13:00:24 2006
@@ -28,21 +28,21 @@
 import javax.wsdl.PortType;
 import javax.wsdl.Service;
 import javax.wsdl.factory.WSDLFactory;
+import javax.wsdl.xml.WSDLReader;
 import javax.xml.namespace.QName;
 
+import junit.framework.TestCase;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.servicemix.client.DefaultServiceMixClient;
 import org.apache.servicemix.components.util.EchoComponent;
-import org.apache.servicemix.http.HttpComponent;
 import org.apache.servicemix.jbi.container.ActivationSpec;
 import org.apache.servicemix.jbi.container.JBIContainer;
 import org.apache.servicemix.jbi.jaxp.SourceTransformer;
 import org.apache.servicemix.jbi.jaxp.StringSource;
 import org.w3c.dom.Document;
 
-import junit.framework.TestCase;
-
 public class HttpXBeanDeployerTest extends TestCase {
 
     private static Log logger =  LogFactory.getLog(HttpSpringTest.class);
@@ -77,6 +77,7 @@
                     type.setUndefined(false);
                     type.setQName(new QName("http://test", "MyConsumerInterface"));
                     Binding binding = def.createBinding();
+                    binding.setQName(new QName("http://test", "MyConsumerBinding"));
                     binding.setUndefined(false);
                     binding.setPortType(type);
                     Service svc = def.createService();
@@ -139,6 +140,52 @@
         } else {
             logger.info(new SourceTransformer().toString(me.getOutMessage().getContent()));
         }
+    }
+    
+    public void testWithNonStandaloneWsdl() throws Exception {
+        // HTTP Component
+        HttpComponent component = new HttpComponent();
+        container.activateComponent(component, "HTTPComponent");
+        
+        // Add a receiver component
+        ActivationSpec asEcho = new ActivationSpec("echo", new EchoComponent() {
+            public Document getServiceDescription(ServiceEndpoint endpoint) {
+                try {
+                    Definition def = WSDLFactory.newInstance().newDefinition();
+                    PortType type = def.createPortType();
+                    type.setUndefined(false);
+                    type.setQName(new QName("http://porttype.test", "MyConsumerInterface"));
+                    def.setTargetNamespace("http://porttype.test");
+                    def.addNamespace("tns", "http://porttype.test");
+                    def.addPortType(type);
+                    Document doc = WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
+                    return doc;
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+        asEcho.setEndpoint("myConsumer");
+        asEcho.setService(new QName("http://test", "MyConsumerService"));
+        container.activateComponent(asEcho);
+        
+        // Start container
+        container.start();
+
+        // Deploy SU
+        URL url = getClass().getClassLoader().getResource("xbean/xbean.xml");
+        File path = new File(new URI(url.toString()));
+        path = path.getParentFile();
+        component.getServiceUnitManager().deploy("xbean", path.getAbsolutePath());
+        component.getServiceUnitManager().start("xbean");
+
+        // Test WSDL
+        WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
+        Definition def;
+        def = reader.readWSDL("http://localhost:8192/Service/?wsdl");
+        assertNotNull(def);
+        assertNotNull(def.getImports());
+        assertEquals(1, def.getImports().size());
     }
     
 }



Mime
View raw message