diff --git a/src/fr/devinsy/xidyn/presenters/FilePresenter.java b/src/fr/devinsy/xidyn/presenters/FilePresenter.java index 5601271..b93cb54 100644 --- a/src/fr/devinsy/xidyn/presenters/FilePresenter.java +++ b/src/fr/devinsy/xidyn/presenters/FilePresenter.java @@ -1,14 +1,11 @@ package fr.devinsy.xidyn.presenters; -import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; -import java.io.StringWriter; import java.net.URI; +import java.net.URISyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; import fr.devinsy.xidyn.data.TagDataManager; import fr.devinsy.xidyn.utils.XidynUtils; @@ -16,14 +13,13 @@ import fr.devinsy.xidyn.utils.XidynUtils; /** * */ -public class FilePresenter implements Presenter +public class FilePresenter extends StringPresenter { static Logger logger = LoggerFactory.getLogger(FilePresenter.class); - private Document doc; + private File source; private String sourceFilePathname; - private long sourceFileTime; - private String doctype; + private long sourceTime; /** * @@ -75,51 +71,46 @@ public class FilePresenter implements Presenter logger.info("dynamize file [" + this.sourceFilePathname + "]"); - // Get the good tree. - File source; - if (this.sourceFilePathname.matches("file://.+")) + // + if (this.source == null) { - source = new File(new URI(this.sourceFilePathname)); + String errorMessage = "source not defined"; + logger.error(errorMessage); + result = null; + throw new Exception(errorMessage); } - else - { - source = new File(this.sourceFilePathname); - } - - if (!source.exists()) + else if (!source.exists()) { String errorMessage = "source file defined but not found (" + this.sourceFilePathname + ")"; logger.error(errorMessage); result = null; throw new Exception(errorMessage); } - else if ((this.doc == null) || (this.sourceFileTime != source.lastModified())) + else { - this.sourceFileTime = source.lastModified(); - this.doc = XidynUtils.fileToDom(this.sourceFilePathname); - if (this.doc != null) + long currentTime = this.source.lastModified(); + if ((super.getSource() == null) || (this.sourceTime != currentTime)) { - XidynUtils.addMetaTag(doc, "generator", "XID 0.0"); + super.setSource(XidynUtils.load(this.source)); + this.sourceTime = currentTime; } - this.doctype = getDoctype(this.sourceFilePathname); } // Build the web page. - StringWriter htmlCode = new StringWriter(XidynUtils.estimatedTargetLength(source.length())); - htmlCode.write(doctype); - htmlCode.write('\n'); + result = super.dynamize(data); - TagDataManager targetData; - if (data == null) - { - targetData = new TagDataManager(); - } - else - { - targetData = data; - } - DomPresenterCore.dynamize(htmlCode, doc, targetData); - result = htmlCode.getBuffer(); + // + return (result); + } + + /** + * + */ + public File getFile() + { + File result; + + result = this.source; // return (result); @@ -143,12 +134,23 @@ public class FilePresenter implements Presenter * {@inheritDoc} */ @Override - public boolean isOutdated() + public boolean isOutdated() throws Exception { boolean result; - // TODO - result = false; + // + if (super.isOutdated()) + { + result = true; + } + else if (this.sourceTime == this.source.lastModified()) + { + result = true; + } + else + { + result = false; + } // return result; @@ -161,23 +163,54 @@ public class FilePresenter implements Presenter { if (source == null) { + super.setSource(null); + this.source = null; + this.sourceFilePathname = null; + this.sourceTime = 0; setSource((String) null); } else { - setSource(source.getAbsolutePath()); + this.source = source; + this.sourceFilePathname = source.getAbsolutePath(); + this.sourceTime = 0; + super.setSource(null); } } /** - * + * @throws Exception + * */ + @Override public void setSource(final String filePathname) { - this.sourceFilePathname = filePathname; - this.sourceFileTime = 0; - this.doc = null; - this.doctype = ""; + if (filePathname == null) + { + setSource((File) null); + } + else + { + if (this.sourceFilePathname.matches("file://.+")) + { + try + { + this.source = new File(new URI(this.sourceFilePathname)); + } + catch (URISyntaxException exception) + { + exception.printStackTrace(); + throw new IllegalArgumentException("Bad URI argument.", exception); + } + } + else + { + this.source = new File(this.sourceFilePathname); + } + this.sourceFilePathname = filePathname; + this.sourceTime = 0; + super.setSource(null); + } } /** @@ -209,35 +242,4 @@ public class FilePresenter implements Presenter // return (result); } - - /** - * - * @param filePathname - * @return - * @throws Exception - */ - static public String getDoctype(final String filePathname) throws Exception - { - String result; - - // - BufferedReader in = new BufferedReader(new FileReader(filePathname)); - String doctype = in.readLine(); - in.close(); - - logger.info("doctype=[" + doctype + "]"); - - // - if ((doctype.startsWith("")) || (this.source.startsWith(""))) - { - sourceHtml = this.source; - } else { - StringBuffer buffer = new StringBuffer(source.length() + 100); - buffer.append("\n"); - buffer.append(source); - buffer.append(""); - sourceHtml = buffer.toString(); + this.doctype = XidynUtils.extractDoctype(this.source); + + if (this.doctype == null) + { + StringBuffer buffer = new StringBuffer(source.length() + 100); + buffer.append("\n"); + buffer.append(this.source); + buffer.append(""); + sourceHtml = buffer.toString(); + } + else + { + sourceHtml = this.source; + } } // StringBufferInputStream is deprecated so we use another solution. // (see // http://www.developpez.net/forums/archive/index.php/t-14101.html). - this.doc = XidynUtils.buildDom(new ByteArrayInputStream(sourceHtml.getBytes())); - XidynUtils.addMetaTag(this.doc, "generator", "XIDYN"); + this.dom = XidynUtils.buildDom(sourceHtml); + XidynUtils.addMetaTag(this.dom, "generator", "XIDYN"); } // - if (datas == null) + if (data == null) { result = dynamize(); } @@ -99,11 +104,13 @@ public class StringPresenter implements Presenter { // StringWriter htmlCode = new StringWriter(XidynUtils.estimatedTargetLength(this.source.length())); - if ((this.source.startsWith("'))); + htmlCode.write(this.doctype); + htmlCode.write('\n'); } - DomPresenterCore.dynamize(htmlCode, doc, datas); + + DomPresenterCore.dynamize(htmlCode, dom, data); StringBuffer htmlTarget = htmlCode.getBuffer(); // @@ -111,7 +118,7 @@ public class StringPresenter implements Presenter { result = null; } - else if ((this.source.startsWith("")) || (this.source.startsWith(""))) + else if (this.doctype != null) { result = htmlTarget; } @@ -156,7 +163,7 @@ public class StringPresenter implements Presenter { boolean result; - if (this.doc == null) + if (this.dom == null) { result = true; } @@ -175,7 +182,8 @@ public class StringPresenter implements Presenter public void setSource(final String html) { this.source = html; - this.doc = null; + this.doctype = null; + this.dom = null; } /** @@ -192,4 +200,33 @@ public class StringPresenter implements Presenter // return (result); } + + /** + * + * @param source + * @return + */ + public static boolean hasHtmlTag(final String source) + { + boolean result; + + if (source == null) + { + result = false; + } + else + { + if (source.matches("<[hH][tT][mM][lL]>")) + { + result = true; + } + else + { + result = false; + } + } + + // + return result; + } } diff --git a/src/fr/devinsy/xidyn/presenters/URLPresenter.java b/src/fr/devinsy/xidyn/presenters/URLPresenter.java index 4f19c50..874ae28 100644 --- a/src/fr/devinsy/xidyn/presenters/URLPresenter.java +++ b/src/fr/devinsy/xidyn/presenters/URLPresenter.java @@ -1,15 +1,11 @@ package fr.devinsy.xidyn.presenters; -import java.io.BufferedReader; -import java.io.FileReader; import java.io.IOException; -import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; import fr.devinsy.xidyn.data.TagDataManager; import fr.devinsy.xidyn.utils.XidynUtils; @@ -17,15 +13,13 @@ import fr.devinsy.xidyn.utils.XidynUtils; /** * */ -public class URLPresenter implements Presenter +public class URLPresenter extends StringPresenter { static private Logger logger = LoggerFactory.getLogger(URLPresenter.class); - private Document doc; private String sourcePathname; - private URL sourceURL; - private long sourceFileTime; - private String doctype; + private URL source; + private long sourceTime; /** * @@ -69,44 +63,31 @@ public class URLPresenter implements Presenter * No need to be synchronized. */ @Override - public StringBuffer dynamize(final TagDataManager datas) throws Exception + public StringBuffer dynamize(final TagDataManager data) throws Exception { StringBuffer result; logger.info("dynamize URL [" + this.sourcePathname + "]"); - if (this.sourceURL == null) + // + if (this.source == null) { - String errorMessage = "source file defined but not found (" + this.sourcePathname + ")"; + String errorMessage = "source not defined"; logger.error(errorMessage); result = null; throw new Exception(errorMessage); } - else if (datas == null) - { - result = dynamize(new TagDataManager()); - } else { - long lastModified = this.sourceURL.openConnection().getLastModified(); - if ((this.doc == null) || (this.sourceFileTime != lastModified)) + long currentSourceTime = this.source.openConnection().getLastModified(); + if ((super.getSource() == null) || (this.sourceTime != currentSourceTime)) { - this.sourceFileTime = lastModified; - this.doc = XidynUtils.buildDom(this.sourceURL.openStream()); - if (this.doc != null) - { - XidynUtils.addMetaTag(this.doc, "generator", "XIDYN"); - } - this.doctype = ""; // TODO Made generic. + super.setSource(XidynUtils.load(this.source)); + this.sourceTime = currentSourceTime; } // Build the web page. - StringWriter htmlCode = new StringWriter(XidynUtils.estimatedTargetLength(sourceURL.openConnection().getContentLength())); - htmlCode.write(doctype); - htmlCode.write('\n'); - - DomPresenterCore.dynamize(htmlCode, doc, datas); - result = htmlCode.getBuffer(); + result = super.dynamize(data); } // @@ -121,7 +102,7 @@ public class URLPresenter implements Presenter { String result; - result = this.sourceURL.toString(); + result = this.source.toString(); // return (result); @@ -133,18 +114,22 @@ public class URLPresenter implements Presenter * @throws IOException */ @Override - public boolean isOutdated() throws IOException + public boolean isOutdated() throws Exception { boolean result; - long lastModified = this.sourceURL.openConnection().getLastModified(); - if (this.sourceFileTime == lastModified) + // + if (super.isOutdated()) { - result = false; + result = true; + } + else if (this.sourceTime == this.source.openConnection().getLastModified()) + { + result = true; } else { - result = true; + result = false; } // @@ -154,6 +139,7 @@ public class URLPresenter implements Presenter /** * */ + @Override public void setSource(final String source) { URL url; @@ -169,6 +155,7 @@ public class URLPresenter implements Presenter } catch (final MalformedURLException exception) { + // TODO logger.warn("UNKNOWN PROTOCOL [" + source + "]"); url = null; } @@ -189,16 +176,18 @@ public class URLPresenter implements Presenter { if (source == null) { + this.source = null; this.sourcePathname = null; + this.sourceTime = 0; + super.setSource(null); } else { + this.source = source; this.sourcePathname = source.toString(); + this.sourceTime = 0; + super.setSource(null); } - this.sourceURL = source; - this.sourceFileTime = 0; - this.doc = null; - this.doctype = ""; } /** @@ -230,35 +219,4 @@ public class URLPresenter implements Presenter // return (result); } - - /** - * - * @param filePathname - * @return - * @throws Exception - */ - static public String getDoctype(final String filePathname) throws Exception - { - String result; - - // - BufferedReader in = new BufferedReader(new FileReader(filePathname)); - String doctype = in.readLine(); - in.close(); - - logger.info("doctype=[" + doctype + "]"); - - // - if ((doctype.startsWith(" needs this possibility. + * This method extracts the string before the html tag. + * + * A possible way is to use pattern searching for + * $(.*)<html>.*^. But if there is no html tag, all the + * source is read for nothing. + * + * A best way is to analyze each < while it is a XML tag or a DOCTYPE tag + * or the <HTML> tag. + * + * Uses cases: + * + * + * ... + * + * + * @param source + * @return the string before the html tag or null if no html + * tag found. So, "" if there is a html tag without doctype. */ - static public Document fileToDom(final String fileName) throws Exception + static public String extractDoctype(final String source) + { + String result; + + if (source == null) + { + result = null; + } + else + { + boolean ended = false; + result = null; + int currentPosition = 0; + while (!ended) + { + currentPosition = source.indexOf('<', currentPosition); + + if (currentPosition == -1) + { + ended = true; + result = null; + } + else + { + if (currentPosition + 1 < source.length()) + { + if (Character.toLowerCase(source.charAt(currentPosition + 1)) == 'h') + { + if (source.substring(currentPosition + 1, currentPosition + 5).matches("^[hH][tT][mM][lL]$")) + { + ended = true; + result = source.substring(0, currentPosition); + } + } + else + { + char letter = source.charAt(currentPosition + 1); + if ((letter != '?') && (letter != '!')) + { + ended = true; + result = null; + } + else + { + currentPosition += 1; + } + } + } + else + { + ended = true; + result = null; + } + } + } + } + + // + return result; + } + + /** + * + */ + static public Document fileToDom(final File source) throws Exception { Document result; try { - result = buildDom(new FileInputStream(new File(fileName))); + result = buildDom(new FileInputStream(source)); } catch (IOException exception) { @@ -294,6 +453,170 @@ public class XidynUtils return result; } + /** + * + * @param file + * @return + * @throws IOException + */ + static public String load(final File source) throws IOException + { + String result; + + final String DEFAULT_CHARSET_NAME = "UTF-8"; + result = load(source, DEFAULT_CHARSET_NAME); + + // + return result; + } + + /** + * + * @param file + * @throws IOException + */ + public static String load(final File source, final String charsetName) throws IOException + { + String result; + + result = loadToStringBuffer(source, charsetName).toString(); + + // + return result; + } + + /** + * + * @param file + * @return + * @throws IOException + */ + static public String load(final URL source) throws IOException + { + String result; + + final String DEFAULT_CHARSET_NAME = "UTF-8"; + result = load(source, DEFAULT_CHARSET_NAME); + + // + return result; + } + + /** + * + * @param file + * @throws IOException + */ + public static String load(final URL source, final String charsetName) throws IOException + { + String result; + + // + StringBuffer buffer = new StringBuffer(source.openConnection().getContentLength() + 1); + read(buffer, source.openStream(), charsetName); + + // + result = buffer.toString(); + + // + return result; + } + + /** + * + * @param file + * @throws IOException + */ + public static StringBuffer loadToStringBuffer(final File file, final String charsetName) throws IOException + { + StringBuffer result; + + BufferedReader in = null; + try + { + in = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName)); + + boolean ended = false; + final String LINE_SEPARATOR = System.getProperty("line.separator"); + result = new StringBuffer((int) file.length() + 1); + while (!ended) + { + String line = in.readLine(); + + if (line == null) + { + ended = true; + } + else + { + result.append(line).append(LINE_SEPARATOR); + } + } + } + finally + { + try + { + if (in != null) + { + in.close(); + } + } + catch (IOException exception) + { + exception.printStackTrace(); + } + } + + // + return result; + } + + /** + * + * @param file + * @throws IOException + */ + public static void read(final StringBuffer out, final InputStream is, final String charsetName) throws IOException + { + BufferedReader in = null; + try + { + in = new BufferedReader(new InputStreamReader(is, charsetName)); + + boolean ended = false; + final String LINE_SEPARATOR = System.getProperty("line.separator"); + + while (!ended) + { + String line = in.readLine(); + + if (line == null) + { + ended = true; + } + else + { + out.append(line).append(LINE_SEPARATOR); + } + } + } + finally + { + try + { + if (in != null) + { + in.close(); + } + } + catch (IOException exception) + { + exception.printStackTrace(); + } + } + } + /** * Any ampersand lt;, ampersand gt; and ampersand amp; sequences in text * nodes get read in as symbols. This method converts them back to entities. @@ -350,4 +673,27 @@ public class XidynUtils // return (result); } + + /** + * + */ + static public Document urlToDom(final URL source) throws Exception + { + Document result; + + try + { + result = buildDom(source.openStream()); + } + catch (IOException exception) + { + String errorMessage = "IOError during parsing." + exception.getMessage(); + logger.error(errorMessage); + result = null; + throw new Exception(errorMessage, exception); + } + + // + return (result); + } } diff --git a/test/fr/devinsy/xidyn/utils/XidynUtilsTest.java b/test/fr/devinsy/xidyn/utils/XidynUtilsTest.java index 4100901..2ca9bd7 100644 --- a/test/fr/devinsy/xidyn/utils/XidynUtilsTest.java +++ b/test/fr/devinsy/xidyn/utils/XidynUtilsTest.java @@ -1,6 +1,10 @@ package fr.devinsy.xidyn.utils; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; import org.fest.assertions.Assertions; +import org.junit.Before; import org.junit.Test; /** @@ -8,6 +12,16 @@ import org.junit.Test; */ public class XidynUtilsTest { + /** + * + */ + @Before + public void before() + { + BasicConfigurator.configure(); + Logger.getRootLogger().setLevel(Level.ERROR); + } + /** * */ @@ -55,4 +69,65 @@ public class XidynUtilsTest String target = XidynUtils.extractBodyContent(source); Assertions.assertThat(target).isEqualTo("hello"); } + + /** + * + */ + @Test + public void testExtractDoctype01() + { + String source = "aaaaahellozzzzz"; + + String target = XidynUtils.extractDoctype(source); + Assertions.assertThat(target).isNull(); + } + + /** + * + */ + @Test + public void testExtractDoctype02() + { + String source = "aaaaahellozzzzz"; + + String target = XidynUtils.extractDoctype(source); + Assertions.assertThat(target).isEqualTo(""); + } + + /** + * + */ + @Test + public void testExtractDoctype03() + { + String source = "aaaaahellozzzzz"; + + String target = XidynUtils.extractDoctype(source); + Assertions.assertThat(target).isEqualTo(""); + } + + /** + * + */ + @Test + public void testExtractDoctype04() + { + String source = "aaaaahellozzzzz"; + + String target = XidynUtils.extractDoctype(source); + Assertions.assertThat(target).isEqualTo(""); + } + + /** + * + */ + @Test + public void testExtractDoctype05() + { + String source = "aaaaahellozzzzz"; + + String target = XidynUtils.extractDoctype(source); + Assertions.assertThat(target).isEqualTo(""); + } + }