Search in sources :

Example 11 with Resource

use of javax.annotation.Resource in project redkale by redkale.

the class Rest method createRestWebSocketServlet.

public static <T extends HttpServlet> T createRestWebSocketServlet(final ClassLoader classLoader, final Class<? extends WebSocket> webSocketType) {
    if (webSocketType == null)
        throw new RuntimeException("Rest WebSocket Class is null on createRestWebSocketServlet");
    if (Modifier.isAbstract(webSocketType.getModifiers()))
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") cannot abstract on createRestWebSocketServlet");
    if (Modifier.isFinal(webSocketType.getModifiers()))
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") cannot final on createRestWebSocketServlet");
    final RestWebSocket rws = webSocketType.getAnnotation(RestWebSocket.class);
    if (rws == null || rws.ignore())
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") have not @RestWebSocket or @RestWebSocket.ignore=true on createRestWebSocketServlet");
    boolean valid = false;
    for (Constructor c : webSocketType.getDeclaredConstructors()) {
        if (c.getParameterCount() == 0 && (Modifier.isPublic(c.getModifiers()) || Modifier.isProtected(c.getModifiers()))) {
            valid = true;
            break;
        }
    }
    if (!valid)
        throw new RuntimeException("Rest WebSocket Class(" + webSocketType + ") must have public or protected Constructor on createRestWebSocketServlet");
    final String rwsname = ResourceFactory.formatResourceName(rws.name());
    if (!checkName(rws.catalog()))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9");
    if (!checkName(rwsname))
        throw new RuntimeException(webSocketType.getName() + " have illegal " + RestWebSocket.class.getSimpleName() + ".name, only 0-9 a-z A-Z _ cannot begin 0-9");
    // ----------------------------------------------------------------------------------------
    final Set<Field> resourcesFieldSet = new LinkedHashSet<>();
    final ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    final Set<String> resourcesFieldNameSet = new HashSet<>();
    Class clzz = webSocketType;
    do {
        for (Field field : clzz.getDeclaredFields()) {
            if (field.getAnnotation(Resource.class) == null)
                continue;
            if (resourcesFieldNameSet.contains(field.getName()))
                continue;
            if (Modifier.isStatic(field.getModifiers()))
                throw new RuntimeException(field + " cannot static on createRestWebSocketServlet");
            if (Modifier.isFinal(field.getModifiers()))
                throw new RuntimeException(field + " cannot final on createRestWebSocketServlet");
            if (!Modifier.isPublic(field.getModifiers()) && !Modifier.isProtected(field.getModifiers())) {
                throw new RuntimeException(field + " must be public or protected on createRestWebSocketServlet");
            }
            resourcesFieldNameSet.add(field.getName());
            resourcesFieldSet.add(field);
        }
    } while ((clzz = clzz.getSuperclass()) != Object.class);
    final List<Field> resourcesFields = new ArrayList<>(resourcesFieldSet);
    StringBuilder sb1 = new StringBuilder();
    StringBuilder sb2 = new StringBuilder();
    for (int i = 0; i < resourcesFields.size(); i++) {
        Field field = resourcesFields.get(i);
        sb1.append(Type.getDescriptor(field.getType()));
        sb2.append(Utility.getTypeDescriptor(field.getGenericType()));
    }
    final String resourceDescriptor = sb1.toString();
    final String resourceGenericDescriptor = sb1.length() == sb2.length() ? null : sb2.toString();
    // ----------------------------------------------------------------------------------------
    final Map<String, List<String>> asmParamMap = MethodParamClassVisitor.getMethodParamNames(new HashMap<>(), webSocketType);
    final Set<String> messageNames = new HashSet<>();
    final List<Method> messageMethods = new ArrayList<>();
    for (Method method : webSocketType.getMethods()) {
        RestOnMessage rom = method.getAnnotation(RestOnMessage.class);
        if (rom == null)
            continue;
        String name = rom.name();
        if (Modifier.isFinal(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not final but (" + method + ")");
        if (Modifier.isStatic(method.getModifiers()))
            throw new RuntimeException("@RestOnMessage method can not static but (" + method + ")");
        if (method.getReturnType() != void.class)
            throw new RuntimeException("@RestOnMessage method must return void but (" + method + ")");
        if (method.getExceptionTypes().length > 0)
            throw new RuntimeException("@RestOnMessage method can not throw exception but (" + method + ")");
        if (name.isEmpty())
            throw new RuntimeException(method + " RestOnMessage.name is empty createRestWebSocketServlet");
        if (messageNames.contains(name))
            throw new RuntimeException(method + " repeat RestOnMessage.name(" + name + ") createRestWebSocketServlet");
        messageNames.add(name);
        messageMethods.add(method);
    }
    // ----------------------------------------------------------------------------------------
    final String resDesc = Type.getDescriptor(Resource.class);
    final String wsDesc = Type.getDescriptor(WebSocket.class);
    final String wsParamDesc = Type.getDescriptor(WebSocketParam.class);
    final String jsonConvertDesc = Type.getDescriptor(JsonConvert.class);
    final String convertDisabledDesc = Type.getDescriptor(ConvertDisabled.class);
    final String webSocketParamName = Type.getInternalName(WebSocketParam.class);
    final String supDynName = WebSocketServlet.class.getName().replace('.', '/');
    final String webServletDesc = Type.getDescriptor(WebServlet.class);
    final String webSocketInternalName = Type.getInternalName(webSocketType);
    final String newDynName = webSocketInternalName.substring(0, webSocketInternalName.lastIndexOf('/') + 1) + "_Dyn" + webSocketType.getSimpleName() + "Servlet";
    final String newDynWebSokcetSimpleName = "_Dyn" + webSocketType.getSimpleName();
    final String newDynWebSokcetFullName = newDynName + "$" + newDynWebSokcetSimpleName;
    final String newDynMessageSimpleName = "_Dyn" + webSocketType.getSimpleName() + "Message";
    final String newDynMessageFullName = newDynName + "$" + newDynMessageSimpleName;
    final String newDynConsumerSimpleName = "_DynRestOnMessageConsumer";
    final String newDynConsumerFullName = newDynName + "$" + newDynConsumerSimpleName;
    // ----------------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        // RestDynSourceType
        av0 = cw.visitAnnotation(Type.getDescriptor(RestDynSourceType.class), true);
        av0.visit("value", Type.getType(Type.getDescriptor(webSocketType)));
        av0.visitEnd();
    }
    {
        // 注入 @WebServlet 注解
        String urlpath = (rws.catalog().isEmpty() ? "/" : ("/" + rws.catalog() + "/")) + rwsname;
        av0 = cw.visitAnnotation(webServletDesc, true);
        {
            AnnotationVisitor av1 = av0.visitArray("value");
            av1.visit(null, urlpath);
            av1.visitEnd();
        }
        av0.visit("moduleid", 0);
        av0.visit("repair", rws.repair());
        av0.visit("comment", rws.comment());
        av0.visitEnd();
    }
    {
        // 内部类
        cw.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
    }
    {
        // @Resource
        for (int i = 0; i < resourcesFields.size(); i++) {
            Field field = resourcesFields.get(i);
            Resource res = field.getAnnotation(Resource.class);
            java.lang.reflect.Type fieldType = field.getGenericType();
            fv = cw.visitField(ACC_PRIVATE, "_redkale_resource_" + i, Type.getDescriptor(field.getType()), fieldType == field.getType() ? null : Utility.getTypeDescriptor(fieldType), null);
            {
                av0 = fv.visitAnnotation(resDesc, true);
                av0.visit("name", res.name());
                av0.visitEnd();
            }
            fv.visitEnd();
        }
    }
    {
        // _DynWebSocketServlet构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(Type.getObjectType(newDynName + "$" + newDynWebSokcetSimpleName + "Message"));
        mv.visitFieldInsn(PUTFIELD, newDynName, "messageTextType", "Ljava/lang/reflect/Type;");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.liveinterval());
        mv.visitFieldInsn(PUTFIELD, newDynName, "liveinterval", "I");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.wsmaxconns());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxconns", "I");
        mv.visitVarInsn(ALOAD, 0);
        pushInt(mv, rws.wsmaxbody());
        mv.visitFieldInsn(PUTFIELD, newDynName, "wsmaxbody", "I");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.single() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "single", "Z");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(rws.anyuser() ? ICONST_1 : ICONST_0);
        mv.visitFieldInsn(PUTFIELD, newDynName, "anyuser", "Z");
        mv.visitInsn(RETURN);
        mv.visitMaxs(3, 1);
        mv.visitEnd();
    }
    {
        // createWebSocket 方法
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createWebSocket", "()" + wsDesc, "<G::Ljava/io/Serializable;T:Ljava/lang/Object;>()L" + WebSocket.class.getName().replace('.', '/') + "<TG;TT;>;", null));
        mv.visitTypeInsn(NEW, newDynName + "$" + newDynWebSokcetSimpleName);
        mv.visitInsn(DUP);
        for (int i = 0; i < resourcesFields.size(); i++) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, "_redkale_resource_" + i, Type.getDescriptor(resourcesFields.get(i).getType()));
        }
        mv.visitMethodInsn(INVOKESPECIAL, newDynWebSokcetFullName, "<init>", "(" + resourceDescriptor + ")V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2 + resourcesFields.size(), 1);
        mv.visitEnd();
    }
    {
        // createRestOnMessageConsumer
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PROTECTED, "createRestOnMessageConsumer", "()Ljava/util/function/BiConsumer;", "()Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", null));
        mv.visitTypeInsn(NEW, newDynConsumerFullName);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, newDynConsumerFullName, "<init>", "()V", false);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();
    }
    {
        // resourceName
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "resourceName", "()Ljava/lang/String;", null, null));
        mv.visitLdcInsn(rwsname);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    RestClassLoader newLoader = new RestClassLoader(loader);
    for (int i = 0; i < messageMethods.size(); i++) {
        // _DyncXXXWebSocketMessage 子消息List
        Method method = messageMethods.get(i);
        String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName + endfix, null, "java/lang/Object", new String[] { webSocketParamName, "java/lang/Runnable" });
        cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        Set<String> paramnames = new HashSet<>();
        String methodesc = method.getName() + ":" + Type.getMethodDescriptor(method);
        List<String> names = asmParamMap.get(methodesc);
        Parameter[] params = method.getParameters();
        // 必须使用LinkedHashMap确保顺序
        final LinkedHashMap<String, Parameter> paramap = new LinkedHashMap();
        for (int j = 0; j < params.length; j++) {
            // 字段列表
            Parameter param = params[j];
            String paramname = param.getName();
            RestParam rp = param.getAnnotation(RestParam.class);
            if (rp != null && !rp.name().isEmpty()) {
                paramname = rp.name();
            } else if (names != null && names.size() > j) {
                paramname = names.get(j);
            }
            if (paramnames.contains(paramname))
                throw new RuntimeException(method + " has same @RestParam.name");
            paramnames.add(paramname);
            paramap.put(paramname, param);
            fv = cw2.visitField(ACC_PUBLIC, paramname, Type.getDescriptor(param.getType()), param.getType() == param.getParameterizedType() ? null : Utility.getTypeDescriptor(param.getParameterizedType()), null);
            fv.visitEnd();
        }
        {
            // _redkale_websocket
            fv = cw2.visitField(ACC_PUBLIC, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";", null, null);
            av0 = fv.visitAnnotation(convertDisabledDesc, true);
            av0.visitEnd();
            fv.visitEnd();
        }
        {
            // 空构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // getNames
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getNames", "()[Ljava/lang/String;", null, null));
            pushInt(mv, paramap.size());
            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
            int index = -1;
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitInsn(DUP);
                pushInt(mv, ++index);
                mv.visitLdcInsn(en.getKey());
                mv.visitInsn(AASTORE);
            }
            mv.visitInsn(ARETURN);
            mv.visitMaxs(paramap.size() + 2, 1);
            mv.visitEnd();
        }
        {
            // getValue
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "getValue", "(Ljava/lang/String;)Ljava/lang/Object;", "<T:Ljava/lang/Object;>(Ljava/lang/String;)TT;", null));
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                Class paramType = en.getValue().getType();
                mv.visitLdcInsn(en.getKey());
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false);
                Label l1 = new Label();
                mv.visitJumpInsn(IFEQ, l1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, en.getKey(), Type.getDescriptor(paramType));
                if (paramType.isPrimitive()) {
                    Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(paramType, 1), 0).getClass();
                    mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(paramType) + ")" + Type.getDescriptor(bigclaz), false);
                }
                mv.visitInsn(ARETURN);
                mv.visitLabel(l1);
            }
            mv.visitInsn(ACONST_NULL);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }
        {
            // execute
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "execute", "(L" + newDynWebSokcetFullName + ";)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            mv.visitVarInsn(ALOAD, 1);
            mv.visitLdcInsn(method.getAnnotation(RestOnMessage.class).name());
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, "preOnMessage", "(Ljava/lang/String;" + wsParamDesc + "Ljava/lang/Runnable;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(4, 2);
            mv.visitEnd();
        }
        {
            // run
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "run", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynMessageFullName + endfix, "_redkale_websocket", "L" + newDynWebSokcetFullName + ";");
            for (Map.Entry<String, Parameter> en : paramap.entrySet()) {
                mv.visitVarInsn(ALOAD, 0);
                mv.visitFieldInsn(GETFIELD, (newDynMessageFullName + endfix), en.getKey(), Type.getDescriptor(en.getValue().getType()));
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynWebSokcetFullName, method.getName(), Type.getMethodDescriptor(method), false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass((newDynMessageFullName + endfix).replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynXXXWebSocketMessage class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynMessageFullName, null, "java/lang/Object", null);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
            fv = cw2.visitField(ACC_PUBLIC, method.getAnnotation(RestOnMessage.class).name(), "L" + newDynMessageFullName + endfix + ";", null, null);
            fv.visitEnd();
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // toString
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
            mv.visitMethodInsn(INVOKESTATIC, JsonConvert.class.getName().replace('.', '/'), "root", "()" + jsonConvertDesc, false);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, JsonConvert.class.getName().replace('.', '/'), "convertTo", "(Ljava/lang/Object;)Ljava/lang/String;", false);
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynMessageFullName.replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynXXXWebSocket class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynWebSokcetFullName, null, webSocketInternalName, null);
        cw2.visitInnerClass(newDynWebSokcetFullName, newDynName, newDynWebSokcetSimpleName, ACC_PUBLIC + ACC_STATIC);
        {
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "(" + resourceDescriptor + ")V", resourceGenericDescriptor == null ? null : ("(" + resourceGenericDescriptor + ")V"), null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, webSocketInternalName, "<init>", "()V", false);
            for (int i = 0; i < resourcesFields.size(); i++) {
                Field field = resourcesFields.get(i);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, i + 1);
                mv.visitFieldInsn(PUTFIELD, newDynWebSokcetFullName, field.getName(), Type.getDescriptor(field.getType()));
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(2, 1 + resourcesFields.size());
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynWebSokcetFullName.replace('/', '.'), cw2.toByteArray());
    }
    {
        // _DynRestOnMessageConsumer class
        ClassWriter cw2 = new ClassWriter(COMPUTE_FRAMES);
        cw2.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynConsumerFullName, "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + wsDesc + "Ljava/lang/Object;>;", "java/lang/Object", new String[] { "java/util/function/BiConsumer" });
        cw2.visitInnerClass(newDynConsumerFullName, newDynName, newDynConsumerSimpleName, ACC_PUBLIC + ACC_STATIC);
        cw2.visitInnerClass(newDynMessageFullName, newDynName, newDynMessageSimpleName, ACC_PUBLIC + ACC_STATIC);
        for (int i = 0; i < messageMethods.size(); i++) {
            Method method = messageMethods.get(i);
            String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
            cw2.visitInnerClass(newDynMessageFullName + endfix, newDynName, newDynMessageSimpleName + endfix, ACC_PUBLIC + ACC_STATIC);
        }
        {
            // 构造函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            // accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, newDynWebSokcetFullName);
            mv.visitVarInsn(ASTORE, 3);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, newDynMessageFullName);
            mv.visitVarInsn(ASTORE, 4);
            for (int i = 0; i < messageMethods.size(); i++) {
                final Method method = messageMethods.get(i);
                String endfix = "_" + method.getName() + "_" + (i > 9 ? i : ("0" + i));
                final String messagename = method.getAnnotation(RestOnMessage.class).name();
                mv.visitVarInsn(ALOAD, 4);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";");
                Label ifLabel = new Label();
                mv.visitJumpInsn(IFNULL, ifLabel);
                mv.visitVarInsn(ALOAD, 4);
                mv.visitFieldInsn(GETFIELD, newDynMessageFullName, messagename, "L" + (newDynMessageFullName + endfix) + ";");
                mv.visitVarInsn(ALOAD, 3);
                mv.visitMethodInsn(INVOKEVIRTUAL, (newDynMessageFullName + endfix), "execute", "(L" + newDynWebSokcetFullName + ";)V", false);
                mv.visitInsn(RETURN);
                mv.visitLabel(ifLabel);
            }
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3 + messageMethods.size());
            mv.visitEnd();
        }
        {
            // 虚拟accept函数
            mv = new MethodDebugVisitor(cw2.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "accept", "(Ljava/lang/Object;Ljava/lang/Object;)V", null, null));
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, WebSocket.class.getName().replace('.', '/'));
            mv.visitVarInsn(ALOAD, 2);
            mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynConsumerFullName, "accept", "(" + wsDesc + "Ljava/lang/Object;)V", false);
            mv.visitInsn(RETURN);
            mv.visitMaxs(3, 3);
            mv.visitEnd();
        }
        cw2.visitEnd();
        newLoader.loadClass(newDynConsumerFullName.replace('/', '.'), cw2.toByteArray());
    }
    cw.visitEnd();
    Class<?> newClazz = newLoader.loadClass(newDynName.replace('/', '.'), cw.toByteArray());
    try {
        return (T) newClazz.getDeclaredConstructor().newInstance();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) Resource(javax.annotation.Resource) Type(org.redkale.asm.Type) ElementType(java.lang.annotation.ElementType)

Example 12 with Resource

use of javax.annotation.Resource in project redkale by redkale.

the class Application method init.

public void init() throws Exception {
    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "" + Runtime.getRuntime().availableProcessors() * 4);
    System.setProperty("net.transport.pinginterval", "30");
    System.setProperty("convert.bson.tiny", "true");
    System.setProperty("convert.json.tiny", "true");
    System.setProperty("convert.bson.pool.size", "128");
    System.setProperty("convert.json.pool.size", "128");
    System.setProperty("convert.bson.writer.buffer.defsize", "4096");
    System.setProperty("convert.json.writer.buffer.defsize", "4096");
    File persist = new File(this.home, "conf/persistence.xml");
    final String homepath = this.home.getCanonicalPath();
    if (persist.isFile())
        System.setProperty(DataSources.DATASOURCE_CONFPATH, persist.getCanonicalPath());
    logger.log(Level.INFO, "APP_JAVA = " + System.getProperty("java.version") + "\r\n" + RESNAME_APP_ADDR + " = " + this.localAddress.getHostAddress() + "\r\n" + RESNAME_APP_HOME + " = " + homepath);
    String lib = config.getValue("lib", "${APP_HOME}/libs/*").trim().replace("${APP_HOME}", homepath);
    lib = lib.isEmpty() ? (homepath + "/conf") : (lib + ";" + homepath + "/conf");
    Server.loadLib(classLoader, logger, lib);
    // ------------------------------------------------------------------------
    final AnyValue resources = config.getAnyValue("resources");
    if (resources != null) {
        resourceFactory.register(RESNAME_APP_GRES, AnyValue.class, resources);
        final AnyValue properties = resources.getAnyValue("properties");
        if (properties != null) {
            String dfloads = properties.getValue("load");
            if (dfloads != null) {
                for (String dfload : dfloads.split(";")) {
                    if (dfload.trim().isEmpty())
                        continue;
                    final File df = (dfload.indexOf('/') < 0) ? new File(home, "conf/" + dfload) : new File(dfload);
                    if (df.isFile()) {
                        Properties ps = new Properties();
                        InputStream in = new FileInputStream(df);
                        ps.load(in);
                        in.close();
                        ps.forEach((x, y) -> resourceFactory.register("property." + x, y));
                    }
                }
            }
            for (AnyValue prop : properties.getAnyValues("property")) {
                String name = prop.getValue("name");
                String value = prop.getValue("value");
                if (name == null || value == null)
                    continue;
                if (name.startsWith("system.property.")) {
                    System.setProperty(name.substring("system.property.".length()), value);
                } else if (name.startsWith("mimetype.property.")) {
                    MimeType.add(name.substring("mimetype.property.".length()), value);
                } else if (name.startsWith("property.")) {
                    resourceFactory.register(name, value);
                } else {
                    resourceFactory.register("property." + name, value);
                }
            }
        }
    }
    this.resourceFactory.register(BsonFactory.root());
    this.resourceFactory.register(JsonFactory.root());
    this.resourceFactory.register(BsonFactory.root().getConvert());
    this.resourceFactory.register(JsonFactory.root().getConvert());
    this.resourceFactory.register("bsonconvert", Convert.class, BsonFactory.root().getConvert());
    this.resourceFactory.register("jsonconvert", Convert.class, JsonFactory.root().getConvert());
    // 只有WatchService才能加载Application、WatchFactory
    final Application application = this;
    this.resourceFactory.register(new ResourceFactory.ResourceLoader() {

        @Override
        public void load(ResourceFactory rf, final Object src, String resourceName, Field field, final Object attachment) {
            try {
                Resource res = field.getAnnotation(Resource.class);
                if (res == null)
                    return;
                // 远程模式不得注入
                if (Sncp.isRemote((Service) src))
                    return;
                Class type = field.getType();
                if (type == Application.class) {
                    field.set(src, application);
                } else if (type == ResourceFactory.class) {
                    field.set(src, res.name().equalsIgnoreCase("server") ? rf : (res.name().isEmpty() ? application.resourceFactory : null));
                } else if (type == TransportFactory.class) {
                    field.set(src, application.sncpTransportFactory);
                } else if (type == NodeSncpServer.class) {
                    NodeServer server = null;
                    for (NodeServer ns : application.getNodeServers()) {
                        if (ns.getClass() == NodeSncpServer.class)
                            continue;
                        if (res.name().equals(ns.server.getName())) {
                            server = ns;
                            break;
                        }
                    }
                    field.set(src, server);
                } else if (type == NodeHttpServer.class) {
                    NodeServer server = null;
                    for (NodeServer ns : application.getNodeServers()) {
                        if (ns.getClass() == NodeHttpServer.class)
                            continue;
                        if (res.name().equals(ns.server.getName())) {
                            server = ns;
                            break;
                        }
                    }
                    field.set(src, server);
                } else if (type == NodeWatchServer.class) {
                    NodeServer server = null;
                    for (NodeServer ns : application.getNodeServers()) {
                        if (ns.getClass() == NodeWatchServer.class)
                            continue;
                        if (res.name().equals(ns.server.getName())) {
                            server = ns;
                            break;
                        }
                    }
                    field.set(src, server);
                }
            // if (type == WatchFactory.class) {
            // field.set(src, application.watchFactory);
            // }
            } catch (Exception e) {
                logger.log(Level.SEVERE, "Resource inject error", e);
            }
        }

        @Override
        public boolean autoNone() {
            return false;
        }
    }, Application.class, ResourceFactory.class, TransportFactory.class, NodeSncpServer.class, NodeHttpServer.class, NodeWatchServer.class);
    // --------------------------------------------------------------------------
    initResources();
}
Also used : Resource(javax.annotation.Resource) Service(org.redkale.service.Service) DefaultAnyValue(org.redkale.util.AnyValue.DefaultAnyValue)

Example 13 with Resource

use of javax.annotation.Resource in project redkale by redkale.

the class Sncp method createLocalServiceClass.

/**
 * <blockquote><pre>
 * public class TestService implements Service{
 *
 *      public String findSomeThing(){
 *          return "hello";
 *      }
 *
 *      &#64;RpcMultiRun(selfrun = false)
 *      public void createSomeThing(TestBean bean){
 *          //do something
 *      }
 *
 *      &#64;RpcMultiRun
 *      public String updateSomeThing(String id){
 *          return "hello" + id;
 *      }
 * }
 * </pre></blockquote>
 *
 * <blockquote><pre>
 * &#64;Resource(name = "")
 * &#64;SncpDyn(remote = false)
 * &#64;ResourceType(TestService.class)
 * public final class _DynLocalTestService extends TestService{
 *
 *      private AnyValue _redkale_conf;
 *
 *      private SncpClient _redkale_client;
 *
 *      &#64;Override
 *      public String toString() {
 *          return _redkale_selfstring == null ? super.toString() : _redkale_selfstring;
 *      }
 *
 *      &#64;Override
 *      public void createSomeThing(TestBean bean){
 *          this._redkale_createSomeThing(false, true, true, bean);
 *      }
 *
 *      &#64;SncpDyn(remote = false, index = 0)
 *      public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
 *          if(selfrunnable) super.createSomeThing(bean);
 *          if (_redkale_client== null) return;
 *          if (samerunnable) _redkale_client.remoteSameGroup(0, true, false, false, bean);
 *          if (diffrunnable) _redkale_client.remoteDiffGroup(0, true, true, false, bean);
 *      }
 *
 *      &#64;Override
 *      public String updateSomeThing(String id){
 *          return this._redkale_updateSomeThing(true, true, true, id);
 *      }
 *
 *      &#64;SncpDyn(remote = false, index = 1)
 *      public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
 *          String rs = super.updateSomeThing(id);
 *          if (_redkale_client== null) return rs;
 *          if (samerunnable) _redkale_client.remoteSameGroup(1, true, false, false, id);
 *          if (diffrunnable) _redkale_client.remoteDiffGroup(1, true, true, false, id);
 *          return rs;
 *      }
 * }
 * </pre></blockquote>
 *
 * 创建Service的本地模式Class
 *
 * @param <T>              Service子类
 * @param classLoader      ClassLoader
 * @param name             资源名
 * @param serviceImplClass Service类
 *
 * @return Service实例
 */
@SuppressWarnings("unchecked")
protected static <T extends Service> Class<? extends T> createLocalServiceClass(ClassLoader classLoader, final String name, final Class<T> serviceImplClass) {
    if (serviceImplClass == null)
        return null;
    if (!Service.class.isAssignableFrom(serviceImplClass))
        return serviceImplClass;
    ResourceFactory.checkResourceName(name);
    int mod = serviceImplClass.getModifiers();
    if (!java.lang.reflect.Modifier.isPublic(mod))
        return serviceImplClass;
    if (java.lang.reflect.Modifier.isAbstract(mod))
        return serviceImplClass;
    final List<Method> methods = SncpClient.parseMethod(serviceImplClass);
    final String supDynName = serviceImplClass.getName().replace('.', '/');
    final String clientName = SncpClient.class.getName().replace('.', '/');
    final String resDesc = Type.getDescriptor(Resource.class);
    final String clientDesc = Type.getDescriptor(SncpClient.class);
    final String anyValueDesc = Type.getDescriptor(AnyValue.class);
    final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
    ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + LOCALPREFIX + serviceImplClass.getSimpleName();
    if (!name.isEmpty()) {
        boolean normal = true;
        for (char ch : name.toCharArray()) {
            if (!((ch >= '0' && ch <= '9') || ch == '_' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
                normal = false;
        }
        if (!normal)
            throw new RuntimeException(serviceImplClass + "'s resource name is illegal, must be 0-9 _ a-z A-Z");
        newDynName += "_" + (normal ? name : hash(name));
    }
    try {
        return (Class<T>) loader.loadClass(newDynName.replace('/', '.'));
    } catch (Throwable ex) {
    }
    // ------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
    {
        av0 = cw.visitAnnotation(resDesc, true);
        av0.visit("name", name);
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(sncpDynDesc, true);
        av0.visit("remote", Boolean.FALSE);
        av0.visitEnd();
    }
    {
        // 给新类加上 原有的Annotation
        for (Annotation ann : serviceImplClass.getAnnotations()) {
            if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType)
                continue;
            visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
        }
    }
    {
        av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
        ResourceType rty = serviceImplClass.getAnnotation(ResourceType.class);
        av0.visit("value", Type.getType(Type.getDescriptor(rty == null ? serviceImplClass : rty.value())));
        av0.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
        fv.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null);
        fv.visitEnd();
    }
    {
        // 构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        // toString()
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNONNULL, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
        Label l2 = new Label();
        mv.visitJumpInsn(GOTO, l2);
        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "toSimpleString", "()Ljava/lang/String;", false);
        mv.visitLabel(l2);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    int i = -1;
    for (final Method method : methods) {
        final RpcMultiRun mrun = method.getAnnotation(RpcMultiRun.class);
        if (mrun == null)
            continue;
        final Class returnType = method.getReturnType();
        final String methodDesc = Type.getMethodDescriptor(method);
        final Class[] paramtypes = method.getParameterTypes();
        final int index = ++i;
        {
            // 原始方法
            mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + (method.isVarArgs() ? ACC_VARARGS : 0), method.getName(), methodDesc, null, null));
            // mv.setDebug(true);
            {
                // 给参数加上 Annotation
                final Annotation[][] anns = method.getParameterAnnotations();
                for (int k = 0; k < anns.length; k++) {
                    for (Annotation ann : anns[k]) {
                        // 必须过滤掉 RpcMultiRun、SncpDyn,否则生成远程模式Service时会出错
                        if (ann instanceof SncpDyn || ann instanceof RpcMultiRun)
                            continue;
                        visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
                    }
                }
            }
            mv.visitVarInsn(ALOAD, 0);
            mv.visitInsn(mrun.selfrun() ? ICONST_1 : ICONST_0);
            mv.visitInsn(mrun.samerun() ? ICONST_1 : ICONST_0);
            mv.visitInsn(mrun.diffrun() ? ICONST_1 : ICONST_0);
            int varindex = 0;
            boolean handlerFuncFlag = false;
            for (Class pt : paramtypes) {
                if (CompletionHandler.class.isAssignableFrom(pt)) {
                    if (handlerFuncFlag)
                        throw new RuntimeException(method + " have more than one CompletionHandler type parameter");
                    checkAsyncModifier(pt, method);
                    handlerFuncFlag = true;
                }
                if (pt.isPrimitive()) {
                    if (pt == long.class) {
                        mv.visitVarInsn(LLOAD, ++varindex);
                        ++varindex;
                    } else if (pt == double.class) {
                        mv.visitVarInsn(DLOAD, ++varindex);
                        ++varindex;
                    } else if (pt == float.class) {
                        mv.visitVarInsn(FLOAD, ++varindex);
                    } else {
                        mv.visitVarInsn(ILOAD, ++varindex);
                    }
                } else {
                    mv.visitVarInsn(ALOAD, ++varindex);
                }
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, FIELDPREFIX + "_" + method.getName(), "(ZZZ" + methodDesc.substring(1), false);
            if (returnType == void.class) {
                mv.visitInsn(RETURN);
            } else if (returnType.isPrimitive()) {
                if (returnType == long.class) {
                    mv.visitInsn(LRETURN);
                } else if (returnType == float.class) {
                    mv.visitInsn(FRETURN);
                } else if (returnType == double.class) {
                    mv.visitInsn(DRETURN);
                } else {
                    mv.visitInsn(IRETURN);
                }
            } else {
                mv.visitInsn(ARETURN);
            }
            mv.visitMaxs(varindex + 3, varindex + 1);
            mv.visitEnd();
        }
        {
            // _方法   _方法比无_方法多了三个参数
            mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC + (method.isVarArgs() ? ACC_VARARGS : 0), FIELDPREFIX + "_" + method.getName(), "(ZZZ" + methodDesc.substring(1), null, null));
            // mv.setDebug(true);
            {
                // 给参数加上 Annotation
                final Annotation[][] anns = method.getParameterAnnotations();
                boolean handlerAttachFlag = false;
                for (int k = 0; k < anns.length; k++) {
                    for (Annotation ann : anns[k]) {
                        if (ann.annotationType() == RpcAttachment.class) {
                            if (handlerAttachFlag) {
                                throw new RuntimeException(method + " have more than one @RpcAttachment parameter");
                            }
                            handlerAttachFlag = true;
                        }
                        // 必须过滤掉 RpcMultiRun、SncpDyn,否则生成远程模式Service时会出错
                        if (ann instanceof SncpDyn || ann instanceof RpcMultiRun)
                            continue;
                        visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
                    }
                }
            }
            av0 = mv.visitAnnotation(sncpDynDesc, true);
            av0.visit("remote", Boolean.FALSE);
            av0.visit("index", index);
            av0.visitEnd();
            // ---------------------------- 调用selfrun ---------------------------------
            Label selfLabel = new Label();
            if (returnType == void.class) {
                // if
                mv.visitVarInsn(ILOAD, 1);
                mv.visitJumpInsn(IFEQ, selfLabel);
            }
            mv.visitVarInsn(ALOAD, 0);
            // 空3给selfrunnable、samerunnable、diffrunnable
            int varindex = 3;
            for (Class pt : paramtypes) {
                if (pt.isPrimitive()) {
                    if (pt == long.class) {
                        mv.visitVarInsn(LLOAD, ++varindex);
                        ++varindex;
                    } else if (pt == double.class) {
                        mv.visitVarInsn(DLOAD, ++varindex);
                        ++varindex;
                    } else if (pt == float.class) {
                        mv.visitVarInsn(FLOAD, ++varindex);
                    } else {
                        mv.visitVarInsn(ILOAD, ++varindex);
                    }
                } else {
                    mv.visitVarInsn(ALOAD, ++varindex);
                }
            }
            mv.visitMethodInsn(INVOKESPECIAL, supDynName, method.getName(), methodDesc, false);
            if (returnType == void.class) {
                // end if
                mv.visitLabel(selfLabel);
            }
            if (returnType == void.class) {
            } else if (returnType.isPrimitive()) {
                if (returnType == long.class) {
                    mv.visitVarInsn(LSTORE, ++varindex);
                // ++varindex; //多加1
                } else if (returnType == float.class) {
                    mv.visitVarInsn(FSTORE, ++varindex);
                } else if (returnType == double.class) {
                    mv.visitVarInsn(DSTORE, ++varindex);
                // ++varindex; //多加1
                } else {
                    mv.visitVarInsn(ISTORE, ++varindex);
                }
            } else {
                mv.visitVarInsn(ASTORE, ++varindex);
            }
            // 
            final int rsindex = varindex;
            // ---------------------------if (_redkale_client== null)  return ----------------------------------
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
            Label clientLabel = new Label();
            mv.visitJumpInsn(IFNONNULL, clientLabel);
            if (returnType == void.class) {
                mv.visitInsn(RETURN);
            } else if (returnType.isPrimitive()) {
                if (returnType == long.class) {
                    mv.visitVarInsn(LLOAD, rsindex);
                    mv.visitInsn(LRETURN);
                } else if (returnType == float.class) {
                    mv.visitVarInsn(FLOAD, rsindex);
                    mv.visitInsn(FRETURN);
                } else if (returnType == double.class) {
                    mv.visitVarInsn(DLOAD, rsindex);
                    mv.visitInsn(DRETURN);
                } else {
                    mv.visitVarInsn(ILOAD, rsindex);
                    mv.visitInsn(IRETURN);
                }
            } else {
                mv.visitVarInsn(ALOAD, rsindex);
                mv.visitInsn(ARETURN);
            }
            mv.visitLabel(clientLabel);
            // ---------------------------- 调用samerun ---------------------------------
            // 读取 samerunnable
            mv.visitVarInsn(ILOAD, 2);
            Label sameLabel = new Label();
            // 判断 samerunnable
            mv.visitJumpInsn(IFEQ, sameLabel);
            // 调用 _client
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
            // 调用selfrunnable之前的参数个数;  _client
            final int preparams = 3;
            // 第几个 SncpAction
            pushInt(mv, index);
            // 参数总数量
            pushInt(mv, paramtypes.length + preparams);
            mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_0);
            // 第一个参数  selfrunnable
            mv.visitInsn(ICONST_1);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_1);
            // 第二个参数  samerunnable
            mv.visitInsn(ICONST_0);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_2);
            // 第三个参数  diffrunnable
            mv.visitInsn(ICONST_0);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            // 空3给selfrunnable、samerunnable、diffrunnable
            int insn = 3;
            for (int j = 0; j < paramtypes.length; j++) {
                final Class pt = paramtypes[j];
                mv.visitInsn(DUP);
                insn++;
                pushInt(mv, j + 3);
                if (pt.isPrimitive()) {
                    if (pt == long.class) {
                        mv.visitVarInsn(LLOAD, insn++);
                    } else if (pt == float.class) {
                        mv.visitVarInsn(FLOAD, insn++);
                    } else if (pt == double.class) {
                        mv.visitVarInsn(DLOAD, insn++);
                    } else {
                        mv.visitVarInsn(ILOAD, insn);
                    }
                    Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass();
                    mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
                } else {
                    mv.visitVarInsn(ALOAD, insn);
                }
                mv.visitInsn(AASTORE);
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteSameGroup" : "remoteSameGroup", "(I[Ljava/lang/Object;)V", false);
            mv.visitLabel(sameLabel);
            // ---------------------------- 调用diffrun ---------------------------------
            // 读取 diffrunnable
            mv.visitVarInsn(ILOAD, 3);
            Label diffLabel = new Label();
            // 判断 diffrunnable
            mv.visitJumpInsn(IFEQ, diffLabel);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
            // 第几个 SncpAction
            pushInt(mv, index);
            // 参数总数量
            pushInt(mv, paramtypes.length + preparams);
            mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_0);
            // 第一个参数  samerunnable
            mv.visitInsn(ICONST_1);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_1);
            // 第二个参数  diffrunnable
            mv.visitInsn(ICONST_1);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            mv.visitInsn(DUP);
            mv.visitInsn(ICONST_2);
            // 第二个参数  diffrunnable
            mv.visitInsn(ICONST_0);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
            mv.visitInsn(AASTORE);
            // 空3给selfrunnable、samerunnable、diffrunnable
            insn = 3;
            for (int j = 0; j < paramtypes.length; j++) {
                final Class pt = paramtypes[j];
                mv.visitInsn(DUP);
                insn++;
                pushInt(mv, j + 3);
                if (pt.isPrimitive()) {
                    if (pt == long.class) {
                        mv.visitVarInsn(LLOAD, insn++);
                    } else if (pt == float.class) {
                        mv.visitVarInsn(FLOAD, insn++);
                    } else if (pt == double.class) {
                        mv.visitVarInsn(DLOAD, insn++);
                    } else {
                        mv.visitVarInsn(ILOAD, insn);
                    }
                    Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(pt, 1), 0).getClass();
                    mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor(pt) + ")" + Type.getDescriptor(bigclaz), false);
                } else {
                    mv.visitVarInsn(ALOAD, insn);
                }
                mv.visitInsn(AASTORE);
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, clientName, mrun.async() ? "asyncRemoteDiffGroup" : "remoteDiffGroup", "(I[Ljava/lang/Object;)V", false);
            mv.visitLabel(diffLabel);
            if (returnType == void.class) {
                mv.visitInsn(RETURN);
            } else if (returnType.isPrimitive()) {
                if (returnType == long.class) {
                    mv.visitVarInsn(LLOAD, rsindex);
                    mv.visitInsn(LRETURN);
                } else if (returnType == float.class) {
                    mv.visitVarInsn(FLOAD, rsindex);
                    mv.visitInsn(FRETURN);
                } else if (returnType == double.class) {
                    mv.visitVarInsn(DLOAD, rsindex);
                    mv.visitInsn(DRETURN);
                } else {
                    mv.visitVarInsn(ILOAD, rsindex);
                    mv.visitInsn(IRETURN);
                }
            } else {
                mv.visitVarInsn(ALOAD, rsindex);
                mv.visitInsn(ARETURN);
            }
            mv.visitMaxs(Math.max(varindex, 10), varindex + 4);
            mv.visitEnd();
        }
    }
    cw.visitEnd();
    byte[] bytes = cw.toByteArray();
    Class<?> newClazz = new ClassLoader(loader) {

        public final Class<?> loadClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
        }
    }.loadClass(newDynName.replace('/', '.'), bytes);
    return (Class<T>) newClazz;
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) CompletionHandler(java.nio.channels.CompletionHandler) Resource(javax.annotation.Resource) Annotation(java.lang.annotation.Annotation)

Example 14 with Resource

use of javax.annotation.Resource in project redkale by redkale.

the class Sncp method createRemoteService.

/**
 * <blockquote><pre>
 * &#64;Resource(name = "")
 * &#64;SncpDyn(remote = true)
 * &#64;ResourceType(TestService.class)
 * public final class _DynRemoteTestService extends TestService{
 *
 *      private AnyValue _redkale_conf;
 *
 *      private SncpClient _redkale_client;
 *
 *      &#64;SncpDyn(remote = false, index = 0)
 *      public void _redkale_createSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, TestBean bean){
 *          _redkale_client.remote(0, selfrunnable, samerunnable, diffrunnable, bean);
 *      }
 *
 *      &#64;SncpDyn(remote = false, index = 1)
 *      public String _redkale_updateSomeThing(boolean selfrunnable, boolean samerunnable, boolean diffrunnable, String id){
 *          return _redkale_client.remote(1, selfrunnable, samerunnable, diffrunnable, id);
 *      }
 *
 *      &#64;Override
 *      public void createSomeThing(TestBean bean){
 *          _redkale_client.remote(2, bean);
 *      }
 *
 *      &#64;Override
 *      public String findSomeThing(){
 *          return _redkale_client.remote(3);
 *      }
 *
 *      &#64;Override
 *      public String updateSomeThing(String id){
 *          return  _redkale_client.remote(4, id);
 *      }
 * }
 * </pre></blockquote>
 *
 * 创建远程模式的Service实例
 *
 * @param <T>                    Service泛型
 * @param classLoader            ClassLoader
 * @param name                   资源名
 * @param serviceTypeOrImplClass Service类
 * @param transportFactory       TransportFactory
 * @param clientAddress          本地IP地址
 * @param groups0                 所有的组节点,包含自身
 * @param conf                   启动配置项
 *
 * @return Service的远程模式实例
 */
@SuppressWarnings("unchecked")
public static <T extends Service> T createRemoteService(final ClassLoader classLoader, final String name, final Class<T> serviceTypeOrImplClass, final TransportFactory transportFactory, final InetSocketAddress clientAddress, final Set<String> groups0, final AnyValue conf) {
    if (serviceTypeOrImplClass == null)
        return null;
    if (!Service.class.isAssignableFrom(serviceTypeOrImplClass))
        return null;
    Set<String> groups = groups0 == null ? new HashSet<>() : groups0;
    ResourceFactory.checkResourceName(name);
    int mod = serviceTypeOrImplClass.getModifiers();
    boolean realed = !(java.lang.reflect.Modifier.isAbstract(mod) || serviceTypeOrImplClass.isInterface());
    if (!java.lang.reflect.Modifier.isPublic(mod))
        return null;
    final String supDynName = serviceTypeOrImplClass.getName().replace('.', '/');
    final String clientName = SncpClient.class.getName().replace('.', '/');
    final String resDesc = Type.getDescriptor(Resource.class);
    final String clientDesc = Type.getDescriptor(SncpClient.class);
    final String sncpDynDesc = Type.getDescriptor(SncpDyn.class);
    final String anyValueDesc = Type.getDescriptor(AnyValue.class);
    ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
    String newDynName = supDynName.substring(0, supDynName.lastIndexOf('/') + 1) + REMOTEPREFIX + serviceTypeOrImplClass.getSimpleName();
    try {
        Class newClazz = loader.loadClass(newDynName.replace('/', '.'));
        T rs = (T) newClazz.getDeclaredConstructor().newInstance();
        SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
        client.setRemoteGroups(groups);
        client.setRemoteGroupTransport(transportFactory.loadRemoteTransport(clientAddress, groups));
        Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
        c.setAccessible(true);
        c.set(rs, client);
        transportFactory.addSncpService(rs);
        return rs;
    } catch (Throwable ex) {
    }
    // ------------------------------------------------------------------------------
    ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
    FieldVisitor fv;
    MethodDebugVisitor mv;
    AnnotationVisitor av0;
    cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, serviceTypeOrImplClass.isInterface() ? new String[] { supDynName } : null);
    {
        av0 = cw.visitAnnotation(resDesc, true);
        av0.visit("name", name);
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(Type.getDescriptor(ResourceType.class), true);
        ResourceType rty = serviceTypeOrImplClass.getAnnotation(ResourceType.class);
        av0.visit("value", Type.getType(Type.getDescriptor(rty == null ? serviceTypeOrImplClass : rty.value())));
        av0.visitEnd();
    }
    {
        av0 = cw.visitAnnotation(sncpDynDesc, true);
        av0.visit("remote", Boolean.TRUE);
        av0.visitEnd();
    }
    {
        // 给新类加上 原有的Annotation
        for (Annotation ann : serviceTypeOrImplClass.getAnnotations()) {
            if (ann instanceof Resource || ann instanceof SncpDyn || ann instanceof ResourceType)
                continue;
            visitAnnotation(cw.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
        }
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_conf", anyValueDesc, null, null);
        fv.visitEnd();
    }
    {
        fv = cw.visitField(ACC_PRIVATE, FIELDPREFIX + "_client", clientDesc, null, null);
        fv.visitEnd();
    }
    {
        // 构造函数
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
        // mv.setDebug(true);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, serviceTypeOrImplClass.isInterface() ? "java/lang/Object" : supDynName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    {
        // init
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "init", "(" + anyValueDesc + ")V", null, null));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 2);
        mv.visitEnd();
    }
    {
        // destroy
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "destroy", "(" + anyValueDesc + ")V", null, null));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 2);
        mv.visitEnd();
    }
    {
        // toString()
        mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNONNULL, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;", false);
        Label l2 = new Label();
        mv.visitJumpInsn(GOTO, l2);
        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
        mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "toSimpleString", "()Ljava/lang/String;", false);
        mv.visitLabel(l2);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }
    int i = -1;
    for (final SncpAction entry : SncpClient.getSncpActions(realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass)) {
        final int index = ++i;
        final java.lang.reflect.Method method = entry.method;
        {
            mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
            // mv.setDebug(true);
            {
                // 给参数加上 Annotation
                final Annotation[][] anns = method.getParameterAnnotations();
                for (int k = 0; k < anns.length; k++) {
                    for (Annotation ann : anns[k]) {
                        visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
                    }
                }
            }
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, newDynName, FIELDPREFIX + "_client", clientDesc);
            pushInt(mv, index);
            {
                // 传参数
                int paramlen = entry.paramTypes.length;
                pushInt(mv, paramlen);
                mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                java.lang.reflect.Type[] paramtypes = entry.paramTypes;
                int insn = 0;
                for (int j = 0; j < paramtypes.length; j++) {
                    final java.lang.reflect.Type pt = paramtypes[j];
                    mv.visitInsn(DUP);
                    insn++;
                    pushInt(mv, j);
                    if (pt instanceof Class && ((Class) pt).isPrimitive()) {
                        if (pt == long.class) {
                            mv.visitVarInsn(LLOAD, insn++);
                        } else if (pt == float.class) {
                            mv.visitVarInsn(FLOAD, insn++);
                        } else if (pt == double.class) {
                            mv.visitVarInsn(DLOAD, insn++);
                        } else {
                            mv.visitVarInsn(ILOAD, insn);
                        }
                        Class bigclaz = java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance((Class) pt, 1), 0).getClass();
                        mv.visitMethodInsn(INVOKESTATIC, bigclaz.getName().replace('.', '/'), "valueOf", "(" + Type.getDescriptor((Class) pt) + ")" + Type.getDescriptor(bigclaz), false);
                    } else {
                        mv.visitVarInsn(ALOAD, insn);
                    }
                    mv.visitInsn(AASTORE);
                }
            }
            mv.visitMethodInsn(INVOKEVIRTUAL, clientName, "remote", "(I[Ljava/lang/Object;)Ljava/lang/Object;", false);
            // mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
            if (method.getGenericReturnType() == void.class) {
                mv.visitInsn(POP);
                mv.visitInsn(RETURN);
            } else {
                Class returnclz = method.getReturnType();
                Class bigPrimitiveClass = returnclz.isPrimitive() ? java.lang.reflect.Array.get(java.lang.reflect.Array.newInstance(returnclz, 1), 0).getClass() : returnclz;
                mv.visitTypeInsn(CHECKCAST, (returnclz.isPrimitive() ? bigPrimitiveClass : returnclz).getName().replace('.', '/'));
                if (returnclz.isPrimitive()) {
                    String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/');
                    try {
                        java.lang.reflect.Method pm = bigPrimitiveClass.getMethod(returnclz.getSimpleName() + "Value");
                        mv.visitMethodInsn(INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false);
                    } catch (Exception ex) {
                        // 不可能会发生
                        throw new RuntimeException(ex);
                    }
                    if (returnclz == long.class) {
                        mv.visitInsn(LRETURN);
                    } else if (returnclz == float.class) {
                        mv.visitInsn(FRETURN);
                    } else if (returnclz == double.class) {
                        mv.visitInsn(DRETURN);
                    } else {
                        mv.visitInsn(IRETURN);
                    }
                } else {
                    mv.visitInsn(ARETURN);
                }
            }
            mv.visitMaxs(20, 20);
            mv.visitEnd();
        }
    }
    cw.visitEnd();
    byte[] bytes = cw.toByteArray();
    Class<?> newClazz = new ClassLoader(loader) {

        public final Class<?> loadClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
        }
    }.loadClass(newDynName.replace('/', '.'), bytes);
    try {
        T rs = (T) newClazz.getDeclaredConstructor().newInstance();
        SncpClient client = new SncpClient(name, serviceTypeOrImplClass, rs, transportFactory, true, realed ? createLocalServiceClass(loader, name, serviceTypeOrImplClass) : serviceTypeOrImplClass, clientAddress);
        client.setRemoteGroups(groups);
        client.setRemoteGroupTransport(transportFactory.loadRemoteTransport(clientAddress, groups));
        {
            Field c = newClazz.getDeclaredField(FIELDPREFIX + "_client");
            c.setAccessible(true);
            c.set(rs, client);
        }
        {
            Field c = newClazz.getDeclaredField(FIELDPREFIX + "_conf");
            c.setAccessible(true);
            c.set(rs, conf);
        }
        transportFactory.addSncpService(rs);
        return rs;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
Also used : MethodDebugVisitor(org.redkale.asm.MethodDebugVisitor) java.lang.reflect(java.lang.reflect) SncpAction(org.redkale.net.sncp.SncpClient.SncpAction) Resource(javax.annotation.Resource) Annotation(java.lang.annotation.Annotation) Type(org.redkale.asm.Type)

Example 15 with Resource

use of javax.annotation.Resource in project syncope by apache.

the class UserDataBinderImpl method update.

@Override
public PropagationByResource update(final User toBeUpdated, final UserPatch userPatch) {
    // Re-merge any pending change from workflow tasks
    User user = userDAO.save(toBeUpdated);
    PropagationByResource propByRes = new PropagationByResource();
    SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
    AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.USER);
    Collection<String> currentResources = userDAO.findAllResourceKeys(user.getKey());
    // fetch connObjectKeys before update
    Map<String, String> oldConnObjectKeys = getConnObjectKeys(user, anyUtils);
    // realm
    setRealm(user, userPatch);
    // password
    if (userPatch.getPassword() != null && StringUtils.isNotBlank(userPatch.getPassword().getValue())) {
        if (userPatch.getPassword().isOnSyncope()) {
            setPassword(user, userPatch.getPassword().getValue(), scce);
            user.setChangePwdDate(new Date());
        }
        propByRes.addAll(ResourceOperation.UPDATE, userPatch.getPassword().getResources());
    }
    // username
    if (userPatch.getUsername() != null && StringUtils.isNotBlank(userPatch.getUsername().getValue())) {
        String oldUsername = user.getUsername();
        user.setUsername(userPatch.getUsername().getValue());
        if (oldUsername.equals(AuthContextUtils.getUsername())) {
            AuthContextUtils.updateUsername(userPatch.getUsername().getValue());
        }
        AccessToken accessToken = accessTokenDAO.findByOwner(oldUsername);
        if (accessToken != null) {
            accessToken.setOwner(userPatch.getUsername().getValue());
            accessTokenDAO.save(accessToken);
        }
        propByRes.addAll(ResourceOperation.UPDATE, currentResources);
    }
    // security question / answer:
    if (userPatch.getSecurityQuestion() != null) {
        if (userPatch.getSecurityQuestion().getValue() == null) {
            user.setSecurityQuestion(null);
            user.setSecurityAnswer(null);
        } else {
            SecurityQuestion securityQuestion = securityQuestionDAO.find(userPatch.getSecurityQuestion().getValue());
            if (securityQuestion != null) {
                user.setSecurityQuestion(securityQuestion);
                user.setSecurityAnswer(userPatch.getSecurityAnswer().getValue());
            }
        }
    }
    if (userPatch.getMustChangePassword() != null) {
        user.setMustChangePassword(userPatch.getMustChangePassword().getValue());
    }
    // roles
    for (StringPatchItem patch : userPatch.getRoles()) {
        Role role = roleDAO.find(patch.getValue());
        if (role == null) {
            LOG.warn("Ignoring unknown role with key {}", patch.getValue());
        } else {
            switch(patch.getOperation()) {
                case ADD_REPLACE:
                    user.add(role);
                    break;
                case DELETE:
                default:
                    user.getRoles().remove(role);
            }
        }
    }
    // attributes and resources
    propByRes.merge(fill(user, userPatch, anyUtils, scce));
    // relationships
    userPatch.getRelationships().stream().filter(patch -> patch.getRelationshipTO() != null).forEachOrdered((patch) -> {
        RelationshipType relationshipType = relationshipTypeDAO.find(patch.getRelationshipTO().getType());
        if (relationshipType == null) {
            LOG.debug("Ignoring invalid relationship type {}", patch.getRelationshipTO().getType());
        } else {
            Optional<? extends URelationship> relationship = user.getRelationship(relationshipType, patch.getRelationshipTO().getOtherEndKey());
            if (relationship.isPresent()) {
                user.getRelationships().remove(relationship.get());
                relationship.get().setLeftEnd(null);
            }
            if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
                AnyObject otherEnd = anyObjectDAO.find(patch.getRelationshipTO().getOtherEndKey());
                if (otherEnd == null) {
                    LOG.debug("Ignoring invalid any object {}", patch.getRelationshipTO().getOtherEndKey());
                } else if (user.getRealm().getFullPath().startsWith(otherEnd.getRealm().getFullPath())) {
                    URelationship newRelationship = entityFactory.newEntity(URelationship.class);
                    newRelationship.setType(relationshipType);
                    newRelationship.setRightEnd(otherEnd);
                    newRelationship.setLeftEnd(user);
                    user.add(newRelationship);
                } else {
                    LOG.error("{} cannot be assigned to {}", otherEnd, user);
                    SyncopeClientException unassignable = SyncopeClientException.build(ClientExceptionType.InvalidRelationship);
                    unassignable.getElements().add("Cannot be assigned: " + otherEnd);
                    scce.addException(unassignable);
                }
            }
        }
    });
    // prepare for membership-related resource management
    Collection<ExternalResource> resources = userDAO.findAllResources(user);
    Map<String, Set<String>> reasons = new HashMap<>();
    user.getResources().forEach(resource -> {
        reasons.put(resource.getKey(), new HashSet<>(Collections.singleton(user.getKey())));
    });
    userDAO.findAllGroupKeys(user).forEach(group -> {
        groupDAO.findAllResourceKeys(group).forEach(resource -> {
            if (!reasons.containsKey(resource)) {
                reasons.put(resource, new HashSet<>());
            }
            reasons.get(resource).add(group);
        });
    });
    Set<String> toBeDeprovisioned = new HashSet<>();
    Set<String> toBeProvisioned = new HashSet<>();
    SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
    // memberships
    userPatch.getMemberships().stream().filter(membPatch -> membPatch.getGroup() != null).forEachOrdered((membPatch) -> {
        Optional<? extends UMembership> membership = user.getMembership(membPatch.getGroup());
        if (membership.isPresent()) {
            user.getMemberships().remove(membership.get());
            membership.get().setLeftEnd(null);
            user.getPlainAttrs(membership.get()).forEach(attr -> {
                user.remove(attr);
                attr.setOwner(null);
                attr.setMembership(null);
            });
            if (membPatch.getOperation() == PatchOperation.DELETE) {
                groupDAO.findAllResourceKeys(membership.get().getRightEnd().getKey()).stream().filter(resource -> reasons.containsKey(resource)).forEach(resource -> {
                    reasons.get(resource).remove(membership.get().getRightEnd().getKey());
                    toBeProvisioned.add(resource);
                });
            }
        }
        if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
            Group group = groupDAO.find(membPatch.getGroup());
            if (group == null) {
                LOG.debug("Ignoring invalid group {}", membPatch.getGroup());
            } else if (user.getRealm().getFullPath().startsWith(group.getRealm().getFullPath())) {
                UMembership newMembership = entityFactory.newEntity(UMembership.class);
                newMembership.setRightEnd(group);
                newMembership.setLeftEnd(user);
                user.add(newMembership);
                membPatch.getPlainAttrs().forEach(attrTO -> {
                    PlainSchema schema = getPlainSchema(attrTO.getSchema());
                    if (schema == null) {
                        LOG.debug("Invalid " + PlainSchema.class.getSimpleName() + "{}, ignoring...", attrTO.getSchema());
                    } else {
                        UPlainAttr attr = user.getPlainAttr(schema.getKey(), newMembership).orElse(null);
                        if (attr == null) {
                            LOG.debug("No plain attribute found for {} and membership of {}", schema, newMembership.getRightEnd());
                            attr = anyUtils.newPlainAttr();
                            attr.setOwner(user);
                            attr.setMembership(newMembership);
                            attr.setSchema(schema);
                            user.add(attr);
                            AttrPatch patch = new AttrPatch.Builder().attrTO(attrTO).build();
                            processAttrPatch(user, patch, schema, attr, anyUtils, resources, propByRes, invalidValues);
                        }
                    }
                });
                if (!invalidValues.isEmpty()) {
                    scce.addException(invalidValues);
                }
                toBeProvisioned.addAll(groupDAO.findAllResourceKeys(group.getKey()));
                // ensure that they are counted for password propagation
                if (toBeUpdated.canDecodePassword()) {
                    if (userPatch.getPassword() == null) {
                        userPatch.setPassword(new PasswordPatch());
                    }
                    group.getResources().stream().filter(resource -> isPasswordMapped(resource)).forEachOrdered(resource -> {
                        userPatch.getPassword().getResources().add(resource.getKey());
                    });
                }
            } else {
                LOG.error("{} cannot be assigned to {}", group, user);
                SyncopeClientException unassignabled = SyncopeClientException.build(ClientExceptionType.InvalidMembership);
                unassignabled.getElements().add("Cannot be assigned: " + group);
                scce.addException(unassignabled);
            }
        }
    });
    // finalize resource management
    reasons.entrySet().stream().filter(entry -> entry.getValue().isEmpty()).forEach(entry -> toBeDeprovisioned.add(entry.getKey()));
    propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
    propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
    // attribute values.
    if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
        currentResources.removeAll(toBeDeprovisioned);
        propByRes.addAll(ResourceOperation.UPDATE, currentResources);
    }
    // check if some connObjectKey was changed by the update above
    Map<String, String> newcCnnObjectKeys = getConnObjectKeys(user, anyUtils);
    oldConnObjectKeys.entrySet().stream().filter(entry -> newcCnnObjectKeys.containsKey(entry.getKey()) && !entry.getValue().equals(newcCnnObjectKeys.get(entry.getKey()))).forEach(entry -> {
        propByRes.addOldConnObjectKey(entry.getKey(), entry.getValue());
        propByRes.add(ResourceOperation.UPDATE, entry.getKey());
    });
    Pair<Set<String>, Set<String>> dynGroupMembs = userDAO.saveAndGetDynGroupMembs(user);
    // finally check if any resource assignment is to be processed due to dynamic group membership change
    dynGroupMembs.getLeft().stream().filter(group -> !dynGroupMembs.getRight().contains(group)).forEach(delete -> {
        groupDAO.find(delete).getResources().stream().filter(resource -> !propByRes.contains(resource.getKey())).forEach(resource -> {
            propByRes.add(ResourceOperation.DELETE, resource.getKey());
        });
    });
    dynGroupMembs.getLeft().stream().filter(group -> dynGroupMembs.getRight().contains(group)).forEach(update -> {
        groupDAO.find(update).getResources().stream().filter(resource -> !propByRes.contains(resource.getKey())).forEach(resource -> {
            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
        });
    });
    dynGroupMembs.getRight().stream().filter(group -> !dynGroupMembs.getLeft().contains(group)).forEach(create -> {
        groupDAO.find(create).getResources().stream().filter(resource -> !propByRes.contains(resource.getKey())).forEach(resource -> {
            propByRes.add(ResourceOperation.CREATE, resource.getKey());
        });
    });
    // Throw composite exception if there is at least one element set in the composing exceptions
    if (scce.hasExceptions()) {
        throw scce;
    }
    return propByRes;
}
Also used : StringPatchItem(org.apache.syncope.common.lib.patch.StringPatchItem) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) SecurityQuestionDAO(org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO) Date(java.util.Date) Realm(org.apache.syncope.core.persistence.api.entity.Realm) Autowired(org.springframework.beans.factory.annotation.Autowired) UserPatch(org.apache.syncope.common.lib.patch.UserPatch) Entity(org.apache.syncope.core.persistence.api.entity.Entity) ResourceOperation(org.apache.syncope.common.lib.types.ResourceOperation) StringUtils(org.apache.commons.lang3.StringUtils) RoleDAO(org.apache.syncope.core.persistence.api.dao.RoleDAO) AnyTypeKind(org.apache.syncope.common.lib.types.AnyTypeKind) Pair(org.apache.commons.lang3.tuple.Pair) Map(java.util.Map) UserDataBinder(org.apache.syncope.core.provisioning.api.data.UserDataBinder) PropagationByResource(org.apache.syncope.core.provisioning.api.PropagationByResource) AuthContextUtils(org.apache.syncope.core.spring.security.AuthContextUtils) Role(org.apache.syncope.core.persistence.api.entity.Role) Collection(java.util.Collection) Resource(javax.annotation.Resource) Set(java.util.Set) Collectors(java.util.stream.Collectors) AnyTypeDAO(org.apache.syncope.core.persistence.api.dao.AnyTypeDAO) List(java.util.List) Provision(org.apache.syncope.core.persistence.api.entity.resource.Provision) AttrPatch(org.apache.syncope.common.lib.patch.AttrPatch) Group(org.apache.syncope.core.persistence.api.entity.group.Group) PlainSchema(org.apache.syncope.core.persistence.api.entity.PlainSchema) Optional(java.util.Optional) ConfDAO(org.apache.syncope.core.persistence.api.dao.ConfDAO) UPlainAttr(org.apache.syncope.core.persistence.api.entity.user.UPlainAttr) AccessToken(org.apache.syncope.core.persistence.api.entity.AccessToken) HashMap(java.util.HashMap) BooleanUtils(org.apache.commons.lang3.BooleanUtils) BeanUtils(org.apache.syncope.core.spring.BeanUtils) URelationship(org.apache.syncope.core.persistence.api.entity.user.URelationship) HashSet(java.util.HashSet) SyncopeClientCompositeException(org.apache.syncope.common.lib.SyncopeClientCompositeException) ClientExceptionType(org.apache.syncope.common.lib.types.ClientExceptionType) UMembership(org.apache.syncope.core.persistence.api.entity.user.UMembership) MembershipTO(org.apache.syncope.common.lib.to.MembershipTO) CipherAlgorithm(org.apache.syncope.common.lib.types.CipherAlgorithm) Encryptor(org.apache.syncope.core.spring.security.Encryptor) AnyObject(org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject) User(org.apache.syncope.core.persistence.api.entity.user.User) AccessTokenDAO(org.apache.syncope.core.persistence.api.dao.AccessTokenDAO) VirSchema(org.apache.syncope.core.persistence.api.entity.VirSchema) ExternalResource(org.apache.syncope.core.persistence.api.entity.resource.ExternalResource) Component(org.springframework.stereotype.Component) PasswordPatch(org.apache.syncope.common.lib.patch.PasswordPatch) PatchOperation(org.apache.syncope.common.lib.types.PatchOperation) RelationshipType(org.apache.syncope.core.persistence.api.entity.RelationshipType) UserTO(org.apache.syncope.common.lib.to.UserTO) AnyUtils(org.apache.syncope.core.persistence.api.entity.AnyUtils) Collections(java.util.Collections) SecurityQuestion(org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion) Transactional(org.springframework.transaction.annotation.Transactional) Group(org.apache.syncope.core.persistence.api.entity.group.Group) User(org.apache.syncope.core.persistence.api.entity.user.User) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) RelationshipType(org.apache.syncope.core.persistence.api.entity.RelationshipType) PropagationByResource(org.apache.syncope.core.provisioning.api.PropagationByResource) SecurityQuestion(org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion) UMembership(org.apache.syncope.core.persistence.api.entity.user.UMembership) AccessToken(org.apache.syncope.core.persistence.api.entity.AccessToken) PlainSchema(org.apache.syncope.core.persistence.api.entity.PlainSchema) UPlainAttr(org.apache.syncope.core.persistence.api.entity.user.UPlainAttr) URelationship(org.apache.syncope.core.persistence.api.entity.user.URelationship) HashSet(java.util.HashSet) SyncopeClientCompositeException(org.apache.syncope.common.lib.SyncopeClientCompositeException) PasswordPatch(org.apache.syncope.common.lib.patch.PasswordPatch) SyncopeClientException(org.apache.syncope.common.lib.SyncopeClientException) ExternalResource(org.apache.syncope.core.persistence.api.entity.resource.ExternalResource) Date(java.util.Date) AttrPatch(org.apache.syncope.common.lib.patch.AttrPatch) Role(org.apache.syncope.core.persistence.api.entity.Role) AnyObject(org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject) StringPatchItem(org.apache.syncope.common.lib.patch.StringPatchItem) AnyUtils(org.apache.syncope.core.persistence.api.entity.AnyUtils)

Aggregations

Resource (javax.annotation.Resource)56 Collectors (java.util.stream.Collectors)22 Set (java.util.Set)20 List (java.util.List)18 Subject (alien4cloud.security.Subject)17 Sets (com.google.common.collect.Sets)17 Arrays (java.util.Arrays)17 ArrayUtils (org.apache.commons.lang3.ArrayUtils)15 IGenericSearchDAO (alien4cloud.dao.IGenericSearchDAO)14 ApplicationEnvironmentService (alien4cloud.application.ApplicationEnvironmentService)12 ApplicationEnvironment (alien4cloud.model.application.ApplicationEnvironment)12 Audit (alien4cloud.audit.annotation.Audit)11 ResourcePermissionService (alien4cloud.authorization.ResourcePermissionService)11 RestResponse (alien4cloud.rest.model.RestResponse)11 RestResponseBuilder (alien4cloud.rest.model.RestResponseBuilder)11 ApplicationEnvironmentAuthorizationUpdateRequest (alien4cloud.rest.orchestrator.model.ApplicationEnvironmentAuthorizationUpdateRequest)11 ApiOperation (io.swagger.annotations.ApiOperation)11 IOException (java.io.IOException)11 MediaType (org.springframework.http.MediaType)11 PreAuthorize (org.springframework.security.access.prepost.PreAuthorize)11