public List<String> onTabComplete(
      CommandSender commandSender, Command command, String s, String[] strings) {

    for (TabCompleter completer : delegateCompleters) {
      List<String> list = completer.onTabComplete(commandSender, command, s, strings);
      if (list != null) return list;
    }

    String expression = strings[strings.length - 1];
    TreeSet<String> result = new TreeSet<String>();
    Caller caller = plugin.getCallerService().getCaller(commandSender);
    WorkspaceService service = plugin.getWorkspaceService();
    String workspaceName = service.getWorkspaceName(commandSender);
    Workspace workspace = service.getWorkspace(workspaceName);
    LinkedList<String> tokens = new LinkedList<String>();
    boolean needHelp = expression.endsWith("?");
    if (needHelp) expression = expression.substring(0, expression.length() - 1);
    Collections.addAll(tokens, expression.split("\\."));
    if (expression.endsWith(".")) tokens.add("");

    if (needHelp) {
      getHelp(caller, workspace, tokens);
      return Collections.singletonList(expression);
    }

    String firstToken = tokens.pollFirst();
    if (firstToken == null) firstToken = "";
    MetaClass callerScriptMetaClass = InvokerHelper.getMetaClass(CallerScript.class);
    MetaClass workspaceMetaClass = InvokerHelper.getMetaClass(Workspace.class);
    Map workspaceVars = null;
    if (workspace != null) workspaceVars = workspace.getBinding().getVariables();
    Map globalVars = service.getBinding().getVariables();
    PreparedScriptProperties properties = new PreparedScriptProperties();
    properties.setCaller(caller);
    properties.setServer(plugin.getServer());
    properties.setWorkspace(workspace);

    if (tokens.isEmpty()) { // get current method or class
      for (MetaProperty metaProperty : callerScriptMetaClass.getProperties()) {
        String name = metaProperty.getName();
        if (name.contains(firstToken)) result.add(name);
      }
      for (String name : service.getImportTabCompleteClasses().keySet()) {
        if (name.contains(firstToken)) result.add(name);
      }
      for (MetaMethod metaMethod : callerScriptMetaClass.getMetaMethods()) {
        if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue;
        String name = metaMethod.getName();
        if (name.contains(firstToken)) {
          String methodEnd = "(";
          if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{";
          else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()";
          result.add(name + methodEnd);
        }
        int args = metaMethod.getParameterTypes().length;
        if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
            && name.length() > 3) {
          String propertyName = getPropertyName(name);
          if (propertyName != null && propertyName.contains(firstToken)) result.add(propertyName);
        }
      }
      for (MetaMethod metaMethod : workspaceMetaClass.getMetaMethods()) {
        if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue;
        String name = metaMethod.getName();
        if (name.contains(firstToken)) {
          String methodEnd = "(";
          if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{";
          else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()";
          result.add(name + methodEnd);
        }
      }
      for (Method method : CallerScript.class.getMethods()) {
        if (method.getDeclaringClass().equals(Object.class)) continue;
        String name = method.getName();
        if (name.contains(firstToken)) {
          String methodEnd = "(";
          Class<?>[] types = method.getParameterTypes();
          if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{";
          else if (types.length == 0) methodEnd = "()";
          result.add(name + methodEnd);
          int args = method.getParameterTypes().length;
          if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
              && name.length() > 3) {
            String propertyName = getPropertyName(name);
            if (propertyName != null && propertyName.contains(firstToken)) result.add(propertyName);
          }
        }
      }
      for (Method method : Workspace.class.getMethods()) {
        if (method.getDeclaringClass().equals(Object.class)) continue;
        String name = method.getName();
        if (name.contains(firstToken)) {
          String methodEnd = "(";
          Class<?>[] types = method.getParameterTypes();
          if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{";
          else if (types.length == 0) methodEnd = "()";
          result.add(name + methodEnd);
        }
      }
      if (workspaceVars != null)
        for (Object key : workspaceVars.keySet()) {
          String name = key.toString();
          if (name.contains(firstToken)) result.add(name);
        }
      if (globalVars != null)
        for (Object key : globalVars.keySet()) {
          String name = key.toString();
          if (name.contains(firstToken)) result.add(name);
        }
      for (GroovyObject modifier : CallerScript.getDynamicModifiers()) {
        Object[] params = {properties};
        try {
          Map<?, ?> map =
              (Map) modifier.getMetaClass().invokeMethod(modifier, "getPropertyMapFor", params);
          for (Object key : map.keySet()) {
            String name = key.toString();
            if (name.contains(firstToken)) result.add(name);
          }
        } catch (Exception ignored) {
        }
        try {
          Map<?, ?> map =
              (Map) modifier.getMetaClass().invokeMethod(modifier, "getMethodMapFor", params);
          for (Object key : map.keySet()) {
            String name = key.toString();
            if (name.contains(firstToken)) result.add(name + "(");
          }
        } catch (Exception ignored) {
        }
      }
      if (globalVars != null)
        for (Object key : globalVars.keySet()) {
          String name = key.toString();
          if (name.contains(firstToken)) result.add(name);
        }
      return new ArrayList<String>(result);
    }

    // get metaclass of first token
    MetaClass metaClass =
        getFirstTokenMeta(
            caller,
            firstToken,
            commandSender,
            service,
            callerScriptMetaClass,
            workspaceMetaClass,
            workspace,
            workspaceVars,
            globalVars,
            properties);
    boolean classHook =
        tokens.size() <= 1 && service.getImportTabCompleteClasses().containsKey(firstToken);

    if (metaClass == null) return null;
    metaClass = skipTokens(tokens, metaClass);
    if (metaClass == null) return null;

    // select property or method of last metaclass
    String token = tokens.pollFirst();
    Class theClass = metaClass.getTheClass();
    String inputPrefix = expression.substring(0, expression.lastIndexOf('.')) + ".";
    for (MetaProperty metaProperty : metaClass.getProperties()) {
      String name = metaProperty.getName();
      if (name.startsWith(token)) result.add(inputPrefix + name);
    }
    for (MetaMethod metaMethod : metaClass.getMetaMethods()) {
      if (metaMethod.getDeclaringClass().getTheClass().equals(Object.class)) continue;
      String name = metaMethod.getName();
      if (name.startsWith(token)) {
        String methodEnd = "(";
        if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{";
        else if (metaMethod.getNativeParameterTypes().length == 0) methodEnd = "()";
        result.add(inputPrefix + name + methodEnd);
      }
      int args = metaMethod.getParameterTypes().length;
      if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
          && name.length() > 3) {
        String propertyName = getPropertyName(name);
        if (propertyName != null && propertyName.startsWith(token))
          result.add(inputPrefix + propertyName);
      }
    }
    for (Method method : theClass.getMethods()) {
      if (method.getDeclaringClass().equals(Object.class)) continue;
      String name = method.getName();
      if (name.startsWith(token)) {
        String methodEnd = "(";
        Class<?>[] types = method.getParameterTypes();
        if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{";
        if (types.length == 0) methodEnd = "()";
        result.add(inputPrefix + name + methodEnd);
      }
      int args = method.getParameterTypes().length;
      if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
          && name.length() > 3) {
        String propertyName = getPropertyName(name);
        if (propertyName != null && propertyName.startsWith(token))
          result.add(inputPrefix + propertyName);
      }
    }
    if (Enum.class.isAssignableFrom(theClass)) {
      Enum[] enumValues = getEnumValues(theClass);
      if (enumValues != null)
        for (Enum anEnum : enumValues) {
          String name = anEnum.name();
          if (name.startsWith(token)) result.add(inputPrefix + name);
        }
    }
    if (classHook) {
      for (MetaProperty metaProperty : InvokerHelper.getMetaClass(Class.class).getProperties()) {
        String name = metaProperty.getName();
        if (name.startsWith(token)) result.add(inputPrefix + name);
      }
      for (Method method : Class.class.getMethods()) {
        if (method.getDeclaringClass().equals(Object.class)) continue;
        String name = method.getName();
        if (name.startsWith(token)) {
          String methodEnd = "(";
          Class<?>[] types = method.getParameterTypes();
          if (types.length == 1 && Closure.class.isAssignableFrom(types[0])) methodEnd = "{";
          if (types.length == 0) methodEnd = "()";
          result.add(inputPrefix + name + methodEnd);
        }
        int args = method.getParameterTypes().length;
        if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
            && name.length() > 3) {
          String propertyName = getPropertyName(name);
          if (propertyName != null && propertyName.startsWith(token))
            result.add(inputPrefix + propertyName);
        }
      }
    }
    return new ArrayList<String>(result);
  }
    public void addGetter(MetaBeanProperty property) throws Exception {
      MetaMethod getter = property.getGetter();

      // GENERATE private boolean <prop>Set;

      String flagName = String.format("%sSet", property.getName());
      visitor.visitField(
          Opcodes.ACC_PRIVATE, flagName, Type.BOOLEAN_TYPE.getDescriptor(), null, null);

      addConventionGetter(getter.getName(), flagName, property);

      String getterName = getter.getName();
      Class<?> returnType = getter.getReturnType();

      // If it's a boolean property, there can be get or is type variants.
      // If this class has both, decorate both.
      if (returnType.equals(Boolean.TYPE)) {
        boolean getterIsIsMethod = getterName.startsWith("is");
        String propertyNameComponent = getterName.substring(getterIsIsMethod ? 2 : 3);
        String alternativeGetterName =
            String.format("%s%s", getterIsIsMethod ? "get" : "is", propertyNameComponent);

        try {
          type.getMethod(alternativeGetterName);
          addConventionGetter(alternativeGetterName, flagName, property);
        } catch (NoSuchMethodException e) {
          // ignore, no method to override
        }
      }
    }
 private void visitType(java.lang.reflect.Type type, StringBuilder builder) {
   if (type instanceof Class) {
     Class<?> cl = (Class<?>) type;
     if (cl.isPrimitive()) {
       builder.append(Type.getType(cl).getDescriptor());
     } else {
       if (cl.isArray()) {
         builder.append(cl.getName().replace('.', '/'));
       } else {
         builder.append('L');
         builder.append(cl.getName().replace('.', '/'));
         builder.append(';');
       }
     }
   } else if (type instanceof ParameterizedType) {
     ParameterizedType parameterizedType = (ParameterizedType) type;
     visitNested(parameterizedType.getRawType(), builder);
     builder.append('<');
     for (java.lang.reflect.Type param : parameterizedType.getActualTypeArguments()) {
       visitType(param, builder);
     }
     builder.append(">;");
   } else if (type instanceof WildcardType) {
     WildcardType wildcardType = (WildcardType) type;
     if (wildcardType.getUpperBounds().length == 1
         && wildcardType.getUpperBounds()[0].equals(Object.class)) {
       if (wildcardType.getLowerBounds().length == 0) {
         builder.append('*');
         return;
       }
     } else {
       for (java.lang.reflect.Type upperType : wildcardType.getUpperBounds()) {
         builder.append('+');
         visitType(upperType, builder);
       }
     }
     for (java.lang.reflect.Type lowerType : wildcardType.getLowerBounds()) {
       builder.append('-');
       visitType(lowerType, builder);
     }
   } else if (type instanceof TypeVariable) {
     TypeVariable<?> typeVar = (TypeVariable) type;
     builder.append('T');
     builder.append(typeVar.getName());
     builder.append(';');
   } else if (type instanceof GenericArrayType) {
     GenericArrayType arrayType = (GenericArrayType) type;
     builder.append('[');
     visitType(arrayType.getGenericComponentType(), builder);
   } else {
     throw new IllegalArgumentException(
         String.format("Cannot generate signature for %s.", type));
   }
 }
 private void visitNested(java.lang.reflect.Type type, StringBuilder builder) {
   if (type instanceof Class) {
     Class<?> cl = (Class<?>) type;
     if (cl.isPrimitive()) {
       builder.append(Type.getType(cl).getDescriptor());
     } else {
       builder.append('L');
       builder.append(cl.getName().replace('.', '/'));
     }
   } else {
     visitType(type, builder);
   }
 }
 private MetaClass skipTokens(LinkedList<String> tokens, MetaClass metaClass) {
   while (tokens.size() > 1) {
     Class theClass = metaClass.getTheClass();
     String token = tokens.pollFirst();
     Class selectedClass = null;
     if (propertyPattern.matcher(token).matches()) {
       String getterName = "get" + StringGroovyMethods.capitalize((CharSequence) token);
       for (MetaMethod metaMethod : metaClass.getMetaMethods()) {
         if (metaMethod.getName().equals(getterName)) {
           selectedClass = metaMethod.getReturnType();
           break;
         }
       }
       if (selectedClass == null)
         for (Method method : theClass.getMethods()) {
           if (method.getParameterTypes().length != 0) continue;
           if (method.getName().equals(getterName)) {
             selectedClass = method.getReturnType();
             break;
           }
         }
       if (selectedClass == null) {
         MetaProperty metaProperty = metaClass.getMetaProperty(token);
         if (metaProperty == null) return null;
         selectedClass = metaProperty.getType();
       }
     } else if (methodPattern.matcher(token).matches()) {
       String curMethodName = token.substring(0, token.indexOf('('));
       for (MetaMethod metaMethod : metaClass.getMetaMethods()) {
         String name = metaMethod.getName();
         if (name.equals(curMethodName)) {
           selectedClass = metaMethod.getReturnType();
           break;
         }
       }
       if (selectedClass == null)
         for (Method method : theClass.getMethods()) {
           String name = method.getName();
           if (name.equals(curMethodName)) {
             selectedClass = method.getReturnType();
             break;
           }
         }
     }
     if (selectedClass == null) return null;
     metaClass = InvokerHelper.getMetaClass(selectedClass);
   }
   return metaClass;
 }
 /**
  * Looks for a class called 'groovy.runtime.metaclass.CustomMetaClassCreationHandle' and if it
  * exists uses it as the MetaClassCreationHandle otherwise uses the default
  *
  * @see groovy.lang.MetaClassRegistry.MetaClassCreationHandle
  */
 private void installMetaClassCreationHandle() {
   try {
     final Class customMetaClassHandle =
         Class.forName("groovy.runtime.metaclass.CustomMetaClassCreationHandle");
     final Constructor customMetaClassHandleConstructor =
         customMetaClassHandle.getConstructor(new Class[] {});
     this.metaClassCreationHandle =
         (MetaClassCreationHandle) customMetaClassHandleConstructor.newInstance();
   } catch (final ClassNotFoundException e) {
     this.metaClassCreationHandle = new MetaClassCreationHandle();
   } catch (final Exception e) {
     throw new GroovyRuntimeException(
         "Could not instantiate custom Metaclass creation handle: " + e, e);
   }
 }
    public Class<? extends T> generate() {
      visitor.visitEnd();

      byte[] bytecode = visitor.toByteArray();
      return DEFINE_CLASS_METHOD.invoke(
          type.getClassLoader(), typeName, bytecode, 0, bytecode.length);
    }
 private static Enum[] getEnumValues(Class<?> enumClass) {
   try {
     return (Enum[]) enumClass.getMethod("values").invoke(null);
   } catch (Exception ignored) {
     return null;
   }
 }
  @SuppressWarnings("rawtypes")
  protected void addGrailsBuildListener(Class listenerClass) {
    if (!GrailsBuildListener.class.isAssignableFrom(listenerClass)) {
      throw new RuntimeException(
          "Intended grails build listener class of "
              + listenerClass.getName()
              + " does not implement "
              + GrailsBuildListener.class.getName());
    }

    try {
      addGrailsBuildListener((GrailsBuildListener) listenerClass.newInstance());
    } catch (Exception e) {
      throw new RuntimeException("Could not instantiate " + listenerClass.getName(), e);
    }
  }
    private ClassBuilderImpl(Class<T> type) {
      this.type = type;

      visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      typeName = type.getName() + "_Decorated";
      generatedType = Type.getType("L" + typeName.replaceAll("\\.", "/") + ";");
      superclassType = Type.getType(type);
    }
  public void loadEventsScript(File eventScript) {
    if (eventScript == null) {
      return;
    }

    GrailsConsole console = GrailsConsole.getInstance();
    try {
      Class<?> scriptClass = classLoader.parseClass(eventScript);
      if (scriptClass == null) {
        console.error("Could not load event script (script may be empty): " + eventScript);
        return;
      }

      Script script = (Script) scriptClass.newInstance();
      script.setBinding(
          new Binding(binding.getVariables()) {
            @SuppressWarnings("rawtypes")
            @Override
            public void setVariable(String var, Object o) {
              final Matcher matcher = EVENT_NAME_PATTERN.matcher(var);
              if (matcher.matches() && (o instanceof Closure)) {
                String eventName = matcher.group(1);
                List<Closure> hooks = globalEventHooks.get(eventName);
                if (hooks == null) {
                  hooks = new ArrayList<Closure>();
                  globalEventHooks.put(eventName, hooks);
                }
                hooks.add((Closure<?>) o);
              }
              super.setVariable(var, o);
            }
          });
      script.run();
    } catch (Throwable e) {
      StackTraceUtils.deepSanitize(e);
      console.error(
          "Error loading event script from file [" + eventScript + "] " + e.getMessage(), e);
    }
  }
 private void createMetaMethodFromClass(Map<CachedClass, List<MetaMethod>> map, Class aClass) {
   try {
     MetaMethod method = (MetaMethod) aClass.newInstance();
     final CachedClass declClass = method.getDeclaringClass();
     List<MetaMethod> arr = map.get(declClass);
     if (arr == null) {
       arr = new ArrayList<MetaMethod>(4);
       map.put(declClass, arr);
     }
     arr.add(method);
     instanceMethods.add(method);
   } catch (InstantiationException e) {
     /* ignore */
   } catch (IllegalAccessException e) {
     /* ignore */
   }
 }
  public void getHelp(Caller caller, Workspace workspace, LinkedList<String> tokens) {

    WorkspaceService service = plugin.getWorkspaceService();
    String source = service.getWorkspaceName(caller.getSender());
    String firstToken = tokens.pollFirst();
    if (firstToken == null) firstToken = "";
    MetaClass callerScriptMetaClass = InvokerHelper.getMetaClass(CallerScript.class);
    MetaClass workspaceMetaClass = InvokerHelper.getMetaClass(Workspace.class);
    Map workspaceVars = null;
    if (workspace != null) workspaceVars = workspace.getBinding().getVariables();
    Map globalVars = service.getBinding().getVariables();
    PreparedScriptProperties properties = new PreparedScriptProperties();
    properties.setCaller(caller);
    properties.setServer(plugin.getServer());
    properties.setWorkspace(workspace);

    if (tokens.isEmpty()) { // get current method or class
      if (firstToken.equals("_")) {
        Object result = caller.getLastResult();
        String type = "null";
        if (result != null) type = result.getClass().getName();
        caller.sendPrintMessage("Last result: " + AQUA + type + RESET, source);
        return;
      }
      MetaProperty prop = callerScriptMetaClass.getMetaProperty(firstToken);
      if (prop != null) {
        caller.sendPrintMessage(
            String.format(
                "Script property %s: %s",
                YELLOW + prop.getName() + RESET, AQUA + prop.getType().getName() + RESET),
            source);
        return;
      }
      Class compClass = service.getImportTabCompleteClasses().get(firstToken);
      if (compClass != null) {
        String type = "Class";
        if (compClass.isInterface()) type = "Interface";
        else if (compClass.isEnum()) type = "Enum class";
        StringBuilder buf = new StringBuilder();
        Class superClass = compClass.getSuperclass();
        buf.append(type).append(" ").append(YELLOW).append(compClass.getName()).append(RESET);
        if (superClass != null) {
          buf.append(" extends ").append(AQUA).append(superClass.getName()).append(RESET);
        }
        caller.sendPrintMessage(buf, source);
        return;
      }
      for (MetaMethod metaMethod : callerScriptMetaClass.getMetaMethods()) {
        String name = metaMethod.getName();
        String methodEnd = "(";
        if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{";
        else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Script meta method ")
              .append(YELLOW)
              .append(metaMethod.getName())
              .append(RESET);
          buf.append(" returns ").append(AQUA).append(metaMethod.getReturnType().getName());
          buf.append(RESET).append('\n');
          Class[] types = metaMethod.getNativeParameterTypes();
          buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
          for (Class type : types)
            buf.append(AQUA).append(type.getName()).append('\n').append(RESET);
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
        int args = metaMethod.getParameterTypes().length;
        if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
            && name.length() > 3) {
          String propertyName = getPropertyName(name);
          if (propertyName != null && propertyName.equals(firstToken)) {
            caller.sendPrintMessage(
                String.format(
                    "Script meta getter %s returns %s",
                    YELLOW + name + "()" + RESET,
                    AQUA + metaMethod.getReturnType().getName() + RESET),
                source);
          }
        }
      }
      for (MetaMethod metaMethod : workspaceMetaClass.getMetaMethods()) {
        String name = metaMethod.getName();
        String methodEnd = "(";
        if (metaMethod.isValidMethod(new Class[] {Closure.class})) methodEnd = "{";
        else if (metaMethod.getParameterTypes().length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Workspace meta method ")
              .append(YELLOW)
              .append(metaMethod.getName())
              .append(RESET);
          buf.append(" returns ").append(AQUA).append(metaMethod.getReturnType().getName());
          buf.append(RESET).append('\n');
          Class[] types = metaMethod.getNativeParameterTypes();
          buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
          for (Class type : types)
            buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
      }
      for (Method method : CallerScript.class.getMethods()) {
        String name = method.getName();
        String methodEnd = "(";
        Class<?>[] params = method.getParameterTypes();
        if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
        else if (params.length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Script method ").append(YELLOW).append(method.getName()).append(RESET);
          buf.append(" returns ").append(AQUA).append(method.getReturnType().getName());
          buf.append(RESET).append('\n');
          buf.append("arguments: ").append(YELLOW).append(params.length).append(RESET).append('\n');
          for (Class<?> type : params)
            buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
        int args = params.length;
        if ((name.startsWith("get") && args == 0 || name.startsWith("set") && args == 1)
            && name.length() > 3) {
          String propertyName = getPropertyName(name);
          if (propertyName != null && propertyName.equals(firstToken)) {
            caller.sendPrintMessage(
                String.format(
                    "Script getter %s returns %s",
                    YELLOW + name + "()" + RESET, AQUA + method.getReturnType().getName() + RESET),
                source);
          }
        }
      }
      for (Method method : Workspace.class.getMethods()) {
        String name = method.getName();
        String methodEnd = "(";
        Class<?>[] params = method.getParameterTypes();
        if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
        else if (params.length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Workspace method ").append(YELLOW).append(method.getName()).append(RESET);
          buf.append(" returns ").append(AQUA).append(method.getReturnType().getName());
          buf.append(RESET).append('\n');
          buf.append("arguments: ").append(YELLOW).append(params.length).append(RESET).append('\n');
          for (Class<?> type : params)
            buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
      }
      if (workspaceVars != null) {
        Object result = workspaceVars.get(firstToken);
        if (result != null || workspaceVars.containsKey(firstToken)) {
          caller.sendPrintMessage(
              String.format(
                  "Workspace variable %s: %s",
                  YELLOW + firstToken + RESET,
                  AQUA + (result == null ? "null" : result.getClass().getName()) + RESET),
              source);
          return;
        }
      }
      if (globalVars != null) {
        Object result = globalVars.get(firstToken);
        if (result != null || globalVars.containsKey(firstToken)) {
          caller.sendPrintMessage(
              String.format(
                  "Workspace variable %s: %s",
                  YELLOW + firstToken + RESET,
                  AQUA + (result == null ? "null" : result.getClass().getName()) + RESET),
              source);
          return;
        }
      }
      for (GroovyObject modifier : CallerScript.getDynamicModifiers()) {
        Object[] params = {properties};
        try {
          Map<?, ?> map =
              (Map) modifier.getMetaClass().invokeMethod(modifier, "getPropertyMapFor", params);
          Object result = map.get(firstToken);
          if (result != null || map.containsKey(firstToken)) {
            Class resultClass = result instanceof Class ? (Class) result : null;
            caller.sendPrintMessage(
                String.format(
                    "Dynamic variable %s: %s",
                    YELLOW + firstToken + RESET,
                    AQUA + (resultClass == null ? "unknown type" : resultClass.getName()) + RESET),
                source);
          }
        } catch (Exception ignored) {
        }
        try {
          Map<?, ?> map =
              (Map) modifier.getMetaClass().invokeMethod(modifier, "getMethodMapFor", params);
          String funToken = firstToken;
          if (funToken.endsWith("(")) funToken = firstToken.substring(0, funToken.length() - 1);
          Object result = map.get(funToken);
          if (result != null || map.containsKey(funToken)) {
            Class resultClass = result instanceof Class ? (Class) result : null;
            caller.sendPrintMessage(
                String.format(
                    "Dynamic function %s: %s",
                    YELLOW + firstToken + RESET,
                    AQUA + (resultClass == null ? "unknown type" : resultClass.getName()) + RESET),
                source);
          }
        } catch (Exception ignored) {
        }
      }
      return;
    }

    MetaClass metaClass =
        getFirstTokenMeta(
            caller,
            firstToken,
            caller.getSender(),
            service,
            callerScriptMetaClass,
            workspaceMetaClass,
            workspace,
            workspaceVars,
            globalVars,
            properties);
    boolean classHook =
        tokens.size() <= 1 && service.getImportTabCompleteClasses().containsKey(firstToken);

    metaClass = skipTokens(tokens, metaClass);
    if (metaClass == null) return;

    // select property or method of last metaclass
    String token = tokens.pollFirst();
    Class theClass = metaClass.getTheClass();
    MetaProperty metaProperty = metaClass.getMetaProperty(token);
    if (metaProperty != null) {
      caller.sendPrintMessage(
          String.format(
              "Meta property %s: %s",
              YELLOW + token + RESET, AQUA + metaProperty.getType().getName() + RESET),
          source);
    }
    for (MetaMethod metaMethod : metaClass.getMetaMethods()) {
      String name = metaMethod.getName();
      String methodEnd = "(";
      Class<?>[] params = metaMethod.getNativeParameterTypes();
      if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
      else if (params.length == 0) methodEnd = "()";
      if (token.equals(name) || token.equals(name + methodEnd)) {
        StringBuilder buf = new StringBuilder();
        buf.append("Meta method ").append(YELLOW).append(metaMethod.getName()).append(RESET);
        buf.append(" returns ").append(AQUA).append(metaMethod.getReturnType().getName());
        buf.append(RESET).append('\n');
        Class[] types = metaMethod.getNativeParameterTypes();
        buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
        for (Class type : types) buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
        buf.deleteCharAt(buf.length() - 1);
        caller.sendPrintMessage(buf, source);
      }
      int args = params.length;
      if (name.startsWith("get") && args == 0 && name.length() > 3) {
        String propertyName = getPropertyName(name);
        if (propertyName != null && propertyName.equals(token)) {
          caller.sendPrintMessage(
              String.format(
                  "Meta getter %s returns %s",
                  YELLOW + name + "()" + RESET,
                  AQUA + metaMethod.getReturnType().getName() + RESET),
              source);
        }
      }
    }
    for (Method method : theClass.getMethods()) {
      String name = method.getName();
      String methodEnd = "(";
      Class<?>[] params = method.getParameterTypes();
      if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
      else if (params.length == 0) methodEnd = "()";
      if (token.equals(name) || token.equals(name + methodEnd)) {
        StringBuilder buf = new StringBuilder();
        buf.append("Method ").append(YELLOW).append(method.getName()).append(RESET);
        buf.append(" returns ").append(AQUA).append(method.getReturnType().getName());
        buf.append(RESET).append('\n');
        Class[] types = method.getParameterTypes();
        buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
        for (Class type : types) buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
        buf.deleteCharAt(buf.length() - 1);
        caller.sendPrintMessage(buf, source);
      }
      int args = params.length;
      if (name.startsWith("get") && args == 0 && name.length() > 3) {
        String propertyName = getPropertyName(name);
        if (propertyName != null && propertyName.equals(token)) {
          caller.sendPrintMessage(
              String.format(
                  "Getter %s returns %s",
                  YELLOW + name + "()" + RESET, AQUA + method.getReturnType().getName() + RESET),
              source);
        }
      }
    }
    if (Enum.class.isAssignableFrom(theClass)) {
      Enum[] enumValues = getEnumValues(theClass);
      if (enumValues != null)
        for (Enum anEnum : enumValues) {
          String name = anEnum.name();
          if (name.equals(token)) {
            caller.sendPrintMessage(
                String.format(
                    "Enum value %s: %s", YELLOW + name + RESET, AQUA + theClass.getName() + RESET),
                source);
          }
        }
    }
    if (classHook) {
      MetaProperty property = InvokerHelper.getMetaClass(Class.class).getMetaProperty(token);
      if (property != null) {
        caller.sendPrintMessage(
            String.format(
                "Meta property %s: %s",
                YELLOW + token + RESET, AQUA + property.getType().getName() + RESET),
            source);
      }
      for (MetaMethod metaMethod : InvokerHelper.getMetaClass(Class.class).getMetaMethods()) {
        String name = metaMethod.getName();
        String methodEnd = "(";
        Class<?>[] params = metaMethod.getNativeParameterTypes();
        if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
        else if (params.length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Method ").append(YELLOW).append(metaMethod.getName()).append(RESET);
          buf.append(" returns ").append(AQUA).append(metaMethod.getReturnType().getName());
          buf.append(RESET).append('\n');
          Class[] types = metaMethod.getNativeParameterTypes();
          buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
          for (Class type : types)
            buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
      }
      for (Method method : Class.class.getMethods()) {
        String name = method.getName();
        String methodEnd = "(";
        Class<?>[] params = method.getParameterTypes();
        if (params.length == 1 && Closure.class.isAssignableFrom(params[0])) methodEnd = "{";
        else if (params.length == 0) methodEnd = "()";
        if (firstToken.equals(name) || firstToken.equals(name + methodEnd)) {
          StringBuilder buf = new StringBuilder();
          buf.append("Method ").append(YELLOW).append(method.getName()).append(RESET);
          buf.append(" returns ").append(AQUA).append(method.getReturnType().getName());
          buf.append(RESET).append('\n');
          Class[] types = method.getParameterTypes();
          buf.append("arguments: ").append(YELLOW).append(types.length).append(RESET).append('\n');
          for (Class type : types)
            buf.append(AQUA).append(type.getName()).append(RESET).append('\n');
          buf.deleteCharAt(buf.length() - 1);
          caller.sendPrintMessage(buf, source);
        }
      }
    }
  }
示例#14
0
  public <T> Class<? extends T> generate(Class<T> type) {
    Map<Class, Class> cache = GENERATED_CLASSES.get(getClass());
    if (cache == null) {
      cache = new HashMap<Class, Class>();
      GENERATED_CLASSES.put(getClass(), cache);
    }
    Class generatedClass = cache.get(type);
    if (generatedClass != null) {
      return generatedClass;
    }

    if (Modifier.isPrivate(type.getModifiers())) {
      throw new GradleException(
          String.format(
              "Cannot create a proxy class for private class '%s'.", type.getSimpleName()));
    }
    if (Modifier.isAbstract(type.getModifiers())) {
      throw new GradleException(
          String.format(
              "Cannot create a proxy class for abstract class '%s'.", type.getSimpleName()));
    }

    Class<? extends T> subclass;
    try {
      ClassBuilder<T> builder = start(type);

      boolean isConventionAware = type.getAnnotation(NoConventionMapping.class) == null;
      boolean isDynamicAware = type.getAnnotation(NoDynamicObject.class) == null;

      builder.startClass(isConventionAware, isDynamicAware);

      if (isDynamicAware && !DynamicObjectAware.class.isAssignableFrom(type)) {
        builder.mixInDynamicAware();
      }
      if (isDynamicAware && !GroovyObject.class.isAssignableFrom(type)) {
        builder.mixInGroovyObject();
      }
      if (isDynamicAware) {
        builder.addDynamicMethods();
      }
      if (isConventionAware && !IConventionAware.class.isAssignableFrom(type)) {
        builder.mixInConventionAware();
      }

      Class noMappingClass = Object.class;
      for (Class<?> c = type; c != null && noMappingClass == Object.class; c = c.getSuperclass()) {
        if (c.getAnnotation(NoConventionMapping.class) != null) {
          noMappingClass = c;
        }
      }

      Collection<String> skipProperties =
          Arrays.asList("metaClass", "conventionMapping", "convention", "asDynamicObject");

      MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(type);
      for (MetaProperty property : metaClass.getProperties()) {
        if (skipProperties.contains(property.getName())) {
          continue;
        }
        if (property instanceof MetaBeanProperty) {
          MetaBeanProperty metaBeanProperty = (MetaBeanProperty) property;
          MetaMethod getter = metaBeanProperty.getGetter();
          if (getter == null) {
            continue;
          }
          if (Modifier.isFinal(getter.getModifiers())
              || Modifier.isPrivate(getter.getModifiers())) {
            continue;
          }
          if (getter.getReturnType().isPrimitive()) {
            continue;
          }
          Class declaringClass = getter.getDeclaringClass().getTheClass();
          if (declaringClass.isAssignableFrom(noMappingClass)) {
            continue;
          }
          builder.addGetter(metaBeanProperty);

          MetaMethod setter = metaBeanProperty.getSetter();
          if (setter == null) {
            continue;
          }
          if (Modifier.isFinal(setter.getModifiers())
              || Modifier.isPrivate(setter.getModifiers())) {
            continue;
          }

          builder.addSetter(metaBeanProperty);
        }
      }

      for (Constructor<?> constructor : type.getConstructors()) {
        if (Modifier.isPublic(constructor.getModifiers())) {
          builder.addConstructor(constructor);
        }
      }

      subclass = builder.generate();
    } catch (Throwable e) {
      throw new GradleException(
          String.format("Could not generate a proxy class for class %s.", type.getName()), e);
    }

    cache.put(type, subclass);
    return subclass;
  }
    /**
     * Turn the template into a writable Closure When executed the closure evaluates all the code
     * embedded in the template and then writes a GString containing the fixed and variable items to
     * the writer passed as a parameter
     *
     * <p>For example:
     *
     * <p>'<%= "test" %> of expr and <% test = 1 %>${test} script.'
     *
     * <p>would compile into:
     *
     * <p>{ out -> out << "${"test"} of expr and "; test = 1 ; out << "${test}
     * script."}.asWritable()
     *
     * @param reader
     * @param parentLoader
     * @throws CompilationFailedException
     * @throws ClassNotFoundException
     * @throws IOException
     */
    GStringTemplate(final Reader reader, final ClassLoader parentLoader)
        throws CompilationFailedException, ClassNotFoundException, IOException {
      final StringBuilder templateExpressions =
          new StringBuilder(
              "package groovy.tmp.templates\n def getTemplate() { return { out -> out << \"\"\"");
      boolean writingString = true;

      while (true) {
        int c = reader.read();
        if (c == -1) break;
        if (c == '<') {
          c = reader.read();
          if (c == '%') {
            c = reader.read();
            if (c == '=') {
              parseExpression(reader, writingString, templateExpressions);
              writingString = true;
              continue;
            } else {
              parseSection(c, reader, writingString, templateExpressions);
              writingString = false;
              continue;
            }
          } else {
            appendCharacter('<', templateExpressions, writingString);
            writingString = true;
          }
        } else if (c == '"') {
          appendCharacter('\\', templateExpressions, writingString);
          writingString = true;
        } else if (c == '$') {
          appendCharacter('$', templateExpressions, writingString);
          writingString = true;
          c = reader.read();
          if (c == '{') {
            appendCharacter('{', templateExpressions, writingString);
            writingString = true;
            parseGSstring(reader, writingString, templateExpressions);
            writingString = true;
            continue;
          }
        }
        appendCharacter((char) c, templateExpressions, writingString);
        writingString = true;
      }

      if (writingString) {
        templateExpressions.append("\"\"\"");
      }

      templateExpressions.append("}}");

      final GroovyClassLoader loader =
          parentLoader instanceof GroovyClassLoader
              ? (GroovyClassLoader) parentLoader
              : ((GroovyClassLoader)
                  AccessController.doPrivileged(
                      new PrivilegedAction() {
                        public Object run() {
                          return new GroovyClassLoader(parentLoader);
                        }
                      }));
      final Class groovyClass;
      try {
        groovyClass =
            loader.parseClass(
                new GroovyCodeSource(
                    templateExpressions.toString(),
                    "GStringTemplateScript" + counter.incrementAndGet() + ".groovy",
                    "x"));
      } catch (Exception e) {
        throw new GroovyRuntimeException(
            "Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): "
                + e.getMessage());
      }

      try {
        final GroovyObject script = (GroovyObject) groovyClass.newInstance();

        this.template = (Closure) script.invokeMethod("getTemplate", null);
        // GROOVY-6521: must set strategy to DELEGATE_FIRST, otherwise writing
        // books = 'foo' in a template would store 'books' in the binding of the template script
        // itself ("script")
        // instead of storing it in the delegate, which is a Binding too
        this.template.setResolveStrategy(Closure.DELEGATE_FIRST);
      } catch (InstantiationException e) {
        throw new ClassNotFoundException(e.getMessage());
      } catch (IllegalAccessException e) {
        throw new ClassNotFoundException(e.getMessage());
      }
    }