diff options
author | Artur Signell <artur@vaadin.com> | 2014-12-12 23:47:40 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2014-12-15 10:54:05 +0000 |
commit | a27ea03db9f6ba5f4358c359645cd62617d2d205 (patch) | |
tree | 1168623c66ade7b8f316289b9bd2ba9d57e79f97 /server/src/com | |
parent | ad8ce56c124440e24b0c40139f7159a6a63a3341 (diff) | |
download | vaadin-framework-a27ea03db9f6ba5f4358c359645cd62617d2d205.tar.gz vaadin-framework-a27ea03db9f6ba5f4358c359645cd62617d2d205.zip |
Refactored API for loading designs (#7749)
Now contains read methods
* Component read(InputStream design)
* DesignContext read(InputStream design, Component rootComponent)
* DesignContext read(String filename, Component rootComponent)
and write methods
* write(Component component, OutputStream outputStream)
* write(DesignContext designContext, OutputStream outputStream)
Change-Id: I9d6862240c5b2018ec39a164a54e7c047a00971b
Diffstat (limited to 'server/src/com')
-rw-r--r-- | server/src/com/vaadin/ui/declarative/Design.java | 219 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/declarative/DesignContext.java | 12 |
2 files changed, 166 insertions, 65 deletions
diff --git a/server/src/com/vaadin/ui/declarative/Design.java b/server/src/com/vaadin/ui/declarative/Design.java index 89e992181b..433705c632 100644 --- a/server/src/com/vaadin/ui/declarative/Design.java +++ b/server/src/com/vaadin/ui/declarative/Design.java @@ -19,11 +19,13 @@ import java.beans.IntrospectionException; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.Serializable; import java.util.Collection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Document.OutputSettings.Syntax; import org.jsoup.nodes.DocumentType; import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; @@ -46,28 +48,21 @@ import com.vaadin.ui.declarative.DesignContext.ComponentCreationListener; */ public class Design implements Serializable { /** - * Constructs a component hierarchy from the design specified as an html - * document. The component hierarchy must contain exactly one top-level - * Component. The component should be located under <body>, but also invalid - * html containing the hierarchy without <html>, <head> and <body> tags is - * accepted. - * + * Parses the given input stream into a jsoup document + * * @param html - * the html document describing the component design - * @return the DesignContext created while traversing the tree. The - * top-level component of the created component hierarchy can be - * accessed using result.getRootComponent(), where result is the - * object returned by this method. + * the stream containing the design + * @return the parsed jsoup document * @throws IOException */ - public static DesignContext parse(InputStream html) { - Document doc; + private static Document parse(InputStream html) { try { - doc = Jsoup.parse(html, "UTF-8", "", Parser.htmlParser()); + Document doc = Jsoup.parse(html, "UTF-8", "", Parser.htmlParser()); + return doc; } catch (IOException e) { throw new DesignException("The html document cannot be parsed."); } - return parse(doc, null); + } /** @@ -79,7 +74,7 @@ public class Design implements Serializable { * some uninitialized instance fields. The fields will be automatically * populated when parsing the design based on the component ids, local ids, * and captions of the components in the design. - * + * * @param html * the html document describing the component design * @param rootInstance @@ -91,34 +86,9 @@ public class Design implements Serializable { * object returned by this method. * @throws IOException */ - public static DesignContext parse(InputStream html, Component rootInstance) { - Document doc; - try { - doc = Jsoup.parse(html, "UTF-8", "", Parser.htmlParser()); - } catch (IOException e) { - throw new DesignException("The html document cannot be parsed."); - } - return parse(doc, rootInstance); - } - - /** - * Constructs a component hierarchy from the design specified as an html - * document given as a string. The component hierarchy must contain exactly - * one top-level Component. The component should be located under <body>, - * but also invalid html containing the hierarchy without <html>, <head> and - * <body> tags is accepted. - * - * @param html - * the html document describing the component design - * @return the DesignContext created while traversing the tree. The - * top-level component of the created component hierarchy can be - * accessed using result.getRootComponent(), where result is the - * object returned by this method. - * @throws IOException - */ - public static DesignContext parse(String html) { - Document doc = Jsoup.parse(html); - return parse(doc, null); + private static DesignContext parse(InputStream html, Component rootInstance) { + Document doc = parse(html); + return designToComponentTree(doc, rootInstance); } /** @@ -130,7 +100,7 @@ public class Design implements Serializable { * component with some uninitialized instance fields. The fields will be * automatically populated when parsing the design based on the component * ids, local ids, and captions of the components in the design. - * + * * @param html * the html document describing the component design * @param rootInstance @@ -142,17 +112,19 @@ public class Design implements Serializable { * object returned by this method. * @throws IOException */ - public static DesignContext parse(String html, Component rootInstance) { + private static DesignContext parse(String html, Component rootInstance) { Document doc = Jsoup.parse(html); - return parse(doc, rootInstance); + return designToComponentTree(doc, rootInstance); } /** * Constructs a component hierarchy from the design specified as an html - * tree. If componentRoot is not null, the component instances created - * during synchronizing the design are assigned to its member fields based - * on their id, localId, and caption + * tree. * + * If a component root is given, the component instances created during + * synchronizing the design are assigned to its member fields based on their + * id, local id, and caption + * * @param doc * the html tree * @param componentRoot @@ -160,9 +132,10 @@ public class Design implements Serializable { * type must match the type of the root element in the design. * The member fields whose type is assignable from * {@link Component} are set when parsing the component tree - * + * */ - private static DesignContext parse(Document doc, Component componentRoot) { + private static DesignContext designToComponentTree(Document doc, + Component componentRoot) { DesignContext designContext = new DesignContext(doc); designContext.getPrefixes(doc); // No special handling for a document without a body element - should be @@ -210,7 +183,7 @@ public class Design implements Serializable { // createChild creates the entire component hierarchy componentRoot = designContext.createChild(element); } - designContext.setComponentRoot(componentRoot); + designContext.setRootComponent(componentRoot); return designContext; } @@ -218,13 +191,13 @@ public class Design implements Serializable { * Generates an html tree representation representing the component * hierarchy having the given root. The hierarchy is stored under <body> in * the tree. The generated tree corresponds to a valid html document. - * - * + * + * * @param root * the root of the component hierarchy * @return an html tree representation of the component hierarchy */ - public static Document createHtml(DesignContext designContext) { + private static Document createHtml(DesignContext designContext) { // Create the html tree skeleton. Document doc = new Document(""); DocumentType docType = new DocumentType("html", "", "", ""); @@ -239,7 +212,7 @@ public class Design implements Serializable { // Append the design under <body> in the html tree. createNode // creates the entire component hierarchy rooted at the // given root node. - Component root = designContext.getComponentRoot(); + Component root = designContext.getRootComponent(); Node rootNode = designContext.createNode(root); body.appendChild(rootNode); return doc; @@ -248,14 +221,142 @@ public class Design implements Serializable { /** * Generates an html file corresponding to the component hierarchy with the * given root. - * + * * @param writer * @param root * @throws IOException */ - public static void createHtml(BufferedWriter writer, DesignContext ctx) + private static void createHtml(BufferedWriter writer, DesignContext ctx) throws IOException { String docAsString = createHtml(ctx).toString(); writer.write(docAsString); } + + /** + * Loads a design from the given file name using the given root component. + * <p> + * Any {@link Component} type fields in the root component which are not + * assigned (i.e. are null) are mapped to corresponding components in the + * design. Matching is done based on field name in the component class and + * id/local id/caption in the design file. + * <p> + * The type of the root component must match the root element in the design + * + * @param filename + * The file name to load. Loaded from the same package as the + * root component + * @param rootComponent + * The root component of the layout. + * @return The design context used in the load operation + * @throws DesignException + * If the design could not be loaded + */ + public static DesignContext read(String filename, Component rootComponent) + throws DesignException { + InputStream stream = rootComponent.getClass().getResourceAsStream( + filename); + if (stream == null) { + throw new DesignException("File " + filename + + " was not found in the package " + + rootComponent.getClass().getPackage().getName()); + } + return read(stream, rootComponent); + } + + /** + * Loads a design from the given stream using the given root component. + * <p> + * Any {@link Component} type fields in the root component which are not + * assigned (i.e. are null) are mapped to corresponding components in the + * design. Matching is done based on field name in the component class and + * id/local id/caption in the design file. + * <p> + * The type of the root component must match the root element in the design + * + * @param stream + * The stream to read the design from + * @param rootComponent + * The root component of the layout. + * @return The design context used in the load operation + * @throws DesignException + * If the design could not be loaded + */ + public static DesignContext read(InputStream design, Component rootComponent) { + if (design == null) { + throw new DesignException("Stream cannot be null"); + } + Document doc = parse(design); + DesignContext context = designToComponentTree(doc, rootComponent); + + return context; + } + + /** + * Loads a design from the given input stream + * + * @param design + * The input stream which contains the design + * @return The root component of the design + */ + public static Component read(InputStream design) { + DesignContext context = read(design, null); + return context.getRootComponent(); + + } + + /** + * Writes the given component tree in design format to the given output + * stream + * + * @param component + * the root component of the component tree to write + * @param outputStream + * the output stream to write the design to. The design is always + * written as UTF-8 + * @throws IOException + */ + public static void write(Component component, OutputStream outputStream) + throws IOException { + DesignContext dc = new DesignContext(); + dc.setRootComponent(component); + write(dc, outputStream); + } + + /** + * Writes the component, given in the design context, in design format to + * the given output stream. The design context is used for writing local ids + * and other information not available in the component tree. + * + * @param component + * the root component of the component tree to write + * @param outputStream + * the output stream to write the design to. The design is always + * written as UTF-8 + * @throws IOException + * if writing fails + */ + public static void write(DesignContext designContext, + OutputStream outputStream) throws IOException { + Document doc = createHtml(designContext); + write(doc, outputStream); + } + + /** + * Writes the given jsoup document to the output stream (in UTF-8) + * + * @param doc + * the document to write + * @param outputStream + * the stream to write to + * @throws IOException + * if writing fails + */ + private static void write(Document doc, OutputStream outputStream) + throws IOException { + doc.outputSettings().indentAmount(4); + doc.outputSettings().syntax(Syntax.html); + doc.outputSettings().prettyPrint(true); + outputStream.write(doc.html().getBytes()); + } + } diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java index 753a2d87ba..a3026fca18 100644 --- a/server/src/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/com/vaadin/ui/declarative/DesignContext.java @@ -46,7 +46,7 @@ public class DesignContext implements Serializable { .synchronizedMap(new HashMap<Class<?>, Object>()); // The root component of the component hierarchy - private Component componentRoot = null; + private Component rootComponent = null; // Attribute names for global id and caption and the prefix name for a local // id public static final String ID_ATTRIBUTE = "id"; @@ -280,7 +280,7 @@ public class DesignContext implements Serializable { * located under <head> in the html document. * */ - public void getPrefixes(Document doc) { + protected void getPrefixes(Document doc) { Element head = doc.head(); if (head == null) { return; @@ -554,15 +554,15 @@ public class DesignContext implements Serializable { * * @return */ - public Component getComponentRoot() { - return componentRoot; + public Component getRootComponent() { + return rootComponent; } /** * Sets the root component of a created component hierarchy. */ - public void setComponentRoot(Component componentRoot) { - this.componentRoot = componentRoot; + public void setRootComponent(Component rootComponent) { + this.rootComponent = rootComponent; } /** |