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

com.google.gwt.uibinder.rebind.messages.MessagesWriter Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.uibinder.rebind.messages;

import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.i18n.client.Messages;
import com.google.gwt.uibinder.rebind.IndentedWriter;
import com.google.gwt.uibinder.rebind.MortalLogger;
import com.google.gwt.uibinder.rebind.UiBinderWriter;
import com.google.gwt.uibinder.rebind.XMLAttribute;
import com.google.gwt.uibinder.rebind.XMLElement;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * TemplateWriter for messages.
 */
public class MessagesWriter {

  public static final String ATTRIBUTE = "attribute";

  private static final String NAME = "name";
  private static final String[] EMPTY_ARRAY = {};

  private final String messagesNamespaceURI;
  private final String packageName;
  private final String messagesClassName;
  private final MortalLogger logger;
  private final List messages = new ArrayList();
  private final String generatedFrom;

  private String baseInterface;
  private String defaultLocale;
  private String messagesPrefix;
  private String generateKeys;
  private GenerateAnnotationWriter generate;

  private Map> elemToAttributeMessages =
      new HashMap>();

  private TypeOracle oracle;

  public MessagesWriter(TypeOracle oracle, String nameSpaceUri, MortalLogger mortalLogger, String generatedFrom,
      String packageName, String uiBinderImplClassName) {
    this.messagesNamespaceURI = nameSpaceUri;
    this.generatedFrom = generatedFrom;
    this.packageName = packageName;

    // Localizable classes cannot have underscores in their names.
    this.messagesClassName = uiBinderImplClassName.replaceAll("_", "") + "GenMessages";

    this.logger = mortalLogger;
    this.oracle = oracle;

    baseInterface = Messages.class.getCanonicalName();
  }

  /**
   * Call {@link #consumeAttributeMessages}, but instead of returning the
   * results store them for retrieval by a later call to
   * {@link #retrieveMessageAttributesFor}.
   *
   * @throws UnableToCompleteException on error
   */
  public void consumeAndStoreMessageAttributesFor(XMLElement elem)
      throws UnableToCompleteException {
    Collection attributeMessages =
        consumeAttributeMessages(elem);
    if (!attributeMessages.isEmpty()) {
      elemToAttributeMessages.put(elem, attributeMessages);
    }
  }

  /**
   * Examine the children of the given element. Consume those tagged m:attribute
   * and return a set of {@link AttributeMessage} instances. E.g.:
   * 

* *

   * <img src="blueSky.jpg" alt="A blue sky">
   *   <ui:attribute name="alt" description="blue sky image alt text"/>
   * </img>
   * 
* *

*/ public Collection consumeAttributeMessages(XMLElement elem) throws UnableToCompleteException { Collection messageChildren = getAttributeMessageChildren(elem); if (messageChildren.isEmpty()) { return Collections.emptySet(); } Set attributeMessages = new HashSet(); for (XMLElement child : messageChildren) { String attributeName = consumeMessageElementAttribute(NAME, child); if (attributeName.length() == 0) { logger.die(child, "Missing name attribute"); } if (!elem.hasAttribute(attributeName)) { logger.die(child, "The enclosing element needs to provide a " + "default value for attribute \"%s\"", attributeName); } XMLAttribute attribute = elem.getAttribute(attributeName); if (attribute.hasComputedValue()) { logger.die(elem, "Attribute \"%s\" has a field reference and " + "so cannot be marked for localization, but found %s", attributeName, child); } String defaultMessage = MessageWriter.escapeMessageFormat(elem.consumeRawAttribute(attributeName)); defaultMessage = UiBinderWriter.escapeTextForJavaStringLiteral(defaultMessage); attributeMessages.add(new AttributeMessage(attributeName, declareMessage( child, defaultMessage))); } return attributeMessages; } /** * Consume an m:blah attribute on a non-message element, e.g. * {@code } * * @param attName name of the attribute (to be prefixed with "msgprefix:") * @param elem element to search * @return attribute value, or an empty string if not found */ public String consumeMessageAttribute(String attName, XMLElement elem) { return consumeMessageAttribute(attName, elem, ""); } /** * Consume an m:blah attribute on a non-message element, e.g. * {@code } * * @param attName name of the attribute (to be prefixed with "msgprefix:") * @param elem element to search * @param defaultValue default value to return if the attribute is not present * @return attribute value, or {@code defaultValue} if not found */ public String consumeMessageAttribute(String attName, XMLElement elem, String defaultValue) { String fullAttName = getMessagesPrefix() + ":" + attName; return elem.consumeRawAttribute(fullAttName, defaultValue); } /** * Declares a message created by a previous call to {@link #newMessage}, and * returns its invocation expression to be stitched into an innerHTML block. */ public String declareMessage(MessageWriter newMessage) { messages.add(newMessage); return String.format("messages.%s", newMessage.getInvocation()); } /** * Expected to be called with the root element, to allow configuration from * various messages related attributes. * * @throws UnableToCompleteException */ public void findMessagesConfig(XMLElement elem) throws UnableToCompleteException { String prefix = elem.lookupPrefix(getMessagesUri()); if (prefix != null) { messagesPrefix = prefix; String baseInterfaceAttr = consumeMessageAttribute("baseMessagesInterface", elem, null); if (baseInterfaceAttr != null) { JClassType baseInterfaceType = oracle.findType(baseInterfaceAttr); if (baseInterfaceType == null) { logger.die(elem, "Could not find class %s", baseInterfaceAttr); } if (baseInterfaceType.isInterface() == null) { logger.die(elem, "%s must be an interface", baseInterfaceAttr); } JClassType msgType = oracle.findType(Messages.class.getCanonicalName()); if (msgType == null) { throw new RuntimeException("Internal Error: Messages interface not found"); } if (!msgType.isAssignableFrom(baseInterfaceType)) { logger.die(elem, "Interface %s must extend Messages", baseInterfaceAttr); } baseInterface = baseInterfaceAttr; } defaultLocale = consumeMessageAttribute("defaultLocale", elem); generateKeys = consumeMessageAttribute("generateKeys", elem); generate = new GenerateAnnotationWriter(getMessageAttributeStringArray( "generateFormat", elem), consumeMessageAttribute( "generateFilename", elem), getMessageAttributeStringArray( "generateLocales", elem)); } } /** * Returns the expression that will instantiate the Messages interface. */ public String getDeclaration() { return String.format( "static %1$s messages = (%1$s) GWT.create(%1$s.class);", getMessagesClassName()); } public String getMessagesClassName() { return messagesClassName; } /** * Returns the namespace prefix (not including :) declared by the template for * message elements and attributes. */ public String getMessagesPrefix() { return messagesPrefix; } /** * Confirm existence of an m:blah attribute on a non-message element, e.g. * {@code } */ public boolean hasMessageAttribute(String attName, XMLElement elem) { String fullAttName = getMessagesPrefix() + ":" + attName; return elem.hasAttribute(fullAttName); } /** * Returns true iff any messages have been declared. */ public boolean hasMessages() { return !messages.isEmpty(); } public boolean isMessage(XMLElement elem) { return isMessagePrefixed(elem) && "msg".equals(elem.getLocalName()); } /** * Creates a new MessageWriter instance with description, key and meaning * values consumed from the given XMLElement. Note that this message will not * be written in the generated code unless it is later declared via * {@link #declareMessage(MessageWriter)} */ public MessageWriter newMessage(XMLElement elem) { MessageWriter newMessage = new MessageWriter(consumeMessageElementAttribute("description", elem), consumeMessageElementAttribute("key", elem), consumeMessageElementAttribute("meaning", elem), nextMessageName()); return newMessage; } /** * Returns the set of AttributeMessages that were found in elem and stored by a * previous call to {@link #consumeAndStoreMessageAttributesFor}. */ public Collection retrieveMessageAttributesFor( XMLElement elem) { return elemToAttributeMessages.get(elem); } public void write(PrintWriter printWriter) { IndentedWriter writer = new IndentedWriter(printWriter); // Package declaration. if (packageName.length() > 0) { writer.write("package %1$s;", packageName); writer.newline(); } // Imports. writer.write("import static com.google.gwt.i18n.client.LocalizableResource.*;"); writer.newline(); // Open interface. genInterfaceAnnotations(writer); writer.write("public interface %s extends %s {", getMessagesClassName(), baseInterface); writer.newline(); writer.indent(); // Write message methods for (MessageWriter m : messages) { m.writeDeclaration(writer); } // Close interface. writer.outdent(); writer.write("}"); } /** * Consume an attribute on a messages related element (as oppposed to a * messages attribute in some other kind of element), e.g. the description in * {@code } */ String consumeMessageElementAttribute(String attName, XMLElement elem) { if (elem.hasAttribute(attName)) { return UiBinderWriter.escapeTextForJavaStringLiteral(elem.consumeRawAttribute(attName)); } String fullAttName = getMessagesPrefix() + ":" + attName; if (elem.hasAttribute(fullAttName)) { String value = elem.consumeRawAttribute(fullAttName); logger.warn(elem, "Deprecated prefix \"%s:\" on \"%s\". Use \"%s\" instead.", getMessagesPrefix(), fullAttName, attName); return value; } return ""; } String consumeRequiredMessageElementAttribute(String attName, XMLElement elem) throws UnableToCompleteException { String value = consumeMessageElementAttribute(attName, elem); if ("".equals(value)) { logger.die(elem, "Missing required attribute %s", attName); } return value; } boolean isMessagePrefixed(XMLElement elem) { String uri = elem.getNamespaceUri(); return uri != null && uri.startsWith(getMessagesUri()); } private String declareMessage(XMLElement elem, String defaultMessage) { List emptyList = Collections.emptyList(); MessageWriter newMessage = newMessage(elem); newMessage.setDefaultMessage(defaultMessage); for (PlaceholderWriter placeholder : emptyList) { newMessage.addPlaceholder(placeholder); } return declareMessage(newMessage); } private void genInterfaceAnnotations(IndentedWriter pw) { pw.write("@GeneratedFrom(\"%s\")", generatedFrom); if (defaultLocale.length() > 0) { pw.write("@DefaultLocale(\"%s\")", defaultLocale); } if (generateKeys.length() > 0) { pw.write("@GenerateKeys(\"%s\")", generateKeys); } generate.write(pw); } private Collection getAttributeMessageChildren( final XMLElement elem) throws UnableToCompleteException { return elem.consumeChildElements(new XMLElement.Interpreter() { public Boolean interpretElement(XMLElement child) throws UnableToCompleteException { if (isAttributeMessage(child)) { if (child.hasChildNodes()) { logger.die(child, "Illegal body.", child, elem); } return true; } return false; } }); } private String[] getMessageAttributeStringArray(String attName, XMLElement elem) { String value = consumeMessageAttribute(attName, elem, null); if (value == null) { return EMPTY_ARRAY; } return value.split("\\s*,\\s*"); } private String getMessagesUri() { return messagesNamespaceURI; } private boolean isAttributeMessage(XMLElement elem) { return isMessagePrefixed(elem) && ATTRIBUTE.equals(elem.getLocalName()); } private String nextMessageName() { return String.format("message%d", messages.size() + 1); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy