Improve design hugly.

This commit is contained in:
Christian P. MOMON 2013-08-03 04:35:57 +02:00
parent e89ab6ea09
commit 5617603b29
5 changed files with 596 additions and 178 deletions

View file

@ -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("<!DOCTYPE")) || (doctype.startsWith("<!doctype")))
{
result = doctype;
}
else
{
result = null;
}
//
return (result);
}
}

View file

@ -1,6 +1,5 @@
package fr.devinsy.xidyn.presenters;
import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import org.slf4j.Logger;
@ -18,7 +17,8 @@ public class StringPresenter implements Presenter
static private Logger logger = LoggerFactory.getLogger(StringPresenter.class);
private String source;
private Document doc;
private String doctype;
private Document dom;
/**
*
@ -54,44 +54,49 @@ public class StringPresenter implements Presenter
* {@inheritDoc}
*/
@Override
public StringBuffer dynamize(final TagDataManager datas) throws Exception
public StringBuffer dynamize(final TagDataManager data) throws Exception
{
StringBuffer result;
//
if (this.doc == null)
// Build the DOM.
if (this.dom == null)
{
// Build doc from this.html.
// Build the source HTML.
String sourceHtml;
if (source == null)
if (this.source == null)
{
String errorMessage = "source not defined";
logger.error(errorMessage);
result = null;
throw new Exception(errorMessage);
}
else if ((this.source.startsWith("<!DOCTYPE")) || (this.source.startsWith("<!doctype")) || (this.source.startsWith("<html>")) || (this.source.startsWith("<HTML>")))
{
sourceHtml = this.source;
}
else
{
StringBuffer buffer = new StringBuffer(source.length() + 100);
buffer.append("<html><head></head><body>\n");
buffer.append(source);
buffer.append("</body></html>");
sourceHtml = buffer.toString();
this.doctype = XidynUtils.extractDoctype(this.source);
if (this.doctype == null)
{
StringBuffer buffer = new StringBuffer(source.length() + 100);
buffer.append("<html><head></head><body>\n");
buffer.append(this.source);
buffer.append("</body></html>");
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("<!DOCTYPE")) || (this.source.startsWith("<!doctype")))
if ((this.doctype != null))
{
htmlCode.write(this.source.substring(0, this.source.indexOf('>')));
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("<!DOCTYPE")) || (this.source.startsWith("<!doctype")) || (this.source.startsWith("<html>")) || (this.source.startsWith("<HTML>")))
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;
}
}

View file

@ -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 = "<!DOCTYPE HTML>"; // 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("<!DOCTYPE")) || (doctype.startsWith("<!doctype")))
{
result = doctype;
}
else
{
result = null;
}
//
return (result);
}
}

View file

@ -1,9 +1,13 @@
package fr.devinsy.xidyn.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -18,6 +22,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
@ -122,6 +127,78 @@ public class XidynUtils
return (result);
}
/**
* This method builds a DOM object from a source.
*/
static public Document buildDom(final String source) throws Exception
{
Document result;
try
{
// Create a DocumentBuilderFactory and configure it.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// Set various configuration options.
dbf.setValidating(false);
dbf.setIgnoringComments(true);
dbf.setIgnoringElementContentWhitespace(false);
dbf.setCoalescing(false);
// Keep entity references as they are.
dbf.setExpandEntityReferences(false);
// Create a DocumentBuilder that satisfies the constraints
// specified by the DocumentBuilderFactory.
DocumentBuilder db = dbf.newDocumentBuilder();
ParserErrorHandler errorHandler;
errorHandler = new ParserErrorHandler();
// Set the error handler.
db.setErrorHandler(errorHandler);
Schema schema = db.getSchema();
logger.debug("schema=" + schema);
// Parse the input file.
result = db.parse(new InputSource(new StringReader(source)));
if (errorHandler.hasError())
{
// Most time, error is (with StringPresenter):
// "Error at line 1 : Document root element "html", must match DOCTYPE root "null".
// Error at line 1 : Document is invalid: no grammar found.
// We ignore it. STU
logger.debug(errorHandler.toString());
}
}
catch (ParserConfigurationException exception)
{
String errorMessage = "Parser configuration exception: " + exception.getMessage();
logger.error(errorMessage);
result = null;
throw new Exception(errorMessage, exception);
}
catch (SAXException exception)
{
String errorMessage = "Error during SAX parsing: " + exception.getMessage();
logger.error(errorMessage);
result = null;
throw new Exception(errorMessage, exception);
}
catch (IOException exception)
{
String errorMessage = "IOError during parsing." + exception.getMessage();
logger.error(errorMessage);
result = null;
throw new Exception(errorMessage, exception);
}
//
return (result);
}
/**
* Good estimation of the target length able to optimize performance.
*/
@ -184,15 +261,97 @@ public class XidynUtils
}
/**
* Define in Presenter cause <object> needs this possibility.
* This method extracts the string before the <i>html</i> tag.
*
* A possible way is to use pattern searching for
* <i>$(.*)&lt;html&gt;.*^</i>. But if there is no <i>html</i> tag, all the
* source is read for nothing.
*
* A best way is to analyze each &lt; while it is a XML tag or a DOCTYPE tag
* or the &lt;HTML&gt; tag.
*
* Uses cases:
*
* <code>
* <?xml version='1.0' encoding='UTF-8' ?><!-- TOTOT --><!DOCTYPE
* html><html xmlns='http://www.w3.org/1999/xhtml'>...
* </code>
*
* @param source
* @return the string before the <i>html</i> tag or null if no <i>html</i>
* tag found. So, "" if there is a <i>html</i> 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);
}
}

View file

@ -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 = "aaaaa<boDY>hello</Body>zzzzz";
String target = XidynUtils.extractDoctype(source);
Assertions.assertThat(target).isNull();
}
/**
*
*/
@Test
public void testExtractDoctype02()
{
String source = "<html xmlns='http://www.w3.org/1999/xhtml'>aaaaa<boDY>hello</Body>zzzzz";
String target = XidynUtils.extractDoctype(source);
Assertions.assertThat(target).isEqualTo("");
}
/**
*
*/
@Test
public void testExtractDoctype03()
{
String source = "<!DOCTYPE html><html xmlns='http://www.w3.org/1999/xhtml'>aaaaa<boDY>hello</Body>zzzzz";
String target = XidynUtils.extractDoctype(source);
Assertions.assertThat(target).isEqualTo("<!DOCTYPE html>");
}
/**
*
*/
@Test
public void testExtractDoctype04()
{
String source = "<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html><html xmlns='http://www.w3.org/1999/xhtml'>aaaaa<boDY>hello</Body>zzzzz";
String target = XidynUtils.extractDoctype(source);
Assertions.assertThat(target).isEqualTo("<?xml version='1.0' encoding='UTF-8' ?><!DOCTYPE html>");
}
/**
*
*/
@Test
public void testExtractDoctype05()
{
String source = "<?xml version='1.0' encoding='UTF-8' ?><!-- TOTOT --><!DOCTYPE html><html xmlns='http://www.w3.org/1999/xhtml'>aaaaa<boDY>hello</Body>zzzzz";
String target = XidynUtils.extractDoctype(source);
Assertions.assertThat(target).isEqualTo("<?xml version='1.0' encoding='UTF-8' ?><!-- TOTOT --><!DOCTYPE html>");
}
}