User:Jiangxin/Patch load mm file with mmx file

From FreeMind
< User:Jiangxin
Revision as of 17:48, 6 April 2006 by Jiangxin (talk | contribs) (initial)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

What is .mmx file?

.mmx file has the same file structure as FreeMind .mm file, but It only contains the unnecessary and frequently changed attributes. This file is NOT suitable for version control system.

How the file is generated? Please see this link: User:Jiangxin/Patch_save_extra_attributes_outof_mmfile.

Overview

Warning: this patch is immature, and it can cause trouble if your FreeMind .mm file is as large as 200KB!

Java expert/FreeMind Funs, can you help me to make it usable. Thank you.

the XSLT

My implementation is using a XSLT file to join the .mmx file with .mm file in runtime. The XSLT is below:

  • file : freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

	<xsl:output method="xml" version="1.0" encoding="utf-8"
		indent="yes" />

	<xsl:param name="mmx_file" />

	<xsl:template match="map">
		<map>
			<xsl:copy-of select="@*" />
			<xsl:apply-templates />
		</map>
	</xsl:template>

	<xsl:template match="node">
		<xsl:param name="mmx_node" select="document($mmx_file)" />
		<xsl:copy>
			<xsl:choose>
				<xsl:when test="$mmx_node//node[@ID=current()/@ID]">
					<xsl:for-each select="@*">
						<xsl:choose>
							<xsl:when test="local-name(.) = 'FOLDED'">
							</xsl:when>
							<xsl:otherwise>
								<xsl:copy-of select="." />
							</xsl:otherwise>
						</xsl:choose>
					</xsl:for-each>
					<xsl:copy-of
						select="$mmx_node//node[@ID=current()/@ID]/@*" />
				</xsl:when>
				<xsl:otherwise>
					<xsl:copy-of select="@*" />
				</xsl:otherwise>
			</xsl:choose>
			<xsl:apply-templates />
		</xsl:copy>
	</xsl:template>

	<xsl:template match="*">
	  <xsl:copy-of select="."/>
	</xsl:template>

</xsl:stylesheet>

Problem 1: too slow

But is is very slow if .mm file and .mmx is as big as 200KB. I test my file using xsltproc like this.

$ time xsltproc --stringparam mmx_file subject-forum.mmx freemind_join_mm_mmx.xslt subject-forum.mm > jx.mm

real    4m33.148s
user    4m30.093s
sys     0m0.015s

Problem 2: memery killer

load without .mmx file, only 40MB memery usage. But if load .mm file with .mmx file, 80MB maybe. It terrible, where is Java GC? Just a tale of sun. (Sorry, I am not familiar with Java.)


My Immature Patch

Index: freemind/freemind/modes/mindmapmode/MindMapMapModel.java
===================================================================
--- freemind/freemind/modes/mindmapmode/MindMapMapModel.java	(.../tags/RELEASE-0-8-0)	(revision 2)
+++ freemind/freemind/modes/mindmapmode/MindMapMapModel.java	(.../branches/WHFM-0-8-0)	(working copy)
@@ -519,21 +562,37 @@
         }
         // the resulting file is accessed by the reader:
         Reader reader = null;
-        if (mapStart.equals(expectedStartString)
-                || mapStart.equals(expectedAlternativeStartString)) {
-            // actual version:
-            reader = getActualReader(file);
-        } else {
+        // join .mmx with .mm file
+        reader = getActualReader(file);
+
+        if (! mapStart.equals(expectedStartString)
+                && ! mapStart.equals(expectedAlternativeStartString)) {
             // older version:
-            reader = getUpdateReader(file);
+            reader = getUpdateReader(reader, file.getName());
         }
         try {
             mapElement.parseFromReader(reader);
@@ -573,14 +602,15 @@
 
     /** Creates a reader that pipes the input file through a XSLT-Script that
      *  updates the version to the current.
-     * @param file
+     * @param reader
+     * @param filename
      * @return 
      * @throws IOException
      */
-    private Reader getUpdateReader(File file) throws IOException {
+    private Reader getUpdateReader(Reader reader, String filename) throws IOException {
         StringWriter writer = null;
         InputStream inputStream = null;
-        logger.info("Updating the file "+file.getName()+" to the current version.");
+        logger.info("Updating the file "+filename+" to the current version.");
         try{
             // try to convert map with xslt:
             URL updaterUrl=null;
@@ -598,12 +629,12 @@
             // create an instance of TransformerFactory
             TransformerFactory transFact = TransformerFactory.newInstance();
             Transformer trans = transFact.newTransformer(xsltSource);
-            trans.transform(new StreamSource(file), result);
-            logger.info("Updating the file "+file.getName()+" to the current version. Done.");
+            trans.transform(new StreamSource(reader), result);
+            logger.info("Updating the file "+filename+" to the current version. Done.");
         } catch(Exception ex) {
             ex.printStackTrace();
             // exception: we take the file itself:
-            return getActualReader(file);
+            return reader;
         } finally {
             if(inputStream!= null) {
                 inputStream.close();
@@ -618,12 +649,99 @@
     /** Creates a default reader that just reads the given file.
      * @param file
      * @return
-     * @throws FileNotFoundException
+     * @throws IOException 
      */
-    private Reader getActualReader(File file) throws FileNotFoundException {
-        return new BufferedReader(new FileReader(file));
+    private Reader getActualReaderXml(File file) throws IOException {
+        try
+        {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            Transformer transformer = tf.newTransformer();
+            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
+
+            Document doc = domBuilder.parse(file);
+            Source src = new DOMSource(doc);
+            StringWriter buffwriter = new StringWriter();
+            StreamResult result = new StreamResult(buffwriter);
+            transformer.transform(src, result);
+
+            return new StringReader(buffwriter.toString());
+        }
+        catch(Exception exp)
+        {
+        	exp.printStackTrace();
+        }
+
+        return new BufferedReader(new FileReader(file));    	
     }
 
+    private Reader getActualReader(File file) throws IOException {
+        // load .mmx file...
+        String ext = Tools.getExtension(file.getName());
+        String mmxFileName = "";
+
+        if(!ext.equals("mm")) 
+        {
+        	mmxFileName = file.getName()+".mmx";
+        }
+        else 
+        {
+        	mmxFileName = Tools.removeExtension(file.getName()) + ".mmx";
+        }
+        File mmxfile = new File(file.getParent(), mmxFileName);
+        
+        if (!mmxfile.exists())
+        {
+        	return getActualReaderXml(file);
+        }
+
+        URL updaterUrl = null;
+        InputStream inputStream = null;
+        Source xsltSource = null;
+        StringWriter buffwriter = null;
+        Result result = null;
+        TransformerFactory tf = null;
+        Transformer transformer = null;
+        String mmxFileFullName = file.getParent() + "/" + mmxFileName;
+        try {
+            // try to convert map with xslt:
+            updaterUrl = getFrame().getResource(
+                    "freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt");
+            if (updaterUrl == null) {
+                throw new IllegalArgumentException(
+                        "freemind_join_mm_mmx.xslt not found.");
+            }
+            inputStream = updaterUrl.openStream();
+            xsltSource = new StreamSource(inputStream);
+            // get output:
+            buffwriter = new StringWriter();
+            result = new StreamResult(buffwriter);
+            // create an instance of TransformerFactory
+            tf = TransformerFactory.newInstance();
+            transformer = tf.newTransformer(xsltSource);
+            transformer.setParameter("mmx_file", mmxFileFullName);
+            transformer.transform(new StreamSource(file), result);
+
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            // exception: we take the file itself:
+            return getActualReaderXml(file);
+        } finally {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+            if (buffwriter != null) {
+                buffwriter.close();
+            }
+            inputStream = null;
+            xsltSource = null;
+            updaterUrl = null;
+            result = null;
+            transformer = null;
+            tf = null;
+        }
+        return new StringReader(buffwriter.getBuffer().toString());    }
+
     //
     // cut'n'paste
     //
Index: freemind/freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt
===================================================================
--- freemind/freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt	(.../tags/RELEASE-0-8-0)	(revision 0)
+++ freemind/freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt	(.../branches/WHFM-0-8-0)	(revision 28)
@@ -0,0 +1,45 @@
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+	<xsl:output method="xml" version="1.0" encoding="utf-8"
+		indent="yes" />
+
+	<xsl:param name="mmx_file" />
+
+	<xsl:template match="map">
+		<map>
+			<xsl:copy-of select="@*" />
+			<xsl:apply-templates />
+		</map>
+	</xsl:template>
+
+	<xsl:template match="node">
+		<xsl:param name="mmx_node" select="document($mmx_file)" />
+		<xsl:copy>
+			<xsl:choose>
+				<xsl:when test="$mmx_node//node[@ID=current()/@ID]">
+					<xsl:for-each select="@*">
+						<xsl:choose>
+							<xsl:when test="local-name(.) = 'FOLDED'">
+							</xsl:when>
+							<xsl:otherwise>
+								<xsl:copy-of select="." />
+							</xsl:otherwise>
+						</xsl:choose>
+					</xsl:for-each>
+					<xsl:copy-of
+						select="$mmx_node//node[@ID=current()/@ID]/@*" />
+				</xsl:when>
+				<xsl:otherwise>
+					<xsl:copy-of select="@*" />
+				</xsl:otherwise>
+			</xsl:choose>
+			<xsl:apply-templates />
+		</xsl:copy>
+	</xsl:template>
+
+	<xsl:template match="*">
+	  <xsl:copy-of select="."/>
+	</xsl:template>
+
+</xsl:stylesheet>
Index: freemind/build.xml
===================================================================
--- freemind/build.xml	(.../tags/RELEASE-0-8-0)	(revision 2)
+++ freemind/build.xml	(.../branches/WHFM-0-8-0)	(working copy)
@@ -284,6 +284,7 @@
 				<include name="Resources*"/>
 				<include name="mindmap_menus.xml"/>
 				<include name="**/freemind_version_updater.xslt"/>
+				<include name="**/freemind_join_mm_mmx.xslt"/>
 			</fileset>
 		</jar>
 	</target>