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

org.apache.commons.javaflow.providers.asm3.IContinuableClassInfoResolver Maven / Gradle / Ivy

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

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;

import org.apache.commons.javaflow.spi.ClassMatcher;
import org.apache.commons.javaflow.spi.ResourceLoader;

class IContinuableClassInfoResolver implements ContinuableClassInfoResolver {
    private final Map visitedClasses = new HashMap();
    private final Set processedAnnotations = new HashSet();
    private final Set continuableAnnotations = new HashSet();
    private final Set refreshClasses = new HashSet();
    private final ResourceLoader resourceLoader;
    private final SharedContinuableClassInfos cciShared;
    
    IContinuableClassInfoResolver(ResourceLoader resourceLoader, SharedContinuableClassInfos cciShared) {
        this.resourceLoader = resourceLoader;
        this.cciShared = cciShared;
    }

    public IContinuableClassInfo resolve(String classInternalName) throws IOException {
        IContinuableClassInfo classInfo = getResolved(classInternalName);
        if (classInfo == null) {
            InputStream classBytes = resourceLoader.getResourceAsStream(classInternalName + ".class");
            try {
                return resolveContinuableClassInfo(classInternalName, new ClassReader(classBytes));
            } finally {
                if (null != classBytes) {
                    try { classBytes.close(); } catch (IOException exIgnore) {}
                }
            }
        } else {
            return unmask(classInfo);
        } 
    }
    
    public boolean isContinuableAnnotation(String annotationClassDescriptor) {
        switch (getAnnotationProcessingState(annotationClassDescriptor)) {
            case SUPPORTED:
                return true;
            case UNSUPPORTED:
                return false;
            case UNKNON:
                markProcessedAnnotation(annotationClassDescriptor);
    
                final Type type = Type.getType(annotationClassDescriptor);
                try {
                    InputStream annotationBytes= resourceLoader.getResourceAsStream(type.getInternalName() + ".class");
                    try {
                        return resolveContinuableAnnotation(annotationClassDescriptor, new ClassReader(annotationBytes));
                    } finally {
                        if (null != annotationBytes) {
                            try { annotationBytes.close(); } catch (IOException exIgnore) {}
                        }
                    }
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            default:
                throw new RuntimeException("Unknown annotation kind");
        }
    }
    
    public void release() {
        cciShared.mergeWith(visitedClasses, processedAnnotations, continuableAnnotations);
    }
    
    public void reset(Collection classNames) {
        visitedClasses.keySet().removeAll(classNames);
        refreshClasses.addAll(classNames);
    }
    
    IContinuableClassInfo resolve(String classInternalName, byte[] classBytes) {
        IContinuableClassInfo classInfo = getResolved(classInternalName);
        if (classInfo == null) {
            return resolveContinuableClassInfo(classInternalName, new ClassReader(classBytes));
        } else {
            return unmask(classInfo);
        }
    }
    
    ClassMatcher veto() {
        return cciShared.veto();
    }
    
    private IContinuableClassInfo getResolved(String classInternalName) {
        if (refreshClasses.contains(classInternalName)) {
            return null;
        }
        IContinuableClassInfo result;
        
        result = visitedClasses.get(classInternalName);
        if (null != result) {
            return result;
        }
        
        result = cciShared.getResolved(classInternalName);
        if (null != result) {
            return result;
        }
        
        return null;
    }

    private IContinuableClassInfo resolveContinuableClassInfo(String classInternalName, ClassReader reader) {
        MaybeContinuableClassVisitor maybeContinuableClassVisitor = new MaybeContinuableClassVisitor(this); 
        reader.accept(maybeContinuableClassVisitor, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);

        IContinuableClassInfo classInfo = maybeContinuableClassVisitor.toContinuableClassInfo();
        visitedClasses.put(classInternalName, null != classInfo ? classInfo : UNSUPPORTED_CLASS_INFO);
        refreshClasses.remove(classInternalName);
        return classInfo;
    }

    private boolean resolveContinuableAnnotation(String annotationClassDescriptor, ClassReader reader) {
        MaybeContinuableAnnotationVisitor maybeContinuableAnnotationVisitor = new MaybeContinuableAnnotationVisitor(this); 
        reader.accept(
            maybeContinuableAnnotationVisitor, 
            ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG
        );

        if (maybeContinuableAnnotationVisitor.isContinuable()) {
            markContinuableAnnotation(annotationClassDescriptor);
            return true;
        } else {
            return false;
        }
    }

    private AnnotationProcessingState getAnnotationProcessingState(String annotationClassDescriptor) {
        // Check already resolved shared state first
        if (cciShared.isContinuableAnnotation(annotationClassDescriptor)) {
            return AnnotationProcessingState.SUPPORTED;
        } else if (cciShared.isProcessedAnnotation(annotationClassDescriptor)) {
            return AnnotationProcessingState.UNSUPPORTED;
        }

        // Now check own state
        if (continuableAnnotations.contains(annotationClassDescriptor))
            return AnnotationProcessingState.SUPPORTED;
        else if (processedAnnotations.contains(annotationClassDescriptor))
            return AnnotationProcessingState.UNSUPPORTED;
        else
            return AnnotationProcessingState.UNKNON;
    }

    private void markProcessedAnnotation(String annotationClassDescriptor) {
        processedAnnotations.add(annotationClassDescriptor);
    }

    private void markContinuableAnnotation(String annotationClassDescriptor) {
        markProcessedAnnotation(annotationClassDescriptor);
        continuableAnnotations.add(annotationClassDescriptor);
    }

    private static IContinuableClassInfo unmask(IContinuableClassInfo classInfo) {
        return classInfo == UNSUPPORTED_CLASS_INFO ? null : classInfo;
    }
    
    private static final IContinuableClassInfo UNSUPPORTED_CLASS_INFO = 
        new IContinuableClassInfo(true, Collections.emptySet());
    
    private static enum AnnotationProcessingState {
        UNKNON, UNSUPPORTED, SUPPORTED;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy