package context.arch.widget; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLEncoder; import java.util.Collection; import java.util.List; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import context.arch.discoverer.ComponentDescription; import context.arch.discoverer.component.ClassnameElement; import context.arch.discoverer.component.ConstantAttributeElement; import context.arch.discoverer.component.NonConstantAttributeElement; import context.arch.discoverer.query.ANDQueryItem; import context.arch.discoverer.query.AbstractQueryItem; import context.arch.discoverer.query.RuleQueryItem; import context.arch.storage.Attribute; import context.arch.storage.AttributeNameValue; import context.arch.storage.Attributes; /** * Utility class to generate Widget from an XML declaration. * Can also generate widget stubs in the form of ComponentDescription to be used * to generate QueryItems for subscribing to the widget. * @author Brian Y. Lim * @apiviz.uses context.arch.widget.Widget * */ public class WidgetXmlParser { /** * Stub class to generate Widget from an XML declaration. * @author Brian Y. Lim * */ private static class WidgetXml { private String classname; private String id; /** * Whether to register to the Discoverer. * Usually true, but null if just creating a stub */ private Boolean register = true; private Element rootNode; private WidgetXml(Document document, String id) { rootNode = document.getRootElement(); // <Widget> // widget name this.classname = rootNode.getAttributeValue("name"); // setWidgetClassName(name); // quality ID with widget name // setId(widgetName + '_' + id); this.id = id; } private WidgetXml(String filename, String id) { this(getDocument(filename), id); } public String getFullId() { return classname + "_" + urlEncode(id); } } public static AbstractQueryItem<?,?> createWidgetSubscriptionQuery(String filename, String id, Attributes constAtts) { return createWidgetSubscriptionQuery( WidgetXmlParser.createWidgetStub( new WidgetXml(filename, id), constAtts )); } /** * Convenience method to create a subscription query from a widget object. * @param widget * @return */ public static AbstractQueryItem<?,?> createWidgetSubscriptionQuery(Widget widget) { return createWidgetSubscriptionQuery( WidgetXmlParser.createWidgetStub(widget) ); } /** * Gets a subscription query based on the name of the widget, and * constant attribute values. The specified values help select the widget of interest * @param widgetStub a minimal description of the widget containing its name, id (maybe; but buggy now), and limited constant attributes with values. * @return an ANDQueryItem of multiple conditions to be satisfied to find this widget to subscribe to */ public static AbstractQueryItem<?,?> createWidgetSubscriptionQuery(ComponentDescription widgetStub) { String widgetName = widgetStub.classname; // String id = widgetStub.id; // may not have been set Collection<AttributeNameValue<?>> constAtts = widgetStub.getConstantAttributes(); // start with matching widget name ANDQueryItem query = new ANDQueryItem( RuleQueryItem.instance(new ClassnameElement(widgetName))); // add id if it was set // if (id != null) { // query.add(new RuleQueryItem<String, String>(new IdElement(id))); // } // still buggy // add constant attributes with values that were set for (AttributeNameValue<?> att : constAtts) { query.add(RuleQueryItem.instance(new ConstantAttributeElement(att))); } // Adicionando os non-constants atributos que serviram para validar os compenents description no metodo subscribe da class EnactorSubscriptionManager. // don't add non-constant attributes since tracking them would be for condition queries instead of subscription // for (String attName : widgetStub.getNonConstantAttributeNames()) { // Attribute<?> att = widgetStub.getNonConstantAttribute(attName); // AttributeNameValue<?> attNameValue = new AttributeNameValue(att.getName(),att.getType()); // query.add(RuleQueryItem.instance(new NonConstantAttributeElement(attNameValue))); // } //System.out.println("getWidgetSubscriptionQuery query = " + query); return query; } public static ComponentDescription createWidgetStub(Widget widget) { ComponentDescription comp = new ComponentDescription(); comp.classname = widget.getClassname(); comp.id = widget.getId(); comp.setConstantAttributes(widget.getConstantAttributes()); comp.setNonConstantAttributes(widget.getNonConstantAttributes()); return comp; } public static ComponentDescription createWidgetStub(final WidgetXml wxml, Attributes constAtts) { Widget widget = WidgetXmlParser.createWidget(wxml, constAtts); return WidgetXmlParser.createWidgetStub(widget); } public static ComponentDescription createWidgetStub(URL href, String widgetId, Attributes constAtts) { WidgetXml wxml = new WidgetXml(getDocument(href), widgetId); wxml.register = null; // so that no widget not registered return WidgetXmlParser.createWidgetStub(wxml, constAtts); } public static Widget createWidget(String filename, String widgetId, Attributes constAtts) { return createWidget(new WidgetXml(filename, widgetId), constAtts); } /** * Very basic widget with no explicit ID constant attribute values being set. * The ID is set by the timestamp of creation. * @param filename * @param widgetId * @return */ public static Widget createWidget(String filename) { return createWidget(new WidgetXml( filename, String.valueOf(System.currentTimeMillis())), new Attributes()); // empty constantAttVars map } /** * * @param wxml * @param constAttValues <attName, value> * @return */ public static Widget createWidget(final WidgetXml wxml, final Attributes constAtts) { Widget widget = new Widget( wxml.getFullId(), wxml.classname) { @SuppressWarnings("unchecked") @Override protected void init() { Namespace ns = wxml.rootNode.getNamespace(); // add attributes for (Element attrElem : (List<Element>) wxml.rootNode .getChild("Attributes", ns) .getChildren("Attribute", ns)) { // XML: could have specified as child element, but using attributes enforces string format String attName = attrElem.getAttributeValue("name"); String typeStr = attrElem.getAttributeValue("type"); boolean constant = Boolean.parseBoolean(attrElem.getAttributeValue("constant")); Attribute<?> att = createAttribute(attName, typeStr, constAtts.getAttributeValue(attName), constant); addAttribute(att, constant); } } @Override public String getClassname() { return wxml.classname; } }; widget.start(wxml.register); // to init and register to Discoverer after construction return widget; } @SuppressWarnings("unchecked") public static <T extends Comparable<? super T>> Attribute<T> createAttribute(String attName, String typeStr, T attValue, boolean constant) { Attribute<T> att; if (constant) { att = AttributeNameValue.instance( attName, attValue ); } else { Class<T> attType = (Class<T>) toClass(typeStr); att = Attribute.instance(attName, attType); } return att; } public static Class<?> toClass(String typeName) { if (typeName.equalsIgnoreCase("int")) { return Integer.class; } else if (typeName.equalsIgnoreCase("float")) { return Float.class; } else if (typeName.equalsIgnoreCase("double")) { return Double.class; } else if (typeName.equalsIgnoreCase("byte")) { return Byte.class; } else if (typeName.equalsIgnoreCase("short")) { return Short.class; } else if (typeName.equalsIgnoreCase("long")) { return Long.class; } else if (typeName.equalsIgnoreCase("boolean")) { return Boolean.class; } else if (typeName.equalsIgnoreCase("string")) { return String.class; } else { // use reflection to get class try { return Class.forName(typeName); } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } } } /* ================================================================================== */ private static SAXBuilder builder = new SAXBuilder(); /** * Convenience method to get an XML document from a file name. * @param filename * @return XML document */ public static Document getDocument(String filename) { try { return (Document) builder.build(new File(filename)); } catch (JDOMException e) { e.printStackTrace(); return null; } } /** * Convenience method to get an XML document from a URL. * @param url * @return XML document */ public static Document getDocument(URL url) { try { return (Document) builder.build(url); } catch (JDOMException e) { e.printStackTrace(); return null; } } public static String urlEncode(String s) { try { return URLEncoder.encode(s, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } }