--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"\r
+ "http://www.w3.org/TR/REC-html40/strict.dtd">\r
+<html>\r
+ <head>\r
+ <title>FileResource.java</title>\r
+ <meta name="Author" content="Benoit Mahe">\r
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">\r
+ <meta name="Generator" content="*emacs: emacs-css">\r
+\r
+ <link rel="Stylesheet" media="screen" type="text/css" href="default-html.css">\r
+ </head>\r
+ <body>\r
+\r
+ <pre>\r
+<span class="comment">// FileResource.java\r
+// $Id: FileResource.html,v 1.1 2010/06/15 12:20:06 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+</span>\r
+<span class="keyword">package</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">tools</span>.<span class="type">resources</span> ;\r
+\r
+<span class="keyword">import</span> <span class="reference">java</span>.<span class="reference">io</span>.* ;\r
+\r
+<span class="comment">/**\r
+ * A simple file resource.\r
+ */</span>\r
+<span class="reference">public</span> <span class="keyword">class</span> <span class="function-name">FileResource</span> <span class="keyword">extends</span> <span class="type">FramedResource</span> {\r
+\r
+ <span class="comment">/**\r
+ * Attributes index - The filename attribute.\r
+ */</span>\r
+ <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_FILENAME</span> = -1 ;\r
+ \r
+ <span class="comment">/**\r
+ * Attribute index - The date at which we last checked the file content.\r
+ */</span>\r
+ <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_FILESTAMP</span> = -1 ;\r
+\r
+ <span class="comment">/**\r
+ * Attribute index - The index for the content length attribute.\r
+ */</span>\r
+ <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_FILE_LENGTH</span> = -1 ;\r
+\r
+ <span class="comment">/**\r
+ * Attribute index - The index for the backup flag\r
+ */</span>\r
+ <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_FILE_BACKUP</span> = -1 ;\r
+ \r
+ <span class="type">static</span> {\r
+ <span class="type">Attribute</span> <span class="variable-name">a</span> = <span class="keyword">null</span> ;\r
+ <span class="type">Class</span> <span class="variable-name">cls</span> = <span class="keyword">null</span> ;\r
+ <span class="keyword">try</span> {\r
+ cls = Class.forName("<span class="string">org.w3c.tools.resources.FileResource</span>") ;\r
+ } <span class="keyword">catch</span> (<span class="type">Exception</span> <span class="variable-name">ex</span>) {\r
+ ex.printStackTrace();\r
+ System.exit(0);\r
+ }\r
+ <span class="comment">// The filename attribute.\r
+</span> a = <span class="keyword">new</span> <span class="type">FilenameAttribute</span>("<span class="string">filename</span>"\r
+ , <span class="keyword">null</span>\r
+ , Attribute.EDITABLE) ;\r
+ ATTR_FILENAME = AttributeRegistry.registerAttribute(cls, a) ;\r
+ <span class="comment">// The file stamp attribute\r
+</span> a = <span class="keyword">new</span> <span class="type">DateAttribute</span>("<span class="string">file-stamp</span>"\r
+ , <span class="keyword">new</span> <span class="type">Long</span>(-1) \r
+ , Attribute.COMPUTED) ;\r
+ ATTR_FILESTAMP = AttributeRegistry.registerAttribute(cls, a) ;\r
+ <span class="comment">// The file length attribute:\r
+</span> a = <span class="keyword">new</span> <span class="type">IntegerAttribute</span>("<span class="string">file-length</span>"\r
+ , <span class="keyword">null</span>\r
+ , Attribute.COMPUTED);\r
+ ATTR_FILE_LENGTH = AttributeRegistry.registerAttribute(cls,a);\r
+ <span class="comment">// The backup attribute:\r
+</span> a = <span class="keyword">new</span> <span class="type">BooleanAttribute</span>("<span class="string">backup</span>"\r
+ , <span class="reference">Boolean</span>.<span class="type">FALSE</span>\r
+ , Attribute.EDITABLE);\r
+ ATTR_FILE_BACKUP = AttributeRegistry.registerAttribute(cls,a);\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * The file we refer to.\r
+ * This is a cached version of some attributes, so we need to override\r
+ * the setValue method in order to be able to catch any changes to it.\r
+ */</span>\r
+ <span class="preprocessor">protected</span> <span class="type">File</span> <span class="variable-name">file</span> = <span class="keyword">null</span> ;\r
+\r
+ <span class="comment">/**\r
+ * Get this resource filename attribute.\r
+ */</span>\r
+ <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getFilename</span>() {\r
+ <span class="keyword">return</span> (<span class="type">String</span>) getValue(ATTR_FILENAME, <span class="keyword">null</span>);\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Get this file length\r
+ */</span>\r
+ <span class="reference">public</span> <span class="type">int</span> <span class="function-name">getFileLength</span>() {\r
+ <span class="keyword">return</span> ((<span class="type">Integer</span>) getValue(ATTR_FILE_LENGTH, \r
+ <span class="keyword">new</span> <span class="type">Integer</span>(0))).intValue();\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Get the date at which we last examined the file.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">long</span> <span class="function-name">getFileStamp</span>() {\r
+ <span class="keyword">return</span> getLong(ATTR_FILESTAMP, (<span class="type">long</span>) -1) ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Get the backup flag, create a backup file when content change\r
+ * if true.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">getBackupFlag</span>() {\r
+ <span class="keyword">return</span> getBoolean(ATTR_FILE_BACKUP, <span class="keyword">false</span>) ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Get the name of the backup file for this resource.\r
+ * </span><span class="keyword">@return </span><span class="comment">A File object suitable to receive the backup version of this\r
+ * file.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">File</span> <span class="function-name">getBackupFile</span>() {\r
+ <span class="type">File</span> <span class="variable-name">file</span> = getFile() ;\r
+ <span class="type">String</span> <span class="variable-name">name</span> = file.getName() ;\r
+ <span class="keyword">return</span> <span class="keyword">new</span> <span class="type">File</span>(file.getParent(), name+"<span class="string">~</span>") ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Save the given stream as the underlying file content.\r
+ * This method preserve the old file version in a <code>~</code> file.\r
+ * </span><span class="keyword">@param </span><span class="variable-name">in</span><span class="comment"> The input stream to use as the resource entity.\r
+ * </span><span class="keyword">@return </span><span class="comment">A boolean, <strong>true</strong> if the resource was just\r
+ * created, <strong>false</strong> otherwise.\r
+ * </span><span class="keyword">@exception </span><span class="type">IOException</span><span class="comment"> If dumping the content failed.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">synchronized</span> <span class="type">boolean</span> <span class="function-name">newContent</span>(<span class="type">InputStream</span> <span class="variable-name">in</span>) \r
+ <span class="keyword">throws</span> <span class="type">IOException</span>\r
+ {\r
+ <span class="type">File</span> <span class="variable-name">file</span> = getFile() ;\r
+ <span class="type">boolean</span> <span class="variable-name">created</span> = (! file.exists() | (file.length() == 0));\r
+ <span class="type">String</span> <span class="variable-name">name</span> = file.getName() ;\r
+ <span class="type">File</span> <span class="variable-name">temp</span> = <span class="keyword">new</span> <span class="type">File</span>(file.getParent(), "<span class="string">#</span>"+name+"<span class="string">#</span>") ;\r
+ <span class="type">String</span> <span class="variable-name">iomsg</span> = <span class="keyword">null</span> ;\r
+\r
+ <span class="comment">// We are not catching IO exceptions here, except to remove temp:\r
+</span> <span class="keyword">try</span> {\r
+ <span class="type">FileOutputStream</span> <span class="variable-name">fout</span> = <span class="keyword">new</span> <span class="type">FileOutputStream</span>(temp) ;\r
+ <span class="type">byte</span> <span class="variable-name">buf</span>[] = <span class="keyword">new</span> <span class="type">byte</span>[4096] ;\r
+ <span class="keyword">for</span> (<span class="type">int</span> <span class="variable-name">got</span> = 0 ; (got = in.read(buf)) > 0 ; )\r
+ fout.write(buf, 0, got) ;\r
+ fout.close() ;\r
+ } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {\r
+ iomsg = ex.getMessage() ;\r
+ } <span class="keyword">finally</span> {\r
+ <span class="keyword">if</span> ( iomsg != <span class="keyword">null</span> ) {\r
+ temp.delete() ;\r
+ <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">IOException</span>(iomsg) ;\r
+ } <span class="keyword">else</span> {\r
+ <span class="keyword">if</span> (getBackupFlag()) {\r
+ <span class="type">File</span> <span class="variable-name">backup</span> = getBackupFile();\r
+ <span class="keyword">if</span> ( backup.exists() )\r
+ backup.delete();\r
+ file.renameTo(getBackupFile()) ;\r
+ }\r
+ temp.renameTo(file) ;\r
+ <span class="comment">// update our attributes for this new content:\r
+</span> updateFileAttributes() ;\r
+ }\r
+ }\r
+ <span class="keyword">return</span> created;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Check this file content, and update attributes if needed.\r
+ * This method is normally called before any perform request is done, so\r
+ * that we make sure that all meta-informations is up to date before\r
+ * handling a request.\r
+ * </span><span class="keyword">@return </span><span class="comment">The time of the last update to the resource.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">long</span> <span class="function-name">checkContent</span>() {\r
+ <span class="type">File</span> <span class="variable-name">file</span> = getFile() ;\r
+ <span class="comment">// Has this resource changed since last queried ? \r
+</span> <span class="type">long</span> <span class="variable-name">lmt</span> = file.lastModified() ;\r
+ <span class="type">long</span> <span class="variable-name">cmt</span> = getFileStamp() ;\r
+ <span class="keyword">if</span> ((cmt < 0) || (cmt < lmt)) {\r
+ updateFileAttributes() ;\r
+ <span class="keyword">return</span> getLastModified() ;\r
+ } <span class="keyword">else</span> {\r
+ <span class="keyword">return</span> cmt;\r
+ }\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Set some of this resource attribute.\r
+ * We just catch here any write access to the filename's, to update \r
+ * our cache file object.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">synchronized</span> <span class="type">void</span> <span class="function-name">setValue</span>(<span class="type">int</span> <span class="variable-name">idx</span>, <span class="type">Object</span> <span class="variable-name">value</span>) {\r
+ <span class="reference">super</span>.setValue(idx, value) ;\r
+ <span class="keyword">if</span> ((idx == ATTR_FILENAME) || (idx == ATTR_IDENTIFIER))\r
+ file = <span class="keyword">null</span>;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Get this file resource file name.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">synchronized</span> <span class="type">File</span> <span class="function-name">getFile</span>() {\r
+ <span class="comment">// Have we already computed this ?\r
+</span> <span class="keyword">if</span> ( file == <span class="keyword">null</span> ) {\r
+ <span class="comment">// Get the file name:\r
+</span> <span class="type">String</span> <span class="variable-name">name</span> = getFilename() ;\r
+ <span class="keyword">if</span> ( name == <span class="keyword">null</span> )\r
+ name = getIdentifier() ;\r
+ <span class="comment">// Get the file directory:\r
+</span> <span class="type">ResourceReference</span> <span class="variable-name">rr</span> = getParent();\r
+ <span class="type">ResourceReference</span> <span class="variable-name">rrtemp</span> = <span class="keyword">null</span>;\r
+ <span class="type">Resource</span> <span class="variable-name">p</span> = <span class="keyword">null</span>;\r
+\r
+ <span class="keyword">while</span> ( <span class="keyword">true</span> ) {\r
+ <span class="keyword">try</span> {\r
+ <span class="keyword">if</span> (rr == <span class="keyword">null</span>)\r
+ <span class="keyword">return</span> <span class="keyword">null</span>;\r
+ p = rr.lock();\r
+ <span class="keyword">if</span> (p <span class="keyword">instanceof</span> <span class="type">DirectoryResource</span>) {\r
+ file = <span class="keyword">new</span> <span class="type">File</span>(((<span class="type">DirectoryResource</span>) p)\r
+ .getDirectory(), name);\r
+ <span class="keyword">return</span> file;\r
+ }\r
+ rrtemp = p.getParent();\r
+ } <span class="keyword">catch</span> (<span class="type">InvalidResourceException</span> <span class="variable-name">ex</span>) {\r
+ <span class="keyword">return</span> <span class="keyword">null</span>;\r
+ } <span class="keyword">finally</span> {\r
+ <span class="keyword">if</span> (rr != <span class="keyword">null</span>)\r
+ rr.unlock();\r
+ }\r
+ rr = rrtemp;\r
+ }\r
+ }\r
+ <span class="keyword">return</span> file ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Is that resource still wrapping an existing file ?\r
+ * If the underlying file has disappeared <string> and if</strong> the\r
+ * container directory is extensible, remove the resource.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">synchronized</span> <span class="type">boolean</span> <span class="function-name">verify</span>() \r
+ <span class="keyword">throws</span> <span class="type">MultipleLockException</span>\r
+ {\r
+ <span class="type">File</span> <span class="variable-name">file</span> = getFile();\r
+ <span class="keyword">if</span> ( ! file.exists() ) {\r
+ <span class="comment">// Is the parent extensible:\r
+</span> <span class="type">ResourceReference</span> <span class="variable-name">rr</span> = getParent();\r
+ <span class="type">ResourceReference</span> <span class="variable-name">rrtemp</span> = <span class="keyword">null</span>;\r
+ <span class="type">Resource</span> <span class="variable-name">p</span> = <span class="keyword">null</span>;\r
+\r
+ <span class="keyword">while</span> ( <span class="keyword">true</span> ) {\r
+ <span class="keyword">try</span> {\r
+ <span class="keyword">if</span> (rr == <span class="keyword">null</span>)\r
+ <span class="keyword">return</span> <span class="keyword">false</span>;\r
+ p = rr.lock();\r
+ <span class="keyword">if</span> (p <span class="keyword">instanceof</span> <span class="type">DirectoryResource</span>) {\r
+ <span class="type">DirectoryResource</span> <span class="variable-name">d</span> = (<span class="type">DirectoryResource</span>) p;\r
+ <span class="keyword">if</span> ( ! d.getExtensibleFlag() ) \r
+ <span class="keyword">return</span> <span class="keyword">false</span>;\r
+ <span class="keyword">else</span> {\r
+ <span class="comment">// Emit an error message, and delete the resource:\r
+</span> <span class="type">String</span> <span class="variable-name">msg</span> = file+\r
+ "<span class="string">: deleted, removing the FileResource.</span>";\r
+ getServer().errlog(<span class="reference">this</span>, msg);\r
+ delete();\r
+ <span class="keyword">return</span> <span class="keyword">false</span>;\r
+ }\r
+ }\r
+ rrtemp = p.getParent();\r
+ } <span class="keyword">catch</span> (<span class="type">InvalidResourceException</span> <span class="variable-name">ex</span>) {\r
+ <span class="keyword">return</span> <span class="keyword">false</span>;\r
+ } <span class="keyword">finally</span> {\r
+ <span class="keyword">if</span> (rr != <span class="keyword">null</span>)\r
+ rr.unlock();\r
+ }\r
+ rr = rrtemp;\r
+ }\r
+ } <span class="keyword">else</span> {\r
+ <span class="keyword">return</span> <span class="keyword">true</span>;\r
+ }\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Update the file related attributes.\r
+ * The file we serve has changed since the last time we checked it, if\r
+ * any of the attribute values depend on the file content, this is the\r
+ * appropriate place to recompute them.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">void</span> <span class="function-name">updateFileAttributes</span>() {\r
+ <span class="type">File</span> <span class="variable-name">file</span> = getFile() ;\r
+ setValue(ATTR_FILESTAMP, <span class="keyword">new</span> <span class="type">Long</span>(file.lastModified()));\r
+ setValue(ATTR_FILE_LENGTH, <span class="keyword">new</span> <span class="type">Integer</span>((<span class="type">int</span>)file.length()));\r
+ <span class="keyword">return</span> ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Update our computed attributes.\r
+ */</span>\r
+ \r
+ <span class="reference">public</span> <span class="type">void</span> <span class="function-name">updateAttributes</span>() {\r
+ <span class="type">long</span> <span class="variable-name">fstamp</span> = getFile().lastModified() ;\r
+ <span class="type">long</span> <span class="variable-name">stamp</span> = getLong(ATTR_FILESTAMP, -1) ;\r
+ \r
+ <span class="keyword">if</span> ((stamp < 0) || (stamp < fstamp)) \r
+ updateFileAttributes() ;\r
+ }\r
+\r
+ <span class="comment">/**\r
+ * Initialize the FileResource instance.\r
+ */</span>\r
+\r
+ <span class="reference">public</span> <span class="type">void</span> <span class="function-name">initialize</span>(<span class="type">Object</span> <span class="variable-name">values</span>[]) {\r
+ <span class="reference">super</span>.initialize(values);\r
+ disableEvent();\r
+ <span class="comment">// If we have a filename attribute, update url:\r
+</span> <span class="type">String</span> <span class="variable-name">filename</span> = getFilename();\r
+ <span class="keyword">if</span> ( filename != <span class="keyword">null</span> ) {\r
+ <span class="type">ResourceReference</span> <span class="variable-name">rr</span> = getParent();\r
+ <span class="keyword">try</span> {\r
+ <span class="type">Resource</span> <span class="variable-name">parent</span> = rr.lock();\r
+ setValue(ATTR_URL, parent.getURLPath()+filename);\r
+ } <span class="keyword">catch</span> (<span class="type">InvalidResourceException</span> <span class="variable-name">ex</span>) {\r
+ <span class="comment">//FIXME \r
+</span> } <span class="keyword">finally</span> {\r
+ rr.unlock();\r
+ }\r
+ }\r
+ enableEvent();\r
+ }\r
+\r
+}\r
+\r
+ </pre>\r
+ </body>\r
+</html>\r