All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.jaxx.compiler.tools.jaxxcapture.handlers.ObjectHandler Maven / Gradle / Ivy

There is a newer version: 3.1.5
Show newest version
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2020 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.jaxx.compiler.tools.jaxxcapture.handlers;

import org.nuiton.jaxx.compiler.JAXXCompiler;
import org.nuiton.jaxx.compiler.finalizers.JAXXCompilerFinalizer;
import org.nuiton.jaxx.compiler.java.JavaFileGenerator;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.CapturedObject;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.ContextNode;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.JAXXCapture;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.LiteralNode;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.MethodNode;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.PropertyNode;
import org.nuiton.jaxx.compiler.tools.jaxxcapture.ValueNode;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.awt.Container;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Stack;

public class ObjectHandler {
    private static int count;

    public static final String ATTRIBUTE_PROPERTY = "property";

    protected CapturedObject createCapturedObject(String className, JAXXCapture capture) {
        return new CapturedObject(this, className, capture);
    }


    // returns true if the tag has any "void" children
    protected boolean processChildren(Element tag, Stack context, JAXXCapture capture) {
        boolean result = false;
        NodeList children = tag.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node child = children.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE) {
                Element innerTag = (Element) child;
                if (innerTag.getTagName().equals(JAXXCompilerFinalizer.TYPE_VOID)) {
                    result = true;
                }
                evaluate(innerTag, context, capture);
            }
        }
        return result;
    }


    protected void evaluateProperty(Element tag, Stack context, JAXXCapture capture) {
        // determine containing object
        CapturedObject contextObject = null;
        for (int i = context.size() - 1; i >= 0; i--) {
            if (context.get(i) instanceof CapturedObject) {
                contextObject = (CapturedObject) context.get(i);
                break;
            }
        }
        assert contextObject != null;

        String property = tag.getAttribute(ATTRIBUTE_PROPERTY);
        if (!property.equals("actionCommand")) { // filter out actionCommand due to screwiness in XMLEncoder's handling of it
            Object current = context.peek();
            PropertyNode newContext = new PropertyNode(property);
            context.push(newContext);
            boolean voidChildren = processChildren(tag, context, capture);

            ContextNode[] arguments = newContext.getArguments();
            if (arguments.length == 1) {
                if (current instanceof CapturedObject && arguments[0] instanceof ValueNode) // simple property assignment
                {
                    ((CapturedObject) current).setProperty(property, dataBindingEncode(String.valueOf(((ValueNode) arguments[0]).getValue())));
                } else if (current instanceof CapturedObject && arguments[0] instanceof CapturedObject && ((CapturedObject) arguments[0]).isInlineable()) // simple data binding
                {
                    ((CapturedObject) current).setProperty(property, "{" + capture.getJavaCode(arguments[0]) + "}");
                } else {
                    contextObject.setInlineable(false);
                    contextObject.appendScriptCode(capture.getJavaCode(context));
                }
            } else if (!voidChildren) {
                contextObject.setInlineable(false);
                contextObject.appendScriptCode(capture.getJavaCode(context));
            }

            assert context.peek() == newContext;
            context.pop();
        }
    }


    protected void evaluateAdd(CapturedObject contextObject, CapturedObject child, ContextNode constraints) {
        contextObject.addChild(child, constraints);
    }


    protected void evaluateMethod(Element tag, Stack context, JAXXCapture capture) {
        // determine containing object
        CapturedObject contextObject = null;
        for (int i = context.size() - 1; i >= 0; i--) {
            if (context.get(i) instanceof CapturedObject) {
                contextObject = (CapturedObject) context.get(i);
                break;
            }
        }
        assert contextObject != null;

        try {
            String methodName = tag.getAttribute("method");
            MethodNode newContext = new MethodNode(methodName);
            context.push(newContext);
            boolean voidChildren = processChildren(tag, context, capture);
            boolean add = false;

            ContextNode[] arguments = newContext.getArguments();
            if (methodName.equals("add") && arguments.length >= 1 && arguments[0] instanceof CapturedObject) {
                Class contextClass = Class.forName(contextObject.getClassName(), true, capture.getClassLoader());
                if (Container.class.isAssignableFrom(contextClass)) {
                    add = true;
                    evaluateAdd(contextObject, (CapturedObject) arguments[0], null);
                }
            }

            if (!voidChildren && !add) {
                contextObject.appendScriptCode(capture.getJavaCode(context));
            }

            assert context.peek() == newContext;
            context.pop();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }


    protected void evaluate(Element tag, Stack context, JAXXCapture capture) {
        String tagName = tag.getTagName();
        if (tagName.equals("object")) {
            String fieldName = tag.getAttribute("field");
            ContextNode currentNode = context.peek();
            if (fieldName.length() > 0) {
                try {
                    String className = tag.getAttribute("class");
                    Field field = Class.forName(className, true, capture.getClassLoader()).getField(fieldName);
                    Object value = field.get(null);
                    currentNode.addArgument(new LiteralNode(className + "." + fieldName, value));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                currentNode.addArgument(capture.processObject(tag, context));
            }
        } else if (tagName.equals(JAXXCompilerFinalizer.TYPE_VOID)) {
            String property = tag.getAttribute(ATTRIBUTE_PROPERTY);
            if (property.length() > 0) {
                evaluateProperty(tag, context, capture);
            } else {
                evaluateMethod(tag, context, capture);
            }
        } else if (tagName.equals("string")) {
            context.peek().addArgument(new ValueNode(JAXXCapture.getText(tag)));
        } else if (tagName.equals("boolean")) {
            context.peek().addArgument(new ValueNode(Boolean.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("char")) {
            context.peek().addArgument(new ValueNode(JAXXCapture.getText(tag).charAt(0)));
        } else if (tagName.equals("short")) {
            context.peek().addArgument(new ValueNode(Short.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("int")) {
            context.peek().addArgument(new ValueNode(Integer.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("long")) {
            context.peek().addArgument(new ValueNode(Long.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("float")) {
            context.peek().addArgument(new ValueNode(Float.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("double")) {
            context.peek().addArgument(new ValueNode(Double.valueOf(JAXXCapture.getText(tag))));
        } else if (tagName.equals("null")) {
            context.peek().addArgument(new ValueNode(null));
        } else {
            System.err.println("unsupported tag: " + tag.getTagName());
        }
    }


    private static String dataBindingEncode(String value) {
        return value.replaceAll("\\{", "\\\\{").replaceAll("\\}", "\\\\}");
    }


    public CapturedObject processObject(Element objectTag, Stack context, JAXXCapture capture) {
        String className = objectTag.getAttribute("class");
        if (className.length() > 0) {
            CapturedObject capturedObject = createCapturedObject(className, capture);
            context.push(capturedObject);
            NodeList children = objectTag.getChildNodes();
            String id = objectTag.getAttribute("id");
            if (id.length() == 0 || capture.getCapturedObjects().containsKey(id)) {
                id = "Auto" + ++count;
            }
            assert !capture.getCapturedObjects().containsKey(id);
            capture.getCapturedObjects().put(id, capturedObject);
            capturedObject.setProperty("id", id);
            // process object's name before anything else
            for (int i = 0; i < children.getLength(); i++) {
                Node child = children.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) child;
                    if (element.getTagName().equals(JAXXCompilerFinalizer.TYPE_VOID) && element.getAttribute(ATTRIBUTE_PROPERTY).equals("name")) {
                        evaluate(element, context, capture);
                        String name = capturedObject.getProperty("name");
                        if (name != null && !capture.getCapturedObjects().containsKey(name)) {
                            capture.getCapturedObjects().put(name, capturedObject);
                            capturedObject.setProperty("id", name);
                            capturedObject.getProperties().remove("name");
                        }
                    }
                }
            }
            // process remaining children
            for (int i = 0; i < children.getLength(); i++) {
                Node child = children.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) child;
                    if (!JAXXCompilerFinalizer.TYPE_VOID.equals(element.getTagName()) || !element.getAttribute(ATTRIBUTE_PROPERTY).equals("name")) {
                        evaluate(element, context, capture);
                    }
                }
            }
            assert context.peek() == capturedObject;
            context.pop();

            return capturedObject;
        } else {
            CapturedObject result = capture.getCapturedObjects().get(objectTag.getAttribute("idref"));
            if (result == null) {
                throw new RuntimeException("Internal error: could not find tag with id " + objectTag.getAttribute("idref"));
            }
            result.setInlineable(false); // we have at least two references to it, and so can't inline it
            return result;
        }
    }


    private static String xmlEncode(String src) {
        return src.replaceAll("'", "&").replaceAll("<", "<");
    }


    public String getXML(CapturedObject object, JAXXCapture capture) {
        StringBuilder result = new StringBuilder();
        result.append('<');
        String className = object.getClassName();
        if (className.startsWith("javax.swing.")) {
            className = className.substring("javax.swing.".length());
        }
        result.append(className);
        Map properties = object.getProperties();
        for (Map.Entry e : properties.entrySet()) {
            result.append(' ');
            result.append(e.getKey());
            result.append("='");
            result.append(xmlEncode(e.getValue()));
            result.append('\'');
        }
        ContextNode[] arguments = object.getArguments();
        if (arguments != null && arguments.length > 0) {
            result.append(" constructorParams='");
            for (int j = 0; j < arguments.length; j++) {
                if (j != 0) {
                    result.append(", ");
                }
                result.append(capture.getJavaCode(arguments[j]));
            }
            result.append('\'');
        }
        boolean tagClosed = false;

        String children = getChildXML(object, capture);
        String lineSeparator = JAXXCompiler.getLineSeparator();
        if (children != null && children.length() > 0) {
            if (!tagClosed) {
                tagClosed = true;
                result.append('>');
                result.append(lineSeparator);
            }
            result.append(children);
        }

        String script = object.getScriptCode();
        if (script != null && script.length() > 0) {
            if (!tagClosed) {
                tagClosed = true;
                result.append('>');
                result.append(lineSeparator);
            }
            result.append("  ");
            result.append(lineSeparator);
        }
        if (tagClosed) {
            result.append("');
        } else {
            result.append("/>");
        }
        return result.toString();
    }


    protected String getChildXML(CapturedObject object, JAXXCapture capture) {
        StringBuilder result = new StringBuilder();
        CapturedObject[] children = object.getChildren();
        String lineSeparator = JAXXCompiler.getLineSeparator();
        for (CapturedObject aChildren : children) {
            if (!aChildren.isInlineable()) {
                result.append(JavaFileGenerator.indent(aChildren.getXML(capture), 2, false, lineSeparator));
                result.append(lineSeparator);
            }
        }
        return result.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy