Fix issue with RealizedFlow XML too big
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 29 Jul 2009 14:27:55 +0000 (14:27 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 29 Jul 2009 14:27:55 +0000 (14:27 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2829 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

modules/server/org.argeo.slc.webapp.war/WEB-INF/slc-service-servlet.xml
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/attachment/AttachmentsStorage.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/attachment/FileAttachmentsStorage.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/attachment/SimpleAttachment.java
runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/GetSlcExecution.java
runtime/org.argeo.slc.server/src/main/java/org/argeo/slc/web/mvc/process/NewSlcExecutionController.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java

index b4143a3ca2f88935dfbe33d797d55c0472eeab3f..c381a31e3e903b76a358f85985a135acd8c4b1f7 100644 (file)
@@ -59,6 +59,7 @@
        <bean name="/getSlcExecution.service" class="org.argeo.slc.web.mvc.process.GetSlcExecution">
                <property name="slcExecutionDao" ref="slcExecutionDao" />
                <property name="unmarshaller" ref="unmarshaller" />
+               <property name="attachmentsStorage" ref="attachmentsStorage" />
        </bean>
 
        <bean name="/newSlcExecution.service"
@@ -67,6 +68,7 @@
                <property name="unmarshaller" ref="unmarshaller" />
                <property name="marshaller" ref="marshaller" />
                <property name="slcExecutionService" ref="slcExecutionService" />
+               <property name="attachmentsStorage" ref="attachmentsStorage" />
        </bean>
 
        <bean name="/getExecutionDescriptor.service" class="org.argeo.slc.web.mvc.execution.GetModuleDescriptor">
index dfb75604ec62e93c1c4760bddceebc292f38e6df..7a5e8cdc37722aa84f31123edb69d0248b671518 100644 (file)
@@ -3,10 +3,10 @@ package org.argeo.slc.core.attachment;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-
 public interface AttachmentsStorage {
        public void retrieveAttachment(Attachment attachment,
                        OutputStream outputStream);
 
+       /** Does NOT close the provided input stream. */
        public void storeAttachment(Attachment attachment, InputStream inputStream);
 }
index 0e70805c061c602f10e678d9063ef176f503d060..ed6cf485f2db05075990dccbe7091a2f2932f079 100644 (file)
@@ -3,30 +3,55 @@ package org.argeo.slc.core.attachment;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.slc.SlcException;
+import org.springframework.beans.factory.InitializingBean;
+
+public class FileAttachmentsStorage implements AttachmentsStorage,
+               InitializingBean {
+       private final static Log log = LogFactory
+                       .getLog(FileAttachmentsStorage.class);
 
-public class FileAttachmentsStorage implements AttachmentsStorage {
        private File attachmentsDirectory;
 
-       public FileAttachmentsStorage() {
-               String osgiInstanceArea = System.getProperty("osgi.instance.area");
-               if (osgiInstanceArea != null) {
-                       if (osgiInstanceArea.startsWith("file:"))
-                               osgiInstanceArea = osgiInstanceArea.substring("file:".length());
-                       attachmentsDirectory = new File(osgiInstanceArea + File.separator
-                                       + "slcAttachments");
-               }
+       private String attachmentsTocFileName = "attachmentsToc.csv";
+
+       private DateFormat dateFormatDay = new SimpleDateFormat("yyyy-MM-dd");
+       private DateFormat dateFormatTime = new SimpleDateFormat("HH:mm:ss");
 
+       public void afterPropertiesSet() {
                if (attachmentsDirectory == null) {
-                       String tempDir = System.getProperty("java.io.tmpdir");
-                       attachmentsDirectory = new File(tempDir + File.separator
-                                       + "slcAttachments");
+
+                       String osgiInstanceArea = System.getProperty("osgi.instance.area");
+                       if (osgiInstanceArea != null) {
+                               if (osgiInstanceArea.startsWith("file:"))
+                                       osgiInstanceArea = osgiInstanceArea.substring("file:"
+                                                       .length());
+                               attachmentsDirectory = new File(osgiInstanceArea
+                                               + File.separator + "slcAttachments");
+                       }
+
+                       if (attachmentsDirectory == null) {
+                               String tempDir = System.getProperty("java.io.tmpdir");
+                               attachmentsDirectory = new File(tempDir + File.separator
+                                               + "slcAttachments");
+                       }
                }
+               if (!attachmentsDirectory.exists())
+                       attachmentsDirectory.mkdirs();
+               if (log.isDebugEnabled())
+                       log.debug("File attachment storage initialized in directory "
+                                       + attachmentsDirectory);
        }
 
        public void retrieveAttachment(Attachment attachment,
@@ -40,6 +65,8 @@ public class FileAttachmentsStorage implements AttachmentsStorage {
                        while ((read = in.read(buffer)) >= 0) {
                                outputStream.write(buffer, 0, read);
                        }
+                       if (log.isTraceEnabled())
+                               log.trace("Read " + attachment + " from " + file);
                } catch (IOException e) {
                        throw new SlcException("Cannot write attachment " + attachment
                                        + " to " + file, e);
@@ -58,6 +85,9 @@ public class FileAttachmentsStorage implements AttachmentsStorage {
                        while ((read = inputStream.read(buffer)) >= 0) {
                                out.write(buffer, 0, read);
                        }
+                       if (log.isTraceEnabled())
+                               log.trace("Wrote " + attachment + " to " + file);
+                       updateAttachmentToc(attachment, file);
                } catch (IOException e) {
                        throw new SlcException("Cannot write attachment " + attachment
                                        + " to " + file, e);
@@ -67,9 +97,37 @@ public class FileAttachmentsStorage implements AttachmentsStorage {
 
        }
 
+       /** For monitoring purposes only */
+       protected void updateAttachmentToc(Attachment attachment, File file) {
+               Date date = new Date(file.lastModified());
+               FileWriter writer = null;
+               try {
+                       writer = new FileWriter(attachmentsDirectory + File.separator
+                                       + attachmentsTocFileName, true);
+                       writer.append(dateFormatDay.format(date));
+                       writer.append(',');
+                       writer.append(dateFormatTime.format(date));
+                       writer.append(',');
+                       writer.append(attachment.getUuid());
+                       writer.append(',');
+                       writer.append(attachment.getName());
+                       writer.append(',');
+                       writer.append(attachment.getContentType());
+                       writer.append(',');
+                       writer.append(Long.toString(file.length()));
+                       writer.append(',');
+                       writer.append(file.getCanonicalPath());
+                       writer.append('\n');
+               } catch (IOException e) {
+                       log.warn("Could not update attachments TOC for " + attachment
+                                       + " and file " + file, e);
+               } finally {
+                       IOUtils.closeQuietly(writer);
+               }
+
+       }
+
        protected File getFile(Attachment attachment) {
-               if (!attachmentsDirectory.exists())
-                       attachmentsDirectory.mkdirs();
                File file = new File(attachmentsDirectory + File.separator
                                + attachment.getUuid());
                return file;
index 1c1f13eb9319ec98b8157c87a0166757b780efcc..29b1093115c45cb85edbf68a0a228e93d35820f9 100644 (file)
@@ -7,6 +7,16 @@ public class SimpleAttachment implements Attachment {
        private String name;
        private String contentType = "";
 
+       public SimpleAttachment() {
+       }
+
+       public SimpleAttachment(String uuid, String name, String contentType) {
+               super();
+               this.uuid = uuid;
+               this.name = name;
+               this.contentType = contentType;
+       }
+
        public String getUuid() {
                return uuid;
        }
index eea87a6ab8abadd980cd727a76f1121c49483d88..fde2e932e0d6b0b1c1746d03064b8111582c0f55 100644 (file)
@@ -1,21 +1,33 @@
 package org.argeo.slc.web.mvc.process;\r
 \r
+import java.io.ByteArrayInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+\r
 import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
+import javax.xml.transform.stream.StreamSource;\r
 \r
+import org.apache.commons.io.IOUtils;\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+import org.argeo.slc.core.attachment.Attachment;\r
+import org.argeo.slc.core.attachment.AttachmentsStorage;\r
 import org.argeo.slc.dao.process.SlcExecutionDao;\r
 import org.argeo.slc.msg.ObjectList;\r
 import org.argeo.slc.process.SlcExecution;\r
 import org.argeo.slc.web.mvc.AbstractServiceController;\r
 import org.springframework.oxm.Unmarshaller;\r
 import org.springframework.web.servlet.ModelAndView;\r
-import org.springframework.xml.transform.StringSource;\r
 \r
 /** Lists SLC executions possibly filtering them. */\r
 public class GetSlcExecution extends AbstractServiceController {\r
+       private final static Log log = LogFactory.getLog(GetSlcExecution.class);\r
+\r
        private SlcExecutionDao slcExecutionDao;\r
        private Unmarshaller unmarshaller;\r
 \r
+       private AttachmentsStorage attachmentsStorage;\r
+\r
        @Override\r
        protected void handleServiceRequest(HttpServletRequest request,\r
                        HttpServletResponse response, ModelAndView modelAndView)\r
@@ -23,14 +35,41 @@ public class GetSlcExecution extends AbstractServiceController {
                String uuid = request.getParameter("uuid");\r
                SlcExecution slcExecution = slcExecutionDao.getSlcExecution(uuid);\r
 \r
-               StringSource source = new StringSource(slcExecution\r
-                               .getRealizedFlowsXml());\r
-               ObjectList ol2 = (ObjectList) unmarshaller.unmarshal(source);\r
-               ol2.fill(slcExecution.getRealizedFlows());\r
+               // StringSource source = new StringSource(slcExecution\r
+               // .getRealizedFlowsXml());\r
+               // ObjectList ol2 = (ObjectList) unmarshaller.unmarshal(source);\r
+               // ol2.fill(slcExecution.getRealizedFlows());\r
+               retrieveRealizedFlows(slcExecution);\r
 \r
                modelAndView.addObject(slcExecution);\r
        }\r
 \r
+       protected void retrieveRealizedFlows(SlcExecution slcExecution) {\r
+               Attachment attachment = NewSlcExecutionController\r
+                               .realizedFlowsAttachment(slcExecution.getRealizedFlowsXml(),\r
+                                               slcExecution);\r
+\r
+               ByteArrayOutputStream out = null;\r
+               ByteArrayInputStream in = null;\r
+               try {\r
+                       // TODO: optimize with piped streams\r
+                       out = new ByteArrayOutputStream();\r
+                       attachmentsStorage.retrieveAttachment(attachment, out);\r
+\r
+                       byte[] arr = out.toByteArray();\r
+                       in = new ByteArrayInputStream(arr);\r
+                       StreamSource source = new StreamSource(in);\r
+                       ObjectList ol = (ObjectList) unmarshaller.unmarshal(source);\r
+                       ol.fill(slcExecution.getRealizedFlows());\r
+               } catch (Exception e) {\r
+                       log.error("Could not retrieve realized flows from attachment #"\r
+                                       + attachment.getUuid(), e);\r
+               } finally {\r
+                       IOUtils.closeQuietly(in);\r
+                       IOUtils.closeQuietly(out);\r
+               }\r
+       }\r
+\r
        public void setSlcExecutionDao(SlcExecutionDao slcExecutionDao) {\r
                this.slcExecutionDao = slcExecutionDao;\r
        }\r
@@ -39,4 +78,8 @@ public class GetSlcExecution extends AbstractServiceController {
                this.unmarshaller = unmarshaller;\r
        }\r
 \r
+       public void setAttachmentsStorage(AttachmentsStorage attachmentsStorage) {\r
+               this.attachmentsStorage = attachmentsStorage;\r
+       }\r
+\r
 }\r
index d4a67b19d91ed51f1cdcb061b8bf692b73a3dd22..5f225bff54ba0f09066d8ebb7ebffad8480f8a81 100644 (file)
@@ -1,13 +1,19 @@
 package org.argeo.slc.web.mvc.process;\r
 \r
 import java.io.BufferedReader;\r
+import java.io.ByteArrayInputStream;\r
+import java.io.InputStream;\r
 import java.util.UUID;\r
 \r
 import javax.servlet.http.HttpServletRequest;\r
 import javax.servlet.http.HttpServletResponse;\r
 \r
+import org.apache.commons.io.IOUtils;\r
 import org.apache.commons.logging.Log;\r
 import org.apache.commons.logging.LogFactory;\r
+import org.argeo.slc.core.attachment.Attachment;\r
+import org.argeo.slc.core.attachment.AttachmentsStorage;\r
+import org.argeo.slc.core.attachment.SimpleAttachment;\r
 import org.argeo.slc.msg.MsgConstants;\r
 import org.argeo.slc.msg.ObjectList;\r
 import org.argeo.slc.process.SlcExecution;\r
@@ -33,6 +39,8 @@ public class NewSlcExecutionController extends AbstractServiceController {
        private Marshaller marshaller;\r
        private SlcExecutionService slcExecutionService;\r
 \r
+       private AttachmentsStorage attachmentsStorage;\r
+\r
        @Override\r
        protected void handleServiceRequest(HttpServletRequest request,\r
                        HttpServletResponse response, ModelAndView modelAndView)\r
@@ -76,10 +84,11 @@ public class NewSlcExecutionController extends AbstractServiceController {
                                new SlcExecutionStep(SlcExecutionStep.TYPE_START,\r
                                                "Process started from the Web UI"));\r
 \r
-               ObjectList ol = new ObjectList(slcExecution.getRealizedFlows());\r
-               StringResult result = new StringResult();\r
-               marshaller.marshal(ol, result);\r
-               slcExecution.setRealizedFlowsXml(result.toString());\r
+               // ObjectList ol = new ObjectList(slcExecution.getRealizedFlows());\r
+               // StringResult result = new StringResult();\r
+               // marshaller.marshal(ol, result);\r
+               // slcExecution.setRealizedFlowsXml(result.toString());\r
+               storeRealizedFlows(slcExecution);\r
 \r
                slcExecutionService.newExecution(slcExecution);\r
 \r
@@ -87,6 +96,29 @@ public class NewSlcExecutionController extends AbstractServiceController {
                agent.runSlcExecution(slcExecution);\r
        }\r
 \r
+       protected void storeRealizedFlows(SlcExecution slcExecution) {\r
+               Attachment attachment = realizedFlowsAttachment(UUID.randomUUID()\r
+                               .toString(), slcExecution);\r
+               InputStream in = null;\r
+               try {\r
+\r
+                       ObjectList ol = new ObjectList(slcExecution.getRealizedFlows());\r
+                       StringResult result = new StringResult();\r
+                       marshaller.marshal(ol, result);\r
+\r
+                       in = new ByteArrayInputStream(result.toString().getBytes());\r
+                       attachmentsStorage.storeAttachment(attachment, in);\r
+\r
+                       slcExecution.setRealizedFlowsXml(attachment.getUuid());\r
+\r
+               } catch (Exception e) {\r
+                       log.error("Could not store realized flows as attachment #"\r
+                                       + attachment.getUuid(), e);\r
+               } finally {\r
+                       IOUtils.closeQuietly(in);\r
+               }\r
+       }\r
+\r
        public void setUnmarshaller(Unmarshaller unmarshaller) {\r
                this.unmarshaller = unmarshaller;\r
        }\r
@@ -103,4 +135,15 @@ public class NewSlcExecutionController extends AbstractServiceController {
                this.marshaller = marshaller;\r
        }\r
 \r
+       public void setAttachmentsStorage(AttachmentsStorage attachmentsStorage) {\r
+               this.attachmentsStorage = attachmentsStorage;\r
+       }\r
+\r
+       /** Unify labelling in the package */\r
+       static Attachment realizedFlowsAttachment(String attachmentUuid,\r
+                       SlcExecution slcExecution) {\r
+               return new SimpleAttachment(attachmentUuid,\r
+                               "RealizedFlows of SlcExecution #" + slcExecution.getUuid(),\r
+                               "text/xml");\r
+       }\r
 }\r
index 626af3eb6770cd43f85b238e81d45b056aa66a8e..88d37c4f581db65e5087463663b6380e9bf0f543 100644 (file)
@@ -28,6 +28,8 @@ public class SlcExecution implements Serializable {
        /** TODO: Synchronize */\r
        private List<SlcExecutionStep> steps = new ArrayList<SlcExecutionStep>();\r
        private List<RealizedFlow> realizedFlows = new ArrayList<RealizedFlow>();\r
+\r
+       /** Attachment uuid. */\r
        private String realizedFlowsXml = null;\r
 \r
        public List<RealizedFlow> getRealizedFlows() {\r
@@ -145,10 +147,16 @@ public class SlcExecution implements Serializable {
                }\r
        }\r
 \r
+       /**\r
+        * Not (yet) a stable API, should not be relied upon!\r
+        * \r
+        * @return an id or an url allowing to retrieve the XML, not the XML itself!\r
+        */\r
        public String getRealizedFlowsXml() {\r
                return realizedFlowsXml;\r
        }\r
 \r
+       /** Not (yet) a stable API, should not be relied upon! */\r
        public void setRealizedFlowsXml(String realizedFlowsXml) {\r
                this.realizedFlowsXml = realizedFlowsXml;\r
        }\r