summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
diff options
context:
space:
mode:
authorHenri Sara <henri.sara@itmill.com>2009-05-11 09:19:03 +0000
committerHenri Sara <henri.sara@itmill.com>2009-05-11 09:19:03 +0000
commitadc8c0ad3573272c236040c3a76005b9e73a5737 (patch)
treea3860704dbd5b82dc6af38684b80f8ef79a32722 /src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
parent5abc870dda584d0c2fc47fd5eec4ae3de3fa240e (diff)
downloadvaadin-framework-adc8c0ad3573272c236040c3a76005b9e73a5737.tar.gz
vaadin-framework-adc8c0ad3573272c236040c3a76005b9e73a5737.zip
#2904: initial bulk rename "com.itmill.toolkit" -> "com.vaadin"
- com.itmill.toolkit.external not yet fully renamed svn changeset:7715/svn branch:6.0
Diffstat (limited to 'src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java')
-rw-r--r--src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java1108
1 files changed, 1108 insertions, 0 deletions
diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
new file mode 100644
index 0000000000..b81e65e429
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java
@@ -0,0 +1,1108 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.ApplicationResource;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Paintable;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.VariableOwner;
+import com.vaadin.ui.Component;
+
+/**
+ * User Interface Description Language Target.
+ *
+ * @author IT Mill Ltd.
+ * @version
+ * @VERSION@
+ * @since 5.0
+ */
+@SuppressWarnings("serial")
+public class JsonPaintTarget implements PaintTarget {
+
+ /* Document type declarations */
+
+ private final static String UIDL_ARG_NAME = "name";
+
+ private final Stack<String> mOpenTags;
+
+ private final Stack<JsonTag> openJsonTags;
+
+ private final PrintWriter uidlBuffer;
+
+ private boolean closed = false;
+
+ private final CommunicationManager manager;
+
+ private int changes = 0;
+
+ Set preCachedResources = new HashSet();
+
+ private boolean customLayoutArgumentsOpen = false;
+
+ private JsonTag tag;
+
+ private int errorsOpen;
+
+ private boolean cacheEnabled = false;
+
+ private Collection<Paintable> paintedComponents = new HashSet<Paintable>();
+
+ private Collection<Paintable> identifiersCreatedDueRefPaint;
+
+ /**
+ * Creates a new XMLPrintWriter, without automatic line flushing.
+ *
+ * @param variableMap
+ * @param manager
+ * @param outWriter
+ * A character-output stream.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public JsonPaintTarget(CommunicationManager manager, PrintWriter outWriter,
+ boolean cachingRequired) throws PaintException {
+
+ this.manager = manager;
+
+ // Sets the target for UIDL writing
+ uidlBuffer = outWriter;
+
+ // Initialize tag-writing
+ mOpenTags = new Stack<String>();
+ openJsonTags = new Stack<JsonTag>();
+ cacheEnabled = cachingRequired;
+ }
+
+ public void startTag(String tagName) throws PaintException {
+ startTag(tagName, false);
+ }
+
+ /**
+ * Prints the element start tag.
+ *
+ * <pre>
+ * Todo:
+ * Checking of input values
+ *
+ * </pre>
+ *
+ * @param tagName
+ * the name of the start tag.
+ * @throws PaintException
+ * if the paint operation failed.
+ *
+ */
+ public void startTag(String tagName, boolean isChildNode)
+ throws PaintException {
+ // In case of null data output nothing:
+ if (tagName == null) {
+ throw new NullPointerException();
+ }
+
+ // Ensures that the target is open
+ if (closed) {
+ throw new PaintException(
+ "Attempted to write to a closed PaintTarget.");
+ }
+
+ if (tag != null) {
+ openJsonTags.push(tag);
+ }
+ // Checks tagName and attributes here
+ mOpenTags.push(tagName);
+
+ tag = new JsonTag(tagName);
+
+ customLayoutArgumentsOpen = "customlayout".equals(tagName);
+
+ if ("error".equals(tagName)) {
+ errorsOpen++;
+ }
+ }
+
+ /**
+ * Prints the element end tag.
+ *
+ * If the parent tag is closed before every child tag is closed an
+ * PaintException is raised.
+ *
+ * @param tag
+ * the name of the end tag.
+ * @throws Paintexception
+ * if the paint operation failed.
+ */
+ public void endTag(String tagName) throws PaintException {
+ // In case of null data output nothing:
+ if (tagName == null) {
+ throw new NullPointerException();
+ }
+
+ // Ensure that the target is open
+ if (closed) {
+ throw new PaintException(
+ "Attempted to write to a closed PaintTarget.");
+ }
+
+ if (openJsonTags.size() > 0) {
+ final JsonTag parent = openJsonTags.pop();
+
+ String lastTag = "";
+
+ lastTag = mOpenTags.pop();
+ if (!tagName.equalsIgnoreCase(lastTag)) {
+ throw new PaintException("Invalid UIDL: wrong ending tag: '"
+ + tagName + "' expected: '" + lastTag + "'.");
+ }
+
+ // simple hack which writes error uidl structure into attribute
+ if ("error".equals(lastTag)) {
+ if (errorsOpen == 1) {
+ parent.addAttribute("\"error\":[\"error\",{}"
+ + tag.getData() + "]");
+ } else {
+ // sub error
+ parent.addData(tag.getJSON());
+ }
+ errorsOpen--;
+ } else {
+ parent.addData(tag.getJSON());
+ }
+
+ tag = parent;
+ } else {
+ changes++;
+ uidlBuffer.print(((changes > 1) ? "," : "") + tag.getJSON());
+ tag = null;
+ }
+ }
+
+ /**
+ * Substitutes the XML sensitive characters with predefined XML entities.
+ *
+ * @param xml
+ * the String to be substituted.
+ * @return A new string instance where all occurrences of XML sensitive
+ * characters are substituted with entities.
+ */
+ static public String escapeXML(String xml) {
+ if (xml == null || xml.length() <= 0) {
+ return "";
+ }
+ return escapeXML(new StringBuffer(xml)).toString();
+ }
+
+ /**
+ * Substitutes the XML sensitive characters with predefined XML entities.
+ *
+ * @param xml
+ * the String to be substituted.
+ * @return A new StringBuffer instance where all occurrences of XML
+ * sensitive characters are substituted with entities.
+ *
+ */
+ static public StringBuffer escapeXML(StringBuffer xml) {
+ if (xml == null || xml.length() <= 0) {
+ return new StringBuffer("");
+ }
+
+ final StringBuffer result = new StringBuffer(xml.length() * 2);
+
+ for (int i = 0; i < xml.length(); i++) {
+ final char c = xml.charAt(i);
+ final String s = toXmlChar(c);
+ if (s != null) {
+ result.append(s);
+ } else {
+ result.append(c);
+ }
+ }
+ return result;
+ }
+
+ static public String escapeJSON(String s) {
+ if (s == null) {
+ return "";
+ }
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < s.length(); i++) {
+ final char ch = s.charAt(i);
+ switch (ch) {
+ case '"':
+ sb.append("\\\"");
+ break;
+ case '\\':
+ sb.append("\\\\");
+ break;
+ case '\b':
+ sb.append("\\b");
+ break;
+ case '\f':
+ sb.append("\\f");
+ break;
+ case '\n':
+ sb.append("\\n");
+ break;
+ case '\r':
+ sb.append("\\r");
+ break;
+ case '\t':
+ sb.append("\\t");
+ break;
+ case '/':
+ sb.append("\\/");
+ break;
+ default:
+ if (ch >= '\u0000' && ch <= '\u001F') {
+ final String ss = Integer.toHexString(ch);
+ sb.append("\\u");
+ for (int k = 0; k < 4 - ss.length(); k++) {
+ sb.append('0');
+ }
+ sb.append(ss.toUpperCase());
+ } else {
+ sb.append(ch);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Substitutes a XML sensitive character with predefined XML entity.
+ *
+ * @param c
+ * the Character to be replaced with an entity.
+ * @return String of the entity or null if character is not to be replaced
+ * with an entity.
+ */
+ private static String toXmlChar(char c) {
+ switch (c) {
+ case '&':
+ return "&amp;"; // & => &amp;
+ case '>':
+ return "&gt;"; // > => &gt;
+ case '<':
+ return "&lt;"; // < => &lt;
+ case '"':
+ return "&quot;"; // " => &quot;
+ case '\'':
+ return "&apos;"; // ' => &apos;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Prints XML-escaped text.
+ *
+ * @param str
+ * @throws PaintException
+ * if the paint operation failed.
+ *
+ */
+ public void addText(String str) throws PaintException {
+ tag.addData("\"" + escapeJSON(str) + "\"");
+ }
+
+ /**
+ * Adds a boolean attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, boolean value) throws PaintException {
+ tag.addAttribute("\"" + name + "\":" + (value ? "true" : "false"));
+ }
+
+ /**
+ * Adds a resource attribute to component. Attributes must be added before
+ * any content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, Resource value) throws PaintException {
+
+ if (value instanceof ExternalResource) {
+ addAttribute(name, ((ExternalResource) value).getURL());
+
+ } else if (value instanceof ApplicationResource) {
+ final ApplicationResource r = (ApplicationResource) value;
+ final Application a = r.getApplication();
+ if (a == null) {
+ throw new PaintException(
+ "Application not specified for resorce "
+ + value.getClass().getName());
+ }
+ String uri;
+ if (a.getURL() != null) {
+ uri = a.getURL().getPath();
+ } else {
+ uri = "";
+ }
+ if (uri.length() > 0 && uri.charAt(uri.length() - 1) != '/') {
+ uri += "/";
+ }
+ uri += a.getRelativeLocation(r);
+ addAttribute(name, uri);
+
+ } else if (value instanceof ThemeResource) {
+ final String uri = "theme://"
+ + ((ThemeResource) value).getResourceId();
+ addAttribute(name, uri);
+ } else {
+ throw new PaintException("Ajax adapter does not "
+ + "support resources of type: "
+ + value.getClass().getName());
+ }
+
+ }
+
+ /**
+ * Adds a integer attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, int value) throws PaintException {
+ tag.addAttribute("\"" + name + "\":" + String.valueOf(value));
+ }
+
+ /**
+ * Adds a long attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, long value) throws PaintException {
+ tag.addAttribute("\"" + name + "\":" + String.valueOf(value));
+ }
+
+ /**
+ * Adds a float attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, float value) throws PaintException {
+ tag.addAttribute("\"" + name + "\":" + String.valueOf(value));
+ }
+
+ /**
+ * Adds a double attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the Attribute name.
+ * @param value
+ * the Attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, double value) throws PaintException {
+ tag.addAttribute("\"" + name + "\":" + String.valueOf(value));
+ }
+
+ /**
+ * Adds a string attribute to component. Atributes must be added before any
+ * content is written.
+ *
+ * @param name
+ * the String attribute name.
+ * @param value
+ * the String attribute value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addAttribute(String name, String value) throws PaintException {
+ // In case of null data output nothing:
+ if ((value == null) || (name == null)) {
+ throw new NullPointerException(
+ "Parameters must be non-null strings");
+ }
+
+ tag.addAttribute("\"" + name + "\": \"" + escapeJSON(value) + "\"");
+
+ if (customLayoutArgumentsOpen && "template".equals(name)) {
+ getPreCachedResources().add("layouts/" + value + ".html");
+ }
+
+ if (name.equals("locale")) {
+ manager.requireLocale(value);
+ }
+
+ }
+
+ public void addAttribute(String name, Object[] values) {
+ // In case of null data output nothing:
+ if ((values == null) || (name == null)) {
+ throw new NullPointerException(
+ "Parameters must be non-null strings");
+ }
+ final StringBuffer buf = new StringBuffer();
+ buf.append("\"" + name + "\":[");
+ for (int i = 0; i < values.length; i++) {
+ if (i > 0) {
+ buf.append(",");
+ }
+ buf.append("\"");
+ buf.append(escapeJSON(values[i].toString()));
+ buf.append("\"");
+ }
+ buf.append("]");
+ tag.addAttribute(buf.toString());
+ }
+
+ /**
+ * Adds a string type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, String value)
+ throws PaintException {
+ tag.addVariable(new StringVariable(owner, name, escapeJSON(value)));
+ }
+
+ /**
+ * Adds a int type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, int value)
+ throws PaintException {
+ tag.addVariable(new IntVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a long type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, long value)
+ throws PaintException {
+ tag.addVariable(new LongVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a float type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, float value)
+ throws PaintException {
+ tag.addVariable(new FloatVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a double type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, double value)
+ throws PaintException {
+ tag.addVariable(new DoubleVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a boolean type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, boolean value)
+ throws PaintException {
+ tag.addVariable(new BooleanVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a string array type variable.
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ * @param value
+ * the Variable initial value.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addVariable(VariableOwner owner, String name, String[] value)
+ throws PaintException {
+ tag.addVariable(new ArrayVariable(owner, name, value));
+ }
+
+ /**
+ * Adds a upload stream type variable.
+ *
+ * TODO not converted for JSON
+ *
+ * @param owner
+ * the Listener for variable changes.
+ * @param name
+ * the Variable name.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addUploadStreamVariable(VariableOwner owner, String name)
+ throws PaintException {
+ startTag("uploadstream");
+ addAttribute(UIDL_ARG_NAME, name);
+ endTag("uploadstream");
+ }
+
+ /**
+ * Prints the single text section.
+ *
+ * Prints full text section. The section data is escaped
+ *
+ * @param sectionTagName
+ * the name of the tag.
+ * @param sectionData
+ * the section data to be printed.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addSection(String sectionTagName, String sectionData)
+ throws PaintException {
+ tag.addData("{\"" + sectionTagName + "\":\"" + escapeJSON(sectionData)
+ + "\"}");
+ }
+
+ /**
+ * Adds XML directly to UIDL.
+ *
+ * @param xml
+ * the Xml to be added.
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void addUIDL(String xml) throws PaintException {
+
+ // Ensure that the target is open
+ if (closed) {
+ throw new PaintException(
+ "Attempted to write to a closed PaintTarget.");
+ }
+
+ // Make sure that the open start tag is closed before
+ // anything is written.
+
+ // Escape and write what was given
+ if (xml != null) {
+ tag.addData("\"" + escapeJSON(xml) + "\"");
+ }
+
+ }
+
+ /**
+ * Adds XML section with namespace.
+ *
+ * @param sectionTagName
+ * the name of the tag.
+ * @param sectionData
+ * the section data.
+ * @param namespace
+ * the namespace to be added.
+ * @throws PaintException
+ * if the paint operation failed.
+ *
+ * @see com.vaadin.terminal.PaintTarget#addXMLSection(String,
+ * String, String)
+ */
+ public void addXMLSection(String sectionTagName, String sectionData,
+ String namespace) throws PaintException {
+
+ // Ensure that the target is open
+ if (closed) {
+ throw new PaintException(
+ "Attempted to write to a closed PaintTarget.");
+ }
+
+ startTag(sectionTagName);
+ if (namespace != null) {
+ addAttribute("xmlns", namespace);
+ }
+ customLayoutArgumentsOpen = false;
+
+ if (sectionData != null) {
+ tag.addData("\"" + escapeJSON(sectionData) + "\"");
+ }
+ endTag(sectionTagName);
+ }
+
+ /**
+ * Gets the UIDL already printed to stream. Paint target must be closed
+ * before the <code>getUIDL</code> can be called.
+ *
+ * @return the UIDL.
+ */
+ public String getUIDL() {
+ if (closed) {
+ return uidlBuffer.toString();
+ }
+ throw new IllegalStateException(
+ "Tried to read UIDL from open PaintTarget");
+ }
+
+ /**
+ * Closes the paint target. Paint target must be closed before the
+ * <code>getUIDL</code> can be called. Subsequent attempts to write to paint
+ * target. If the target was already closed, call to this function is
+ * ignored. will generate an exception.
+ *
+ * @throws PaintException
+ * if the paint operation failed.
+ */
+ public void close() throws PaintException {
+ if (tag != null) {
+ uidlBuffer.write(tag.getJSON());
+ }
+ flush();
+ closed = true;
+ }
+
+ /**
+ * Method flush.
+ */
+ private void flush() {
+ uidlBuffer.flush();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.PaintTarget#startTag(com.vaadin.terminal
+ * .Paintable, java.lang.String)
+ */
+ public boolean startTag(Paintable paintable, String tagName)
+ throws PaintException {
+ startTag(tagName, true);
+ final boolean isPreviouslyPainted = manager.hasPaintableId(paintable)
+ && (identifiersCreatedDueRefPaint == null || !identifiersCreatedDueRefPaint
+ .contains(paintable));
+ final String id = manager.getPaintableId(paintable);
+ paintable.addListener(manager);
+ addAttribute("id", id);
+ paintedComponents.add(paintable);
+ return cacheEnabled && isPreviouslyPainted;
+ }
+
+ public void paintReference(Paintable paintable, String referenceName)
+ throws PaintException {
+ if (!manager.hasPaintableId(paintable)) {
+ if (identifiersCreatedDueRefPaint == null) {
+ identifiersCreatedDueRefPaint = new HashSet<Paintable>();
+ }
+ identifiersCreatedDueRefPaint.add(paintable);
+ }
+ final String id = manager.getPaintableId(paintable);
+ addAttribute(referenceName, id);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.PaintTarget#addCharacterData(java.lang.String
+ * )
+ */
+ public void addCharacterData(String text) throws PaintException {
+ if (text != null) {
+ tag.addData(text);
+ }
+ }
+
+ /**
+ * This is basically a container for UI components variables, that will be
+ * added at the end of JSON object.
+ *
+ * @author mattitahvonen
+ *
+ */
+ class JsonTag implements Serializable {
+ boolean firstField = false;
+
+ Vector variables = new Vector();
+
+ Vector children = new Vector();
+
+ Vector attr = new Vector();
+
+ StringBuffer data = new StringBuffer();
+
+ public boolean childrenArrayOpen = false;
+
+ private boolean childNode = false;
+
+ private boolean tagClosed = false;
+
+ public JsonTag(String tagName) {
+ data.append("[\"" + tagName + "\"");
+ }
+
+ private void closeTag() {
+ if (!tagClosed) {
+ data.append(attributesAsJsonObject());
+ data.append(getData());
+ // Writes the end (closing) tag
+ data.append("]");
+ tagClosed = true;
+ }
+ }
+
+ public String getJSON() {
+ if (!tagClosed) {
+ closeTag();
+ }
+ return data.toString();
+ }
+
+ public void openChildrenArray() {
+ if (!childrenArrayOpen) {
+ // append("c : [");
+ childrenArrayOpen = true;
+ // firstField = true;
+ }
+ }
+
+ public void closeChildrenArray() {
+ // append("]");
+ // firstField = false;
+ }
+
+ public void setChildNode(boolean b) {
+ childNode = b;
+ }
+
+ public boolean isChildNode() {
+ return childNode;
+ }
+
+ public String startField() {
+ if (firstField) {
+ firstField = false;
+ return "";
+ } else {
+ return ",";
+ }
+ }
+
+ /**
+ *
+ * @param s
+ * json string, object or array
+ */
+ public void addData(String s) {
+ children.add(s);
+ }
+
+ public String getData() {
+ final StringBuffer buf = new StringBuffer();
+ final Iterator it = children.iterator();
+ while (it.hasNext()) {
+ buf.append(startField());
+ buf.append(it.next());
+ }
+ return buf.toString();
+ }
+
+ public void addAttribute(String jsonNode) {
+ attr.add(jsonNode);
+ }
+
+ private String attributesAsJsonObject() {
+ final StringBuffer buf = new StringBuffer();
+ buf.append(startField());
+ buf.append("{");
+ for (final Iterator iter = attr.iterator(); iter.hasNext();) {
+ final String element = (String) iter.next();
+ buf.append(element);
+ if (iter.hasNext()) {
+ buf.append(",");
+ }
+ }
+ buf.append(tag.variablesAsJsonObject());
+ buf.append("}");
+ return buf.toString();
+ }
+
+ public void addVariable(Variable v) {
+ variables.add(v);
+ }
+
+ private String variablesAsJsonObject() {
+ if (variables.size() == 0) {
+ return "";
+ }
+ final StringBuffer buf = new StringBuffer();
+ buf.append(startField());
+ buf.append("\"v\":{");
+ final Iterator iter = variables.iterator();
+ while (iter.hasNext()) {
+ final Variable element = (Variable) iter.next();
+ buf.append(element.getJsonPresentation());
+ if (iter.hasNext()) {
+ buf.append(",");
+ }
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ class TagCounter {
+ int count;
+
+ public TagCounter() {
+ count = 0;
+ }
+
+ public void increment() {
+ count++;
+ }
+
+ public String postfix(String s) {
+ if (count > 0) {
+ return s + count;
+ }
+ return s;
+ }
+ }
+ }
+
+ abstract class Variable implements Serializable {
+
+ String name;
+
+ public abstract String getJsonPresentation();
+ }
+
+ class BooleanVariable extends Variable implements Serializable {
+ boolean value;
+
+ public BooleanVariable(VariableOwner owner, String name, boolean v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":" + (value == true ? "true" : "false");
+ }
+
+ }
+
+ class StringVariable extends Variable implements Serializable {
+ String value;
+
+ public StringVariable(VariableOwner owner, String name, String v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":\"" + value + "\"";
+ }
+
+ }
+
+ class IntVariable extends Variable implements Serializable {
+ int value;
+
+ public IntVariable(VariableOwner owner, String name, int v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":" + value;
+ }
+ }
+
+ class LongVariable extends Variable implements Serializable {
+ long value;
+
+ public LongVariable(VariableOwner owner, String name, long v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":" + value;
+ }
+ }
+
+ class FloatVariable extends Variable implements Serializable {
+ float value;
+
+ public FloatVariable(VariableOwner owner, String name, float v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":" + value;
+ }
+ }
+
+ class DoubleVariable extends Variable implements Serializable {
+ double value;
+
+ public DoubleVariable(VariableOwner owner, String name, double v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ return "\"" + name + "\":" + value;
+ }
+ }
+
+ class ArrayVariable extends Variable implements Serializable {
+ String[] value;
+
+ public ArrayVariable(VariableOwner owner, String name, String[] v) {
+ value = v;
+ this.name = name;
+ }
+
+ @Override
+ public String getJsonPresentation() {
+ String pres = "\"" + name + "\":[";
+ for (int i = 0; i < value.length;) {
+ pres += "\"" + value[i] + "\"";
+ i++;
+ if (i < value.length) {
+ pres += ",";
+ }
+ }
+ pres += "]";
+ return pres;
+ }
+ }
+
+ public Set getPreCachedResources() {
+ return preCachedResources;
+ }
+
+ public void setPreCachedResources(Set preCachedResources) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Method to check if paintable is already painted into this target.
+ *
+ * @param p
+ * @return true if is not yet painted into this target and is connected to
+ * app
+ */
+ public boolean needsToBePainted(Paintable p) {
+ if (paintedComponents.contains(p)) {
+ return false;
+ } else if (((Component) p).getApplication() == null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+}