Package com.googlecode.gwt.test.uibinder

Source Code of com.googlecode.gwt.test.uibinder.UiResourceManager$UiTextTag

package com.googlecode.gwt.test.uibinder;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.gwt.dom.client.Element;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.DataResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.resources.client.TextResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.UIObject;
import com.googlecode.gwt.test.exceptions.GwtTestUiBinderException;
import com.googlecode.gwt.test.exceptions.ReflectionException;
import com.googlecode.gwt.test.internal.resources.ResourcePrototypeProxyBuilder;
import com.googlecode.gwt.test.utils.GwtReflectionUtils;

/**
* Class responsible for managing declared resources, e.g. <ui:with />, <ui:style />, <ui:image />
* and <ui:data /> tags.
*
* @author Gael Lazzari
*
*/
class UiResourceManager {

   /**
    * Handles <ui:data /> tags.
    */
   private static class UiDataTag extends UiResourceTag {

      UiDataTag(ResourcePrototypeProxyBuilder builder, String alias, UiTag<?> parentTag,
               Object owner, Map<String, Object> resources, Map<String, Object> attributes) {
         super(builder, alias, parentTag, owner, resources);

         // handle "src" attribute
         String src = (String) attributes.get("src");
         builder.resourceURL(computeImageURL(owner, src));
      }

      @Override
      protected Object buildObject(ResourcePrototypeProxyBuilder builder) {
         return builder.build();
      }

      private URL computeImageURL(Object owner, String src) {
         URL dataURL = owner.getClass().getResource(src);

         if (dataURL == null) {
            throw new GwtTestUiBinderException("Cannot find binary file with src=\"" + src
                     + "\" declared in " + owner.getClass().getSimpleName() + ".ui.xml");
         }

         return dataURL;
      }
   }

   /**
    * Handles <ui:image /> tags.
    */
   private static class UiImgTag extends UiResourceTag {

      UiImgTag(ResourcePrototypeProxyBuilder builder, String alias, UiTag<?> parentTag,
               Object owner, Map<String, Object> resources, Map<String, Object> attributes) {
         super(builder, alias, parentTag, owner, resources);

         // handle "src" attribute
         String src = (String) attributes.get("src");
         builder.resourceURL(computeImageURLs(owner, src));
      }

      @Override
      protected Object buildObject(ResourcePrototypeProxyBuilder builder) {
         return builder.build();
      }

      private URL computeImageURLs(Object owner, String src) {
         URL imageURL = owner.getClass().getResource(src);

         if (imageURL == null) {
            throw new GwtTestUiBinderException("Cannot find image file with src=\"" + src
                     + "\" declared in " + owner.getClass().getSimpleName() + ".ui.xml");
         }

         return imageURL;
      }

   }

   /**
    * Handles <ui:import> tags.
    */
   private static class UiImportTag implements UiTag<Object> {

      private final UiTag<?> parentTag;

      UiImportTag(Map<String, Object> attributes, UiTag<?> parentTag,
               Map<String, Object> resources, Object owner) {
         this.parentTag = parentTag;
         // collects single and multiple imports in UiBinderResourceManager
         // inner
         // map
         collectObjectToImport(attributes, resources, owner);
      }

      public void addElement(Element element) {
         // nothing to do
      }

      public void addUiObject(UIObject uiObject) {
         // nothing to do
      }

      public void addWidget(IsWidget widget) {
         // nothing to do
      }

      public void appendText(String text) {
         // nothing to do
      }

      public Object endTag() {
         // the result will not be used by UiBinderTagBuilder
         return null;
      }

      public UiTag<?> getParentTag() {
         return parentTag;
      }

      private void collectMultipleImports(String importValue, Map<String, Object> resources,
               Object owner) {

         try {
            String className = importValue.substring(0, importValue.lastIndexOf('.'));

            Class<?> clazz = GwtReflectionUtils.getClass(className);

            // this code handles classes and enums fine
            for (Field field : GwtReflectionUtils.getFields(clazz)) {
               if (Modifier.isStatic(field.getModifiers())
                        && !Modifier.isPrivate(field.getModifiers())
                        && !Modifier.isProtected(field.getModifiers())) {
                  // register static field value in UiResourcesManager inner map
                  Object value = GwtReflectionUtils.getStaticFieldValue(clazz, field.getName());
                  resources.put(field.getName(), value);
               }
            }

         } catch (Exception e) {
            throw new GwtTestUiBinderException("Error while trying to import multiple ui fields '"
                     + importValue + "'", e);
         }
      }

      private Map<String, Object> collectObjectToImport(Map<String, Object> attributes,
               Map<String, Object> resources, Object owner) {
         Map<String, Object> result = new HashMap<String, Object>();

         for (Map.Entry<String, Object> entry : attributes.entrySet()) {
            String attrName = entry.getKey();
            String attrValue = entry.getValue().toString().trim();

            // ignore attributes other than <ui:field>
            if (!"ui:field".equals(attrName)) {
               continue;
            }

            // ignore empty attributes
            if (attrValue.length() == 0) {
               continue;
            }

            int token = attrValue.lastIndexOf('.');
            if (token > -1 && token < attrValue.length() - 1
                     && attrValue.substring(token).equals(".*")) {
               // case of multiple import
               collectMultipleImports(attrValue, resources, owner);

            } else {
               // case of single import
               collectSingleImport(attrValue, resources, owner);
            }
         }

         return result;
      }

      private void collectSingleImport(String importValue, Map<String, Object> resources,
               Object owner) {
         try {
            int token = importValue.lastIndexOf('.');
            String className = importValue.substring(0, token);
            Class<?> clazz = GwtReflectionUtils.getClass(className);
            String fieldName = importValue.substring(token + 1);

            Object objectToImport = GwtReflectionUtils.getStaticFieldValue(clazz, fieldName);

            // register static field value in UiResourcesManager inner map
            resources.put(fieldName, objectToImport);

         } catch (Exception e) {
            throw new GwtTestUiBinderException("Error while trying to import ui field '"
                     + importValue + "'", e);
         }
      }
   }

   /**
    * Handles <ui:msg /> tags.
    *
    * @author Gael Lazzari
    *
    */
   private static class UiMsgTag implements UiTag<String> {

      private final UiTag<?> parentTag;
      private final StringBuilder sb;

      UiMsgTag(UiTag<?> parent) {
         this.parentTag = parent;
         sb = new StringBuilder();
      }

      public void addElement(Element element) {
         sb.append("<").append(element.getTagName());
         // TODO : append attributes
         sb.append(">").append(element.getInnerText()).append("</").append(element.getTagName()).append(
                  ">");
      }

      public void addUiObject(UIObject uiObject) {
         parentTag.addUiObject(uiObject);
      }

      public void addWidget(IsWidget isWidget) {
         parentTag.addWidget(isWidget);

      }

      public void appendText(String data) {
         sb.append(data);
      }

      public String endTag() {
         return sb.toString();
      }

      public UiTag<?> getParentTag() {
         return parentTag;
      }
   }

   /**
    * Base class for resource tags : <ui:style />, <ui:image /> and <ui:data />
    *
    */
   private static abstract class UiResourceTag implements UiTag<Object> {

      private final String alias;
      private final ResourcePrototypeProxyBuilder builder;
      private final Object owner;
      private final UiTag<?> parentTag;
      private final Map<String, Object> resources;
      private Object wrappedObject;

      UiResourceTag(ResourcePrototypeProxyBuilder builder, String alias, UiTag<?> parentTag,
               Object owner, Map<String, Object> resources) {
         this.builder = builder;
         this.owner = owner;
         this.parentTag = parentTag;
         this.alias = alias;
         this.resources = resources;
      }

      public void addElement(Element element) {
         // adapter method
      }

      public void addUiObject(UIObject uiObject) {
         // adapter method
      }

      public void addWidget(IsWidget widget) {
         // adapter method
      }

      public void appendText(String text) {
         // adapter method
      }

      public Object endTag() {
         if (wrappedObject == null) {
            // delegate the creation to subclasses
            wrappedObject = buildObject(builder);

            // set the corresponding @UiField
            Field resourceUiField = getUniqueUiField(alias);
            if (resourceUiField != null) {
               try {
                  resourceUiField.set(owner, wrappedObject);
               } catch (Exception e) {
                  throw new ReflectionException(e);
               }
            }

            // register the built resource to the resourceManager inner map
            resources.put(alias, wrappedObject);

         }

         return wrappedObject;
      }

      public UiTag<?> getParentTag() {
         return parentTag;
      }

      protected abstract Object buildObject(ResourcePrototypeProxyBuilder builder);

      private Field getUniqueUiField(String alias) {
         Set<Field> resourceFields = GwtReflectionUtils.getFields(owner.getClass());
         if (resourceFields.size() == 0) {
            return null;
         }

         Field result = null;

         for (Field f : resourceFields) {
            if (alias.equals(f.getName()) && f.isAnnotationPresent(UiField.class)) {
               if (result != null) {
                  throw new GwtTestUiBinderException("There are more than one '" + f.getName()
                           + "' @UiField in class '" + owner.getClass().getName()
                           + "' or its superclass");
               }

               result = f;
            }
         }

         return result;
      }

   }

   /**
    * Handles <ui:style /> tags with a "type" attribute to specify a {@link CssResource} subtype.
    */
   private static class UiStyleTag extends UiResourceTag {

      private final StringBuilder text;

      UiStyleTag(ResourcePrototypeProxyBuilder builder, String alias, UiTag<?> parentTag,
               Object owner, Map<String, Object> resources) {
         super(builder, alias, parentTag, owner, resources);
         this.text = new StringBuilder();
      }

      @Override
      public void appendText(String text) {
         this.text.append(text.trim());
      }

      @Override
      protected Object buildObject(ResourcePrototypeProxyBuilder builder) {
         return builder.text(text.toString()).build();
      }

   }

   /**
    * Handles <ui:text /> tags
    */
   private static class UiTextTag implements UiTag<String> {

      private final UiTag<?> parentTag;
      private final String text;

      UiTextTag(Map<String, Object> attributes, UiTag<?> parentTag, Object owner) {
         this.parentTag = parentTag;

         Object value = attributes.get("from");
         if (value instanceof TextResource) {
            text = ((TextResource) value).getText();
         } else if (value instanceof String) {
            text = (String) value;
         } else {
            throw new GwtTestUiBinderException("Error in " + owner.getClass().getSimpleName()
                     + ".ui.xml : <ui:text> tag declared without 'from' attribute");
         }
      }

      public void addElement(Element element) {
         // adapter method
      }

      public void addUiObject(UIObject uiObject) {
         // adapter method
      }

      public void addWidget(IsWidget widget) {
         // adapter method
      }

      public void appendText(String text) {
         // adapter method
      }

      public String endTag() {
         return text;
      }

      public UiTag<?> getParentTag() {
         return parentTag;
      }

   }

   /**
    * Handles <ui:with /> tags.
    */
   private static class UiWithTag implements UiTag<Object> {

      private final Object with;

      public UiWithTag(Object with) {
         this.with = with;
      }

      public void addElement(Element element) {
         // nothing to do
      }

      public void addUiObject(UIObject uiObject) {
         // nothing to do
      }

      public void addWidget(IsWidget isWidget) {
         // nothing to do
      }

      public void appendText(String text) {
         // nothing to do
      }

      public Object endTag() {
         return with;
      }

      public UiTag<?> getParentTag() {
         // nothing to do
         return null;
      }

   }

   /**
    * Constructs a new UiResourceManager associated with a widget.
    *
    * @param owner The {@link UiBinder} owner widget to be associated with the UiResourceManager,
    *           which calls the {@link UiBinder#createAndBindUi(Object)} method to initialize itself
    * @return The new instance
    */
   static final UiResourceManager newInstance(Object owner) {
      return new UiResourceManager(owner);
   }

   private final Object owner;
   private final Map<String, Object> resources = new HashMap<String, Object>();

   private UiResourceManager(Object owner) {
      this.owner = owner;
   }

   /**
    * Get a resource declared in the .ui.xml file with the <with res="alias" /> tag.
    *
    * @param alias The alias of the resource ('res' attribute in the .ui.xml file)
    * @return The corresponding resource, or null if it does not exist
    */
   @SuppressWarnings("unchecked")
   <T> T getUiResource(String alias) {
      return (T) resources.get(alias);
   }

   /**
    * Register some new resources which should correspond to a <ui:import> tag in the .ui.xml file.
    *
    * @param attributes Map of attributes parsed from the tag
    * @param parentTag The parent tag if any
    * @param owner The {@link UiBinder} owner widget, which calls the
    *           {@link UiBinder#createAndBindUi(Object)} method to initialize itself.
    * @return The UiBinderTag which has registered the imported object instances in the
    *         {@link UiResourceManager}.
    */
   UiTag<?> registerImport(Map<String, Object> attributes, UiTag<?> parentTag, Object owner) {
      return new UiImportTag(attributes, parentTag, resources, owner);
   }

   /**
    * Register a <ui:msg> tag declared in the .ui.xml file.
    *
    * @param attributes Map of attributes parsed from the tag
    * @param parentTag The parent tag if any
    * @param owner The {@link UiBinder} owner widget, which calls the
    *           {@link UiBinder#createAndBindUi(Object)} method to initialize itself.
    * @return The UiBinderTag which has registered the imported object instances in the
    *         {@link UiResourceManager}.
    */
   UiTag<String> registerMsg(Map<String, Object> attributes, UiTag<?> parentTag, Object owner) {
      return new UiMsgTag(parentTag);
   }

   /**
    * Register a new resource which should correspond to a resource tag in the .ui.xml file.
    *
    * @param localName The type of the resource ('with', 'style', 'image' or 'data')
    * @param attributes Map of attributes parsed from the tag
    * @param parentTag The parent tag if any
    * @param owner The {@link UiBinder} owner widget, which calls the
    *           {@link UiBinder#createAndBindUi(Object)} method to initialize itself.
    * @return The UiBinderTag which wraps the Resource instance.
    *
    * @throws GwtTestUiBinderException If the localName is not managed or if the alias is already
    *            binded to another Resource object
    */
   UiTag<?> registerResource(String localName, Map<String, Object> attributes, UiTag<?> parentTag,
            Object owner) throws GwtTestUiBinderException {

      String alias = getResourceAlias(localName, attributes);

      if (resources.containsKey(alias)) {
         throw new GwtTestUiBinderException("Two inner resources '" + alias + " are declared in "
                  + owner.getClass().getSimpleName()
                  + ".ui.xml. You should add a 'field' attribute to one of them");
      }

      Class<?> type = getResourceType(alias, localName, attributes);

      if ("with".equals(localName)) {
         // special resource <ui:with> : the resource can be annotated with
         // @UiConstructor, @UiFactory or @UiField(provided=true)
         Object resource = UiBinderInstanciator.getInstance(type, attributes, owner);
         resources.put(alias, resource);
         return new UiWithTag(resource);

      }

      ResourcePrototypeProxyBuilder builder = ResourcePrototypeProxyBuilder.createBuilder(type,
               owner.getClass());
      // common properties
      builder.name(alias);

      if ("style".equals(localName)) {
         // <ui:style>
         return new UiStyleTag(builder, alias, parentTag, owner, resources);

      } else if ("image".equals(localName)) {
         // <ui:image>
         return new UiImgTag(builder, alias, parentTag, owner, resources, attributes);

      } else if ("data".equals(localName)) {
         // <ui:data>
         return new UiDataTag(builder, alias, parentTag, owner, resources, attributes);
      } else {
         throw new GwtTestUiBinderException("resource <" + localName
                  + "> element is not yet implemented by gwt-test-utils");
      }
   }

   /**
    * Register a <ui:text> tag declared in the .ui.xml file.
    *
    * @param attributes Map of attributes parsed from the tag
    * @param parentTag The parent tag if any
    * @param owner The {@link UiBinder} owner widget, which calls the
    *           {@link UiBinder#createAndBindUi(Object)} method to initialize itself.
    * @return The UiBinderTag which has registered the imported object instances in the
    *         {@link UiResourceManager}.
    */
   UiTag<String> registerText(Map<String, Object> attributes, UiTag<?> parentTag, Object owner) {
      return new UiTextTag(attributes, parentTag, owner);
   }

   private String getResourceAlias(String localName, Map<String, Object> attributes) {
      String alias;
      alias = (String) attributes.get("ui:field");
      if (alias == null && !"with".equals(localName)) {
         alias = localName;
      }
      if (alias == null) {
         throw new GwtTestUiBinderException("Cannot find the required 'field' value for tag <"
                  + localName + "> in " + owner.getClass().getSimpleName() + ".ui.xml");
      }

      return alias;
   }

   private Class<?> getResourceType(String alias, String localName, Map<String, Object> attributes) {
      String type = (String) attributes.get("type");

      if (type == null && "image".equals(localName)) {
         // special code for <ui:image> with no 'type' attribute
         return ImageResource.class;
      } else if (type == null && "style".equals(localName)) {
         // special code for <ui:style> with no 'type' attribute
         return CssResource.class;
      } else if (type == null && "data".equals(localName)) {
         // special code for <ui:data> with no 'type' attribute
         return DataResource.class;
      } else if (type == null && "text".equals(localName)) {
         // sepcial code for <ui:text> with no 'type' attribute
         return TextResource.class;
      } else if (type == null) {
         throw new GwtTestUiBinderException("<" + localName + "> element declared in "
                  + owner.getClass().getSimpleName() + ".ui.xml must specify a 'type' attribute");
      }

      try {
         return GwtReflectionUtils.getClass(type);
      } catch (ClassNotFoundException e2) {
         throw new GwtTestUiBinderException("Cannot find class '" + type + "' for resource '"
                  + alias + "' declared in file '" + owner.getClass().getSimpleName() + ".ui.xml'");
      }
   }
}
TOP

Related Classes of com.googlecode.gwt.test.uibinder.UiResourceManager$UiTextTag

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.