Package org.jboss.errai.bus.rebind

Source Code of org.jboss.errai.bus.rebind.BusClientConfigGenerator$ValueBinder

/*
* Copyright 2010 JBoss, a divison Red Hat, 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 org.jboss.errai.bus.rebind;

import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.*;
import com.google.gwt.user.rebind.SourceWriter;
import org.jboss.errai.bus.server.ErraiBootstrapFailure;
import org.jboss.errai.bus.server.annotations.ExposeEntity;
import org.jboss.errai.bus.server.annotations.Remote;
import org.jboss.errai.bus.server.service.ErraiServiceConfigurator;
import org.jboss.errai.bus.server.service.metadata.MetaDataScanner;
import org.mvel2.templates.CompiledTemplate;
import org.mvel2.util.Make;
import org.mvel2.util.ParseTools;
import org.mvel2.util.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import static org.mvel2.templates.TemplateCompiler.compileTemplate;
import static org.mvel2.templates.TemplateRuntime.execute;

/**
* @author Mike Brock
* @author Heiko Braun
*/
public class BusClientConfigGenerator implements ExtensionGenerator {
  private Logger log = LoggerFactory.getLogger(BusClientConfigGenerator.class);

  private CompiledTemplate demarshallerGenerator;
  private CompiledTemplate marshallerGenerator;
  private CompiledTemplate rpcProxyGenerator;

  public BusClientConfigGenerator() {
    InputStream istream = this.getClass().getResourceAsStream("DemarshallerGenerator.mv");
    demarshallerGenerator = compileTemplate(istream, null);

    istream = this.getClass().getResourceAsStream("MarshallerGenerator.mv");
    marshallerGenerator = compileTemplate(istream, null);

    istream = this.getClass().getResourceAsStream("RPCProxyGenerator.mv");
    rpcProxyGenerator = compileTemplate(istream, null);
  }

  public void generate(
          GeneratorContext context, TreeLogger logger,
          SourceWriter writer, MetaDataScanner scanner, final TypeOracle oracle) {

    for (Class<?> entity : scanner.getTypesAnnotatedWith(ExposeEntity.class)) {
      generateMarshaller(loadType(oracle, entity), logger, writer);
    }

    for (Class<?> remote : scanner.getTypesAnnotatedWith(Remote.class)) {
      JClassType type = loadType(oracle, remote);
      try {
        writer.print((String) execute(rpcProxyGenerator,
                Make.Map.<String, Object>$()
                        ._("implementationClassName", type.getName() + "Impl")
                        ._("interfaceClass", Class.forName(type.getQualifiedSourceName()))
                        ._()));
      }
      catch (Throwable t) {
        throw new ErraiBootstrapFailure(t);
      }
    }

    Properties props = scanner.getProperties("ErraiApp.properties");
    if (props != null) {
      logger.log(TreeLogger.Type.INFO, "Checking ErraiApp.properties for configured types ...");

      for (Object o : props.keySet()) {
        String key = (String) o;
        /**
         * Types configuration
         */
        if (ErraiServiceConfigurator.CONFIG_ERRAI_SERIALIZABLE_TYPE.equals(key)) {
          for (String s : props.getProperty(key).split(" ")) {
            try {
              generateMarshaller(oracle.getType(s.trim()), logger, writer);
            }
            catch (Exception e) {
              e.printStackTrace();
              throw new ErraiBootstrapFailure(e);
            }
          }
        }

        /**
         * Entity configuration
         */
        else if (ErraiServiceConfigurator.CONFIG_ERRAI_SERIALIZABLE_TYPE.equals(key)) {
          for (String s : props.getProperty(key).split(" ")) {
            try {
              generateMarshaller(oracle.getType(s.trim()), logger, writer);
            }
            catch (Exception e) {
              e.printStackTrace();
              throw new ErraiBootstrapFailure(e);
            }
          }
        }
      }
    }
    else {
      // props not found
      log.warn("No modules found ot load. Unable to find ErraiApp.properties in the classpath");
    }
  }

  private JClassType loadType(TypeOracle oracle, Class<?> entity) {
    try {
      return oracle.getType(entity.getCanonicalName());
    }
    catch (NotFoundException e) {
      throw new RuntimeException("Failed to load type " + entity.getName(), e);
    }
  }

  private void generateMarshaller(JClassType visit, TreeLogger logger, SourceWriter writer) {
    Boolean enumType = visit.isEnum() != null;
    Map<String, Class> types = new HashMap<String, Class>();
    Map<String, ValueExtractor> getters = new HashMap<String, ValueExtractor>();
    Map<String, ValueBinder> setters = new HashMap<String, ValueBinder>();
    Map<Class, Integer> arrayConverters = new HashMap<Class, Integer>();

    try {
      JClassType scan = visit;

      do {
        for (JField f : scan.getFields()) {
          if (f.isTransient() || f.isStatic() || f.isEnumConstant() != null) continue;

          JClassType type = f.getType().isClassOrInterface();
          JMethod getterMeth;
          JMethod setterMeth;
          if (type == null) {
            JPrimitiveType pType = f.getType().isPrimitive();
            Class c;
            if (pType == null) {
              JArrayType aType = f.getType().isArray();
              if (aType == null) continue;

              String name = aType.getQualifiedBinaryName();
              int depth = 0;
              for (int i = 0; i < name.length(); i++) {
                if (name.charAt(i) == '[') depth++;
                else break;
              }

              types.put(f.getName(), c = Class.forName(name.substring(0, depth)
                      + getInternalRep(aType.getQualifiedBinaryName().substring(depth))));
              arrayConverters.put(c, depth);
            }
            else {
              types.put(f.getName(), c = ParseTools.unboxPrimitive(Class.forName(pType.getQualifiedBoxedSourceName())));
            }
          }
          else {
            types.put(f.getName(), Class.forName(type.getQualifiedBinaryName()));
          }

          getterMeth = getAccessorMethod(visit, f);
          setterMeth = getSetterMethod(visit, f);

          if (getterMeth == null) {
            if (f.isPublic()) {
              getters.put(f.getName(), new ValueExtractor(f));
            }
            else if (visit == scan) {
              throw new GenerationException("could not find a read accessor in class: "
                      + visit.getQualifiedSourceName() + "; for field: " + f.getName() + "; should declare an accessor: "
                      + ReflectionUtil.getGetter(f.getName()));
            }
          }
          else {
            getters.put(f.getName(), new ValueExtractor(getterMeth));
          }

          if (setterMeth == null) {
            if (f.isPublic()) {
              setters.put(f.getName(), new ValueBinder(f));
            }
            else if (visit == scan) {
              throw new GenerationException("could not find a write accessor in class: " + visit.getQualifiedSourceName()
                      + "; for field: " + f.getName() + "; should declare an accessor: " + ReflectionUtil.getSetter(f.getName()));
            }
            else {
              types.remove(f.getName());
            }
          }
          else {
            setters.put(f.getName(), new ValueBinder(setterMeth));
          }
        }
      }
      while ((scan = scan.getSuperclass()) != null && !scan.getQualifiedSourceName().equals("java.lang.Object"));

    }
    catch (ClassNotFoundException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }

    try {
      if (!enumType) visit.getConstructor(new JClassType[0]);
    }
    catch (NotFoundException e) {
      String errorMsg = "Type marked for serialization does not expose a default constructor: "
              + visit.getQualifiedSourceName();
      logger.log(TreeLogger.Type.ERROR, errorMsg, e);
      throw new GenerationException(errorMsg, e);
    }

    Map<String, Object> templateVars = Make.Map.<String, Object>$()
            ._("className", visit.getQualifiedSourceName())
            ._("canonicalClassName", visit.getQualifiedBinaryName())
            ._("fields", types.keySet())
            ._("targetTypes", types)
            ._("getters", getters)
            ._("setters", setters)
            ._("arrayConverters", arrayConverters)
            ._("enumType", enumType)._();

    String genStr;

    writer.print(genStr = (String) execute(demarshallerGenerator, templateVars));

    log.debug("generated demarshaller: \n" + genStr);

    logger.log(TreeLogger.Type.INFO, genStr);

    writer.print(genStr = (String) execute(marshallerGenerator, templateVars));

    log.debug("generated marshaller: \n" + genStr);

    logger.log(TreeLogger.Type.INFO, genStr);
    logger.log(TreeLogger.Type.INFO, "Generated marshaller/demarshaller for: " + visit.getName());
  }

  public static class ValueExtractor {
    private boolean accessor;
    private String name;

    public ValueExtractor(JMethod m) {
      accessor = true;
      name = m.getName();
    }

    public ValueExtractor(JField f) {
      accessor = false;
      name = f.getName();
    }

    @Override
    public String toString() {
      return accessor ? name + "()" : name;
    }
  }

  public static class ValueBinder {
    private boolean accessor;
    private String name;

    public ValueBinder(JMethod m) {
      accessor = true;
      name = m.getName();
    }

    public ValueBinder(JField f) {
      accessor = false;
      name = f.getName();
    }

    public String bindValue(String expr) {
      return accessor ? name + "(" + expr + ")" : "name = " + expr;
    }
  }

  private static JMethod getAccessorMethod(JClassType clazz, JField field) {
    JMethod m = null;

    if (field.getType().getQualifiedSourceName().equals("boolean"))
      m = _findGetterMethod(clazz, ReflectionUtil.getIsGetter(field.getName()));

    if (m == null)
      m = _findGetterMethod(clazz, ReflectionUtil.getGetter(field.getName()));

    if (m == null)
      m = _findGetterMethod(clazz, "get" + field.getName());

    return m;
  }

  private static JMethod getSetterMethod(JClassType clazz, JField field) {
    JMethod m = null;

    m = _findSetterMethod(clazz, field.getType(), ReflectionUtil.getSetter(field.getName()));

    if (m == null)
      m = _findSetterMethod(clazz, field.getType(), "set" + field.getName());

    return m;
  }


  private static JMethod _findGetterMethod(JClassType clazz, String methName) {
    JClassType scan = clazz;
    do {
      try {
        return scan.getMethod(methName, new JType[0]);
      }
      catch (NotFoundException e) {
        //
      }
    } while ((scan = scan.getSuperclass()) != null && !scan.getQualifiedSourceName().equals("java.lang.Object"));
    return null;
  }

  private static JMethod _findSetterMethod(JClassType clazz, JType field, String methName) {
    JClassType scan = clazz;
    do {

      try {
        return scan.getMethod(methName, new JType[]{field});
      }
      catch (NotFoundException e) {
        //
      }
    } while ((scan = scan.getSuperclass()) != null && !scan.getQualifiedSourceName().equals("java.lang.Object"));
    return null;
  }

  private String getInternalRep(String c) {
    if ("char".equals(c)) {
      return "C";
    }
    else if ("byte".equals(c)) {
      return "B";
    }
    else if ("double".equals(c)) {
      return "D";
    }
    else if ("float".equals(c)) {
      return "F";
    }
    else if ("int".equals(c)) {
      return "I";
    }
    else if ("long".equals(c)) {
      return "J";
    }
    else if ("short".equals(c)) {
      return "S";
    }
    else if ("boolean".equals(c)) {
      return "Z";
    }
    return "L" + c + ";";
  }

}
TOP

Related Classes of org.jboss.errai.bus.rebind.BusClientConfigGenerator$ValueBinder

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.