summaryrefslogtreecommitdiffstats
path: root/server/src/com
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2014-12-12 23:47:40 +0200
committerVaadin Code Review <review@vaadin.com>2014-12-15 10:54:05 +0000
commita27ea03db9f6ba5f4358c359645cd62617d2d205 (patch)
tree1168623c66ade7b8f316289b9bd2ba9d57e79f97 /server/src/com
parentad8ce56c124440e24b0c40139f7159a6a63a3341 (diff)
downloadvaadin-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.java219
-rw-r--r--server/src/com/vaadin/ui/declarative/DesignContext.java12
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;
}
/**