예제 #1
1
  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);
  }
예제 #2
0
    public void addSetMethod(MetaBeanProperty property) throws Exception {
      MetaMethod setter = property.getSetter();
      Type paramType = Type.getType(setter.getParameterTypes()[0].getTheClass());
      Type returnType = Type.getType(setter.getReturnType());
      String setterDescriptor = Type.getMethodDescriptor(returnType, new Type[] {paramType});

      // GENERATE public void <propName>(<type> v) { <setter>(v) }
      String setMethodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {paramType});
      MethodVisitor methodVisitor =
          visitor.visitMethod(
              Opcodes.ACC_PUBLIC, property.getName(), setMethodDescriptor, null, new String[0]);
      methodVisitor.visitCode();

      // GENERATE <setter>(v)

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitVarInsn(paramType.getOpcode(Opcodes.ILOAD), 1);

      methodVisitor.visitMethodInsn(
          Opcodes.INVOKEVIRTUAL,
          generatedType.getInternalName(),
          setter.getName(),
          setterDescriptor);

      // END

      methodVisitor.visitInsn(Opcodes.RETURN);
      methodVisitor.visitMaxs(0, 0);
      methodVisitor.visitEnd();
    }
예제 #3
0
    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
        }
      }
    }
예제 #4
0
 /**
  * Get the property of the given object.
  *
  * @param object which to be got
  * @return the property of the given object
  * @throws RuntimeException if the property could not be evaluated
  */
 public Object getProperty(Object object) {
   MetaMethod getter = getGetter();
   if (getter == null) {
     if (field != null) return field.getProperty(object);
     // TODO: create a WriteOnlyException class?
     throw new GroovyRuntimeException("Cannot read write-only property: " + name);
   }
   return getter.invoke(object, MetaClassHelper.EMPTY_ARRAY);
 }
예제 #5
0
 /**
  * Set the property on the given object to the new value.
  *
  * @param object on which to set the property
  * @param newValue the new value of the property
  * @throws RuntimeException if the property could not be set
  */
 public void setProperty(Object object, Object newValue) {
   MetaMethod setter = getSetter();
   if (setter == null) {
     if (field != null && !Modifier.isFinal(field.getModifiers())) {
       field.setProperty(object, newValue);
       return;
     }
     throw new GroovyRuntimeException("Cannot set read-only property: " + name);
   }
   newValue = DefaultTypeTransformation.castToType(newValue, getType());
   setter.invoke(object, new Object[] {newValue});
 }
 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 */
   }
 }
예제 #7
0
    public void addSetter(MetaBeanProperty property) throws Exception {
      MetaMethod setter = property.getSetter();

      // GENERATE public <return-type> <setter>(<type> v) { <return-type> v = super.<setter>(v);
      // <prop>Set = true; return v; }

      Type paramType = Type.getType(setter.getParameterTypes()[0].getTheClass());
      Type returnType = Type.getType(setter.getReturnType());
      String setterDescriptor = Type.getMethodDescriptor(returnType, new Type[] {paramType});
      MethodVisitor methodVisitor =
          visitor.visitMethod(
              Opcodes.ACC_PUBLIC, setter.getName(), setterDescriptor, null, new String[0]);
      methodVisitor.visitCode();

      // GENERATE super.<setter>(v)

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitVarInsn(paramType.getOpcode(Opcodes.ILOAD), 1);

      methodVisitor.visitMethodInsn(
          Opcodes.INVOKESPECIAL,
          superclassType.getInternalName(),
          setter.getName(),
          setterDescriptor);

      // END

      // GENERATE <prop>Set = true

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitLdcInsn(true);
      methodVisitor.visitFieldInsn(
          Opcodes.PUTFIELD,
          generatedType.getInternalName(),
          String.format("%sSet", property.getName()),
          Type.BOOLEAN_TYPE.getDescriptor());

      // END

      methodVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
      methodVisitor.visitMaxs(0, 0);
      methodVisitor.visitEnd();
    }
예제 #8
0
 /**
  * Gets the visibility modifiers for the property as defined by the getter and setter methods.
  *
  * @return the visibility modifier of the getter, the setter, or both depending on which exist
  */
 public int getModifiers() {
   MetaMethod getter = getGetter();
   MetaMethod setter = getSetter();
   if (setter != null && getter == null) return setter.getModifiers();
   if (getter != null && setter == null) return getter.getModifiers();
   int modifiers = getter.getModifiers() | setter.getModifiers();
   int visibility = 0;
   if (Modifier.isPublic(modifiers)) visibility = Modifier.PUBLIC;
   if (Modifier.isProtected(modifiers)) visibility = Modifier.PROTECTED;
   if (Modifier.isPrivate(modifiers)) visibility = Modifier.PRIVATE;
   int states = getter.getModifiers() & setter.getModifiers();
   states &= ~(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE);
   states |= visibility;
   return states;
 }
예제 #9
0
    public void addActionMethod(MetaMethod method) throws Exception {
      Type actionImplType = Type.getType(ClosureBackedAction.class);
      Type closureType = Type.getType(Closure.class);

      String methodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {closureType});

      // GENERATE public void <method>(Closure v) { <method>(new ClosureBackedAction(v)); }
      MethodVisitor methodVisitor =
          visitor.visitMethod(
              Opcodes.ACC_PUBLIC, method.getName(), methodDescriptor, null, new String[0]);
      methodVisitor.visitCode();

      // GENERATE <method>(new ClosureBackedAction(v));
      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);

      // GENERATE new ClosureBackedAction(v);
      methodVisitor.visitTypeInsn(Opcodes.NEW, actionImplType.getInternalName());
      methodVisitor.visitInsn(Opcodes.DUP);
      methodVisitor.visitVarInsn(Opcodes.ALOAD, 1);
      String constuctorDescriptor =
          Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {closureType});
      methodVisitor.visitMethodInsn(
          Opcodes.INVOKESPECIAL, actionImplType.getInternalName(), "<init>", constuctorDescriptor);

      methodDescriptor =
          Type.getMethodDescriptor(
              Type.getType(method.getReturnType()),
              new Type[] {Type.getType(method.getParameterTypes()[0].getTheClass())});
      methodVisitor.visitMethodInsn(
          Opcodes.INVOKEVIRTUAL,
          generatedType.getInternalName(),
          method.getName(),
          methodDescriptor);

      methodVisitor.visitInsn(Opcodes.RETURN);
      methodVisitor.visitMaxs(0, 0);
      methodVisitor.visitEnd();
    }
예제 #10
0
 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;
 }
예제 #11
0
    private void addConventionGetter(String getterName, String flagName, MetaBeanProperty property)
        throws Exception {
      // GENERATE public <type> <getter>() { return
      // (<type>)getConventionMapping().getConventionValue(super.<getter>(), '<prop>', <prop>Set); }
      MetaMethod getter = property.getGetter();

      Type returnType = Type.getType(getter.getReturnType());
      String methodDescriptor = Type.getMethodDescriptor(returnType, new Type[0]);
      MethodVisitor methodVisitor =
          visitor.visitMethod(
              Opcodes.ACC_PUBLIC, getterName, methodDescriptor, null, new String[0]);
      methodVisitor.visitCode();

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitMethodInsn(
          Opcodes.INVOKEINTERFACE,
          conventionAwareType.getInternalName(),
          "getConventionMapping",
          Type.getMethodDescriptor(conventionMappingType, new Type[0]));

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitMethodInsn(
          Opcodes.INVOKESPECIAL, superclassType.getInternalName(), getterName, methodDescriptor);

      Type boxedType = null;
      if (getter.getReturnType().isPrimitive()) {
        // Box value
        boxedType =
            Type.getType(JavaReflectionUtil.getWrapperTypeForPrimitiveType(getter.getReturnType()));
        String valueOfMethodDescriptor =
            Type.getMethodDescriptor(boxedType, new Type[] {returnType});
        methodVisitor.visitMethodInsn(
            Opcodes.INVOKESTATIC, boxedType.getInternalName(), "valueOf", valueOfMethodDescriptor);
      }

      methodVisitor.visitLdcInsn(property.getName());

      methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
      methodVisitor.visitFieldInsn(
          Opcodes.GETFIELD,
          generatedType.getInternalName(),
          flagName,
          Type.BOOLEAN_TYPE.getDescriptor());

      String getConventionValueDesc =
          Type.getMethodDescriptor(
              ConventionMapping.class.getMethod(
                  "getConventionValue", Object.class, String.class, Boolean.TYPE));
      methodVisitor.visitMethodInsn(
          Opcodes.INVOKEINTERFACE,
          conventionMappingType.getInternalName(),
          "getConventionValue",
          getConventionValueDesc);

      if (getter.getReturnType().isPrimitive()) {
        // Unbox value
        methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, boxedType.getInternalName());
        String valueMethodDescriptor = Type.getMethodDescriptor(returnType, new Type[0]);
        methodVisitor.visitMethodInsn(
            Opcodes.INVOKEVIRTUAL,
            boxedType.getInternalName(),
            getter.getReturnType().getName() + "Value",
            valueMethodDescriptor);
      } else {
        // Cast to return type
        methodVisitor.visitTypeInsn(
            Opcodes.CHECKCAST,
            getter.getReturnType().isArray()
                ? "[" + returnType.getElementType().getDescriptor()
                : returnType.getInternalName());
      }

      methodVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
      methodVisitor.visitMaxs(0, 0);
      methodVisitor.visitEnd();
    }
예제 #12
0
  private MetaClass getFirstTokenMeta(
      Caller caller,
      String firstToken,
      CommandSender commandSender,
      WorkspaceService service,
      MetaClass callerScriptMetaClass,
      MetaClass workspaceMetaClass,
      Workspace workspace,
      Map workspaceVars,
      Map globalVars,
      PreparedScriptProperties properties) {

    if (firstToken.isEmpty() || propertyPattern.matcher(firstToken).matches()) {
      if (firstToken.equals("me")) return InvokerHelper.getMetaClass(commandSender.getClass());
      if (firstToken.equals("this")) return InvokerHelper.getMetaClass(CallerScript.class);
      if (firstToken.equals("_")) {
        Object result = caller.getLastResult();
        if (result == null) return null;
        return InvokerHelper.getMetaClass(result.getClass());
      }
      Class aClass = service.getImportTabCompleteClasses().get(firstToken);
      if (aClass != null) return InvokerHelper.getMetaClass(aClass);
      MetaProperty property = callerScriptMetaClass.getMetaProperty(firstToken);
      if (property != null) return InvokerHelper.getMetaClass(property.getType());
      if (workspaceVars != null)
        for (Object key : workspaceVars.keySet()) {
          String name = key.toString();
          if (name.contains(firstToken)) {
            Object val = workspaceVars.get(key);
            return InvokerHelper.getMetaClass(val.getClass());
          }
        }
      if (globalVars != null)
        for (Object key : globalVars.keySet()) {
          String name = key.toString();
          if (name.contains(firstToken)) {
            Object val = globalVars.get(key);
            return InvokerHelper.getMetaClass(val.getClass());
          }
        }
      if (workspace != null) {
        for (GroovyObject modifier : CallerScript.getDynamicModifiers()) {
          Object[] params = {properties};
          try {
            Map<?, ?> map =
                (Map) modifier.getMetaClass().invokeMethod(modifier, "getPropertyMapFor", params);
            Object value = map.get(firstToken);
            if (!(value instanceof Class)) return null;
            return InvokerHelper.getMetaClass((Class) value);
          } catch (Exception ignored) {
          }
        }
      }
    } else if (methodPattern.matcher(firstToken).matches()) {
      String curMethodName = firstToken.substring(0, firstToken.indexOf('('));
      for (MetaMethod metaMethod : callerScriptMetaClass.getMetaMethods()) {
        String name = metaMethod.getName();
        if (name.equals(curMethodName)) {
          return InvokerHelper.getMetaClass(metaMethod.getReturnType());
        }
      }
      for (MetaMethod metaMethod : workspaceMetaClass.getMetaMethods()) {
        String name = metaMethod.getName();
        if (name.equals(curMethodName)) {
          return InvokerHelper.getMetaClass(metaMethod.getReturnType());
        }
      }
      for (GroovyObject modifier : CallerScript.getDynamicModifiers()) {
        Object[] params = {properties};
        try {
          Map<?, ?> map =
              (Map) modifier.getMetaClass().invokeMethod(modifier, "getMethodMapFor", params);
          Object value = map.get(curMethodName);
          if (!(value instanceof Class)) return null;
          return InvokerHelper.getMetaClass(value);
        } catch (Exception ignored) {
        }
      }
    } else if (firstToken.endsWith("\'") || firstToken.endsWith("\"")) {
      return InvokerHelper.getMetaClass(String.class);
    }
    return null;
  }
예제 #13
0
  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;
  }
  private void registerMethods(
      final Class theClass,
      final boolean useMethodWrapper,
      final boolean useInstanceMethods,
      Map<CachedClass, List<MetaMethod>> map) {
    if (useMethodWrapper) {
      // Here we instantiate objects representing MetaMethods for DGM methods.
      // Calls for such meta methods done without reflection, so more effectively.

      try {
        List<GeneratedMetaMethod.DgmMethodRecord> records =
            GeneratedMetaMethod.DgmMethodRecord.loadDgmInfo();

        for (GeneratedMetaMethod.DgmMethodRecord record : records) {
          Class[] newParams = new Class[record.parameters.length - 1];
          System.arraycopy(record.parameters, 1, newParams, 0, record.parameters.length - 1);

          MetaMethod method =
              new GeneratedMetaMethod.Proxy(
                  record.className,
                  record.methodName,
                  ReflectionCache.getCachedClass(record.parameters[0]),
                  record.returnType,
                  newParams);
          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 (Throwable e) {
        e.printStackTrace();
        // we print the error, but we don't stop with an exception here
        // since it is more comfortable this way for development
      }
    } else {
      CachedMethod[] methods = ReflectionCache.getCachedClass(theClass).getMethods();

      for (CachedMethod method : methods) {
        final int mod = method.getModifiers();
        if (Modifier.isStatic(mod)
            && Modifier.isPublic(mod)
            && method.getCachedMethod().getAnnotation(Deprecated.class) == null) {
          CachedClass[] paramTypes = method.getParameterTypes();
          if (paramTypes.length > 0) {
            List<MetaMethod> arr = map.get(paramTypes[0]);
            if (arr == null) {
              arr = new ArrayList<MetaMethod>(4);
              map.put(paramTypes[0], arr);
            }
            if (useInstanceMethods) {
              final NewInstanceMetaMethod metaMethod = new NewInstanceMetaMethod(method);
              arr.add(metaMethod);
              instanceMethods.add(metaMethod);
            } else {
              final NewStaticMetaMethod metaMethod = new NewStaticMetaMethod(method);
              arr.add(metaMethod);
              staticMethods.add(metaMethod);
            }
          }
        }
      }
    }
  }