airavata-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shame...@apache.org
Subject airavata git commit: Fixed AIRAVATA-1594 - Save workflow inputs and outputs. Renamed workflow-core artifact id to airavata-workflow-core
Date Mon, 30 Mar 2015 16:39:42 GMT
Repository: airavata
Updated Branches:
  refs/heads/master dbe9c8cb9 -> 17b8740c2


Fixed AIRAVATA-1594 - Save workflow inputs and outputs. Renamed workflow-core artifact id
to airavata-workflow-core


Project: http://git-wip-us.apache.org/repos/asf/airavata/repo
Commit: http://git-wip-us.apache.org/repos/asf/airavata/commit/17b8740c
Tree: http://git-wip-us.apache.org/repos/asf/airavata/tree/17b8740c
Diff: http://git-wip-us.apache.org/repos/asf/airavata/diff/17b8740c

Branch: refs/heads/master
Commit: 17b8740c2a613c17fc12d5bd869fb1e07dd3b573
Parents: dbe9c8c
Author: shamrath <shameerainfo@gmail.com>
Authored: Mon Mar 30 12:39:19 2015 -0400
Committer: shamrath <shameerainfo@gmail.com>
Committed: Mon Mar 30 12:39:19 2015 -0400

----------------------------------------------------------------------
 .../client/samples/RegisterSampleData.java      |   9 ++
 .../appcatalog/cpi/WorkflowCatalog.java         |   4 +
 .../catalog/data/impl/WorkflowCatalogImpl.java  |  21 ++++
 .../data/resources/WorkflowOutputResource.java  |   4 +-
 .../airavata-orchestrator-service/pom.xml       |   2 +-
 modules/workflow/workflow-core/pom.xml          |   3 +-
 .../core/SimpleWorkflowInterpreter.java         |  18 ++++
 .../core/parser/AiravataWorkflowParser.java     |   1 +
 .../ui/dialogs/registry/RegistryWindow.java     |   2 +-
 .../WorkflowInterpreterLaunchWindow.java        | 105 +++++++++++--------
 10 files changed, 120 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/airavata-api/airavata-client-sdks/java-client-samples/src/main/java/org/apache/airavata/client/samples/RegisterSampleData.java
----------------------------------------------------------------------
diff --git a/airavata-api/airavata-client-sdks/java-client-samples/src/main/java/org/apache/airavata/client/samples/RegisterSampleData.java
b/airavata-api/airavata-client-sdks/java-client-samples/src/main/java/org/apache/airavata/client/samples/RegisterSampleData.java
index c9017c3..75413cb 100644
--- a/airavata-api/airavata-client-sdks/java-client-samples/src/main/java/org/apache/airavata/client/samples/RegisterSampleData.java
+++ b/airavata-api/airavata-client-sdks/java-client-samples/src/main/java/org/apache/airavata/client/samples/RegisterSampleData.java
@@ -29,6 +29,10 @@ import org.apache.airavata.model.appcatalog.appinterface.DataType;
 import org.apache.airavata.model.appcatalog.appinterface.InputDataObjectType;
 import org.apache.airavata.model.appcatalog.appinterface.OutputDataObjectType;
 import org.apache.airavata.model.appcatalog.computeresource.ComputeResourceDescription;
+import org.apache.airavata.model.appcatalog.computeresource.DataMovementInterface;
+import org.apache.airavata.model.appcatalog.computeresource.DataMovementProtocol;
+import org.apache.airavata.model.appcatalog.computeresource.JobSubmissionInterface;
+import org.apache.airavata.model.appcatalog.computeresource.JobSubmissionProtocol;
 import org.apache.airavata.model.appcatalog.computeresource.LOCALSubmission;
 import org.apache.airavata.model.appcatalog.computeresource.ResourceJobManager;
 import org.apache.airavata.model.appcatalog.computeresource.ResourceJobManagerType;
@@ -109,6 +113,11 @@ public class RegisterSampleData {
 
             ComputeResourceDescription computeResourceDescription = RegisterSampleApplicationsUtils.
                     createComputeResourceDescription("localhost", "LocalHost", null, null);
+            DataMovementInterface dataMovementInterface = new DataMovementInterface("localhost_data_movement_interface",
DataMovementProtocol.LOCAL, 1);
+            computeResourceDescription.addToDataMovementInterfaces(dataMovementInterface);
+            JobSubmissionInterface jobSubmissionInterface = new JobSubmissionInterface("localhost_job_submission_interface",
JobSubmissionProtocol.LOCAL, 1);
+            computeResourceDescription.addToJobSubmissionInterfaces(jobSubmissionInterface);
+
             localhostId = airavataClient.registerComputeResource(computeResourceDescription);
             ResourceJobManager resourceJobManager = RegisterSampleApplicationsUtils.
                     createResourceJobManager(ResourceJobManagerType.FORK, null, null, null);

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/app-catalog/app-catalog-cpi/src/main/java/org/airavata/appcatalog/cpi/WorkflowCatalog.java
----------------------------------------------------------------------
diff --git a/modules/app-catalog/app-catalog-cpi/src/main/java/org/airavata/appcatalog/cpi/WorkflowCatalog.java
b/modules/app-catalog/app-catalog-cpi/src/main/java/org/airavata/appcatalog/cpi/WorkflowCatalog.java
index 538dc01..6beeb60 100644
--- a/modules/app-catalog/app-catalog-cpi/src/main/java/org/airavata/appcatalog/cpi/WorkflowCatalog.java
+++ b/modules/app-catalog/app-catalog-cpi/src/main/java/org/airavata/appcatalog/cpi/WorkflowCatalog.java
@@ -21,6 +21,8 @@
 
 package org.airavata.appcatalog.cpi;
 
+import org.apache.airavata.model.appcatalog.appinterface.OutputDataObjectType;
+
 import java.util.List;
 
 public interface WorkflowCatalog {
@@ -38,4 +40,6 @@ public interface WorkflowCatalog {
     public String getWorkflowTemplateId(String workflowName) throws AppCatalogException;
 
     public boolean isWorkflowExistWithName(String workflowName) throws AppCatalogException;
+
+    public void updateWorkflowOutputs(String workflowTemplateId, List<OutputDataObjectType>
workflowOutputs) throws AppCatalogException;
 }

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/impl/WorkflowCatalogImpl.java
----------------------------------------------------------------------
diff --git a/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/impl/WorkflowCatalogImpl.java
b/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/impl/WorkflowCatalogImpl.java
index 7aaf1bd..0c3f2ad 100644
--- a/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/impl/WorkflowCatalogImpl.java
+++ b/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/impl/WorkflowCatalogImpl.java
@@ -208,4 +208,25 @@ public class WorkflowCatalogImpl implements WorkflowCatalog {
         }
         return false;
     }
+
+    @Override
+    public void updateWorkflowOutputs(String workflowTemplateId, List<OutputDataObjectType>
workflowOutputs) throws AppCatalogException {
+        WorkflowResource resource = new WorkflowResource();
+        WorkflowResource existingWF = (WorkflowResource)resource.get(workflowTemplateId);
+        if (workflowOutputs != null && workflowOutputs.size() != 0) {
+            for (OutputDataObjectType output : workflowOutputs) {
+                WorkflowOutputResource outputResource = new WorkflowOutputResource();
+                Map<String, String> ids = new HashMap<String, String>();
+                ids.put(AbstractResource.WFOutputConstants.WF_TEMPLATE_ID, existingWF.getWfTemplateId());
+                ids.put(AbstractResource.WFOutputConstants.OUTPUT_KEY, output.getName());
+                WorkflowOutputResource existingOutput = (WorkflowOutputResource) outputResource.get(ids);
+                existingOutput.setWorkflowResource(existingWF);
+                existingOutput.setOutputKey(output.getName());
+                existingOutput.setOutputVal(output.getValue());
+                existingOutput.setWfTemplateId(existingWF.getWfTemplateId());
+                existingOutput.setDataType(output.getType().toString());
+                existingOutput.save();
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/resources/WorkflowOutputResource.java
----------------------------------------------------------------------
diff --git a/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/resources/WorkflowOutputResource.java
b/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/resources/WorkflowOutputResource.java
index b8f7bbf..7f180bd 100644
--- a/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/resources/WorkflowOutputResource.java
+++ b/modules/app-catalog/app-catalog-data/src/main/java/org/apache/aiaravata/application/catalog/data/resources/WorkflowOutputResource.java
@@ -276,7 +276,7 @@ public class WorkflowOutputResource extends AbstractResource {
                 existingWorkflowOutput.setWorkflow(workflow);
                 existingWorkflowOutput.setDataType(dataType);
                 existingWorkflowOutput.setOutputKey(outputKey);
-                if (outputKey != null){
+                if (outputVal != null){
                     existingWorkflowOutput.setOutputVal(outputVal.toCharArray());
                 }
                 existingWorkflowOutput.setValidityType(validityType);
@@ -290,7 +290,7 @@ public class WorkflowOutputResource extends AbstractResource {
                 workflowOutput.setWorkflow(workflow);
                 workflowOutput.setDataType(dataType);
                 workflowOutput.setOutputKey(outputKey);
-                if (outputKey != null){
+                if (outputVal != null){
                     workflowOutput.setOutputVal(outputVal.toCharArray());
                 }
                 workflowOutput.setValidityType(validityType);

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/orchestrator/airavata-orchestrator-service/pom.xml
----------------------------------------------------------------------
diff --git a/modules/orchestrator/airavata-orchestrator-service/pom.xml b/modules/orchestrator/airavata-orchestrator-service/pom.xml
index c6ab2f4..3c1a6a6 100644
--- a/modules/orchestrator/airavata-orchestrator-service/pom.xml
+++ b/modules/orchestrator/airavata-orchestrator-service/pom.xml
@@ -52,7 +52,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.airavata</groupId>
-            <artifactId>workflow-core</artifactId>
+            <artifactId>airavata-workflow-core</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/workflow/workflow-core/pom.xml
----------------------------------------------------------------------
diff --git a/modules/workflow/workflow-core/pom.xml b/modules/workflow/workflow-core/pom.xml
index 1cb8e0d..2983924 100644
--- a/modules/workflow/workflow-core/pom.xml
+++ b/modules/workflow/workflow-core/pom.xml
@@ -8,8 +8,7 @@
         <version>0.15-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>workflow-core</artifactId>
+    <artifactId>airavata-workflow-core</artifactId>
     <name>Airavata Workflow Core</name>
 
     <dependencies>

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/SimpleWorkflowInterpreter.java
----------------------------------------------------------------------
diff --git a/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/SimpleWorkflowInterpreter.java
b/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/SimpleWorkflowInterpreter.java
index a674aad..778fee2 100644
--- a/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/SimpleWorkflowInterpreter.java
+++ b/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/SimpleWorkflowInterpreter.java
@@ -21,6 +21,8 @@
 
 package org.apache.airavata.workflow.core;
 
+import org.airavata.appcatalog.cpi.AppCatalogException;
+import org.apache.aiaravata.application.catalog.data.impl.AppCatalogFactory;
 import org.apache.airavata.common.exception.AiravataException;
 import org.apache.airavata.common.utils.AiravataUtils;
 import org.apache.airavata.messaging.core.MessageContext;
@@ -151,6 +153,22 @@ class SimpleWorkflowInterpreter{
             addToProcessingQueue(processContext);
             publishToProcessQueue(process);
         }
+        if (processingQueue.isEmpty()) {
+            try {
+                saveWorkflowOutputs();
+            } catch (AppCatalogException e) {
+                throw new AiravataException("Error while updating completed workflow outputs
to registry", e);
+            }
+        }
+    }
+
+    private void saveWorkflowOutputs() throws AppCatalogException {
+        List<OutputDataObjectType> outputDataObjects = new ArrayList<OutputDataObjectType>();
+        for (WorkflowOutputNode completeWorkflowOutput : completeWorkflowOutputs) {
+            outputDataObjects.add(completeWorkflowOutput.getOutputObject());
+        }
+        AppCatalogFactory.getAppCatalog().getWorkflowCatalog()
+                .updateWorkflowOutputs(experiment.getApplicationId(), outputDataObjects);
     }
 
 

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/parser/AiravataWorkflowParser.java
----------------------------------------------------------------------
diff --git a/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/parser/AiravataWorkflowParser.java
b/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/parser/AiravataWorkflowParser.java
index 1e1a5c5..185671d 100644
--- a/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/parser/AiravataWorkflowParser.java
+++ b/modules/workflow/workflow-core/src/main/java/org/apache/airavata/workflow/core/parser/AiravataWorkflowParser.java
@@ -160,6 +160,7 @@ public class AiravataWorkflowParser implements WorkflowParser {
         WorkflowOutputNodeImpl workflowOutputNode = new WorkflowOutputNodeImpl(oNode.getID(),
oNode.getName());
         OutputDataObjectType outputDataObjectType = new OutputDataObjectType();
         outputDataObjectType.setType(oNode.getParameterType());
+        outputDataObjectType.setName(oNode.getID());
         workflowOutputNode.setOutputObject(outputDataObjectType);
         return workflowOutputNode;
     }

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/dialogs/registry/RegistryWindow.java
----------------------------------------------------------------------
diff --git a/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/dialogs/registry/RegistryWindow.java
b/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/dialogs/registry/RegistryWindow.java
index 0b5f2c1..cbbf588 100644
--- a/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/dialogs/registry/RegistryWindow.java
+++ b/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/dialogs/registry/RegistryWindow.java
@@ -124,7 +124,7 @@ public class RegistryWindow {
         this.usernameTextField = new XBayaTextField();
         this.serverTextField.setText("localhost");
         this.portTextField.setText("8930");
-        this.gatewayIdTextField.setText("airavata");
+        this.gatewayIdTextField.setText("sample");
         this.usernameTextField.setText("airavata");
         ThriftClientData thriftClientData = engine.getConfiguration().getThriftClientData(ThriftServiceType.API_SERVICE);
     	if (thriftClientData!=null){

http://git-wip-us.apache.org/repos/asf/airavata/blob/17b8740c/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/experiment/WorkflowInterpreterLaunchWindow.java
----------------------------------------------------------------------
diff --git a/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/experiment/WorkflowInterpreterLaunchWindow.java
b/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/experiment/WorkflowInterpreterLaunchWindow.java
index 1678f19..5ae0c94 100644
--- a/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/experiment/WorkflowInterpreterLaunchWindow.java
+++ b/modules/xbaya-gui/src/main/java/org/apache/airavata/xbaya/ui/experiment/WorkflowInterpreterLaunchWindow.java
@@ -268,62 +268,74 @@ public class WorkflowInterpreterLaunchWindow {
     }
 
     private void execute() throws AiravataClientConnectException, TException {
-    	ThriftClientData thriftClientData = engine.getConfiguration().getThriftClientData(ThriftServiceType.API_SERVICE);
-		Client airavataClient = XBayaUtil.getAiravataClient(thriftClientData);
-        String gatewayId = engine.getConfiguration().getThriftClientData(ThriftServiceType.API_SERVICE).getGatewayId();
-
-		Workflow workflowClone = workflow.clone();
-		workflowClone.setName(workflowClone.getName()+UUID.randomUUID().toString());
-		org.apache.airavata.model.Workflow w = new org.apache.airavata.model.Workflow();
-		w.setName(workflowClone.getName());
-        w.setGraph(JSONUtil.jsonElementToString(workflowClone.toJSON()));
-        w.setTemplateId(airavataClient.registerWorkflow(gatewayId, w));
         String instanceName = this.instanceNameTextField.getText();
         if (instanceName.trim().equals("")){
-        	JOptionPane.showMessageDialog(engine.getGUI().getFrame(),
-        		    "Experiment name cannot be empty",
-        		    "Experiment Name",
-        		    JOptionPane.ERROR_MESSAGE);
-        	return;
+            JOptionPane.showMessageDialog(engine.getGUI().getFrame(),
+                    "Experiment name cannot be empty",
+                    "Experiment Name",
+                    JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        ThriftClientData thriftClientData = engine.getConfiguration().getThriftClientData(ThriftServiceType.API_SERVICE);
+        Client airavataClient = XBayaUtil.getAiravataClient(thriftClientData);
+        String gatewayId = engine.getConfiguration().getThriftClientData(ThriftServiceType.API_SERVICE).getGatewayId();
+
+        final List<InputNode> inputNodes = GraphUtil.getInputNodes(this.workflow.getGraph());
+        List<InputDataObjectType> inputDataTypes = new ArrayList<InputDataObjectType>();
+        List<OutputDataObjectType> outputDataTypes = new ArrayList<OutputDataObjectType>();
+        InputDataObjectType input = null;
+        for (int i = 0; i < inputNodes.size(); i++) {
+            InputNode inputNode = inputNodes.get(i);
+            XBayaTextField parameterTextField = this.parameterTextFields.get(i);
+            inputNode.getID();
+            String value = parameterTextField.getText();
+            input = new InputDataObjectType();
+//            inputNode.setDefaultValue(value);
+            input.setName(inputNode.getID());
+            input.setType(inputNode.getDataType());
+            input.setValue(value);
+            input.setApplicationArgument(inputNode.getApplicationArgument());
+            input.setInputOrder(inputNode.getInputOrder());
+            inputDataTypes.add(input);
+
         }
-        //previous instance name
-        if (!instanceNameTextField.getText().equals("")){
-            this.instanceNameTextField.setText("");
+        final List<OutputNode> outputNodes = GraphUtil.getOutputNodes(this.workflow.getGraph());
+        OutputDataObjectType output = null;
+        for (OutputNode outputNode : outputNodes) {
+            output = new OutputDataObjectType();
+            output.setName(outputNode.getID());
+            output.setType(DataType.STRING);
+            outputDataTypes.add(output);
         }
+
+        Workflow workflowClone = workflow.clone();
+        workflowClone.setName(workflowClone.getName() + UUID.randomUUID().toString());
+        org.apache.airavata.model.Workflow workflowModel = new org.apache.airavata.model.Workflow();
+        workflowModel.setName(workflowClone.getName());
+        workflowModel.setGraph(JSONUtil.jsonElementToString(workflowClone.toJSON()));
+        for (InputDataObjectType inputDataType : inputDataTypes) {
+            workflowModel.addToWorkflowInputs(inputDataType);
+        }
+        for (OutputDataObjectType outputDataType : outputDataTypes) {
+            workflowModel.addToWorkflowOutputs(outputDataType);
+        }
+        workflowModel.setTemplateId(airavataClient.registerWorkflow(gatewayId, workflowModel));
         // Use topic as a base of workflow instance ID so that the monitor can
         // find it.
         Project project = new Project();
         project.setName("project1");
         project.setOwner(thriftClientData.getUsername());
         project.setProjectID(airavataClient.createProject(gatewayId, project));
-        final List<InputNode> inputNodes = GraphUtil.getInputNodes(this.workflow.getGraph());
         final Experiment experiment = new Experiment();
-        experiment.setApplicationId(w.getTemplateId());
+        experiment.setApplicationId(workflowModel.getTemplateId());
         experiment.setName(instanceName);
         experiment.setProjectID(project.getProjectID());
         experiment.setUserName(thriftClientData.getUsername());
-        for (int i = 0; i < inputNodes.size(); i++) {
-            InputNode inputNode = inputNodes.get(i);
-            XBayaTextField parameterTextField = this.parameterTextFields.get(i);
-            inputNode.getID();
-            String value = parameterTextField.getText();
-//            inputNode.setDefaultValue(value);
-            InputDataObjectType elem = new InputDataObjectType();
-            elem.setName(inputNode.getID());
-            elem.setType(inputNode.getDataType());
-            elem.setValue(value);
-            elem.setApplicationArgument(inputNode.getApplicationArgument());
-            elem.setInputOrder(inputNode.getInputOrder());
-
-			experiment.addToExperimentInputs(elem );
+        for (InputDataObjectType inputDataType : inputDataTypes) {
+            experiment.addToExperimentInputs(inputDataType);
         }
-        final List<OutputNode> outputNodes = GraphUtil.getOutputNodes(this.workflow.getGraph());
-        OutputDataObjectType outputDataObjectType = null;
-        for (OutputNode outputNode : outputNodes) {
-            outputDataObjectType = new OutputDataObjectType();
-            outputDataObjectType.setName(outputNode.getName());
-            outputDataObjectType.setType(DataType.STRING);
-            experiment.addToExperimentOutputs(outputDataObjectType);
+        for (OutputDataObjectType outputDataType : outputDataTypes) {
+            experiment.addToExperimentOutputs(outputDataType);
         }
         // Add scheduling configurations
         if (host != null && host.getSelectedIndex() >= 0) {
@@ -379,10 +391,17 @@ public class WorkflowInterpreterLaunchWindow {
             logger.error("Error while subscribing with experiment Id : " + experiment.getExperimentID(),
e);
         }
         airavataClient.launchExperiment(experiment.getExperimentID(), token.getText());
+
+        clean();
         hide();
     }
-    
-	private OrchestratorService.Client getOrchestratorClient() {
+
+    private void clean() {
+        this.instanceNameTextField.setText("");
+        this.token.setText("");
+    }
+
+    private OrchestratorService.Client getOrchestratorClient() {
 		final int serverPort = Integer.parseInt(ServerSettings.getSetting(org.apache.airavata.common.utils.Constants.ORCHESTRATOR_SERVER_PORT,"8940"));
         final String serverHost = ServerSettings.getSetting(org.apache.airavata.common.utils.Constants.ORCHESTRATOR_SERVER_HOST,
null);
         try {


Mime
View raw message