package rocks.inspectit.server.instrumentation.classcache; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.concurrent.Callable; import org.apache.commons.collections.CollectionUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import rocks.inspectit.server.instrumentation.classcache.index.FqnIndexer; import rocks.inspectit.server.instrumentation.classcache.index.HashIndexer; import rocks.inspectit.shared.all.instrumentation.classcache.ImmutableAnnotationType; import rocks.inspectit.shared.all.instrumentation.classcache.ImmutableClassType; import rocks.inspectit.shared.all.instrumentation.classcache.ImmutableInterfaceType; import rocks.inspectit.shared.all.instrumentation.classcache.ImmutableType; import rocks.inspectit.shared.all.instrumentation.classcache.Type; import rocks.inspectit.shared.all.pattern.IMatchPattern; import rocks.inspectit.shared.all.pattern.PatternFactory; import rocks.inspectit.shared.all.spring.logger.Log; /** * Lookup service for the {@link ClassCache}. * * @author Ivan Senic * */ @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Lazy public class ClassCacheLookup { /** * Log of the class. */ @Log Logger log; /** * Indexer to help searching with the fully qualified class name and wild-cards. */ @Autowired private FqnIndexer<Type> fqnIndexer; /** * Indexer for that hash code and types. */ @Autowired private HashIndexer hashIndexer; /** * {@link ClassCache} lookup belongs to. */ private ClassCache classcache; /** * Init the {@link ClassCacheLookup}. * * @param classcache * {@link ClassCache} it belongs to. */ public void init(ClassCache classcache) { this.classcache = classcache; classcache.registerNodeChangeListener(fqnIndexer); classcache.registerNodeChangeListener(hashIndexer); } /** * Finds {@link ImmutableType} by the exact fully qualified name of the type. * * @param fqn * Fully qualified name of the type * @return Found type or <code>null</code> if one does not exists. */ public ImmutableType findByFQN(final String fqn) { try { return classcache.executeWithReadLock(new Callable<ImmutableType>() { @Override public ImmutableType call() throws Exception { return fqnIndexer.lookup(fqn); } }); } catch (Exception e) { log.warn("Unexpected exception occurred during read from the FQN indexer", e); return null; } } /** * Finds {@link ImmutableType} by the hash value of the type. * * @param hash * Type hash * @return Found type or <code>null</code> if one does not exists. */ public ImmutableType findByHash(final String hash) { try { return classcache.executeWithReadLock(new Callable<ImmutableType>() { @Override public ImmutableType call() throws Exception { return hashIndexer.lookup(hash); } }); } catch (Exception e) { log.warn("Unexpected exception occurred during read from the Hash indexer", e); return null; } } /** * Returns all {@link ImmutableType}s from the FQN indexer. * * @return Returns all {@link ImmutableType}s from the FQN indexer. */ public Collection<? extends ImmutableType> findAll() { try { return classcache.executeWithReadLock(new Callable<Collection<Type>>() { @Override public Collection<Type> call() throws Exception { return fqnIndexer.findAll(); } }); } catch (Exception e) { log.warn("Unexpected exception occurred during read from the FQN indexer", e); return Collections.emptyList(); } } /** * Returns all {@link ImmutableType}s from the FQN indexer that apply for the given pattern. * Pattern can be with wild cards. * * @param fqnPattern * FQN pattern that can be complete FQN or pattern with wild cards (*). * @param onlyInitialized * Include only initialized types. * @return Returns all {@link ImmutableType}s from the FQN indexer that apply for the given * pattern. Patter can be with wild cards. */ public Collection<? extends ImmutableType> findByPattern(final String fqnPattern, boolean onlyInitialized) { try { final IMatchPattern pattern = PatternFactory.getPattern(fqnPattern); Collection<? extends ImmutableType> results = classcache.executeWithReadLock(new Callable<Collection<Type>>() { @Override public Collection<Type> call() throws Exception { return fqnIndexer.findByPattern(pattern); } }); for (Iterator<? extends ImmutableType> it = results.iterator(); it.hasNext();) { ImmutableType immutableType = it.next(); if (onlyInitialized && !immutableType.isInitialized()) { it.remove(); } } return results; } catch (Exception e) { log.warn("Unexpected exception occurred during read from the FQN indexer", e); return Collections.emptyList(); } } /** * Returns all {@link ImmutableClassType} from the FQN indexer that apply for the given pattern. * Pattern can be with wild cards. * * @param fqnPattern * FQN pattern that can be complete FQN or pattern with wild cards (*). * @param onlyInitialized * Include only initialized types. * @return Returns all {@link ImmutableClassType}s from the FQN indexer that apply for the given * pattern. Patter can be with wild cards. */ public Collection<? extends ImmutableClassType> findClassTypesByPattern(String fqnPattern, boolean onlyInitialized) { // first search for all Collection<? extends ImmutableType> results = findByPattern(fqnPattern, onlyInitialized); // if empty return if (CollectionUtils.isEmpty(results)) { return Collections.emptyList(); } // otherwise filter only for classes Collection<ImmutableClassType> classTypes = new ArrayList<>(); for (ImmutableType immutableType : results) { if (immutableType.isClass()) { classTypes.add(immutableType.castToClass()); } } return classTypes; } /** * Returns all {@link ImmutableInterfaceType} from the FQN indexer that apply for the given * pattern. Pattern can be with wild cards. * * @param fqnPattern * FQN pattern that can be complete FQN or pattern with wild cards (*). * @param onlyInitialized * Include only initialized types. * @return Returns all {@link ImmutableInterfaceType}s from the FQN indexer that apply for the * given pattern. Patter can be with wild cards. */ public Collection<? extends ImmutableInterfaceType> findInterfaceTypesByPattern(String fqnPattern, boolean onlyInitialized) { // first search for all Collection<? extends ImmutableType> results = findByPattern(fqnPattern, onlyInitialized); // if empty return if (CollectionUtils.isEmpty(results)) { return Collections.emptyList(); } // otherwise filter only for classes Collection<ImmutableInterfaceType> interfaceTypes = new ArrayList<>(); for (ImmutableType immutableType : results) { if (immutableType.isInterface()) { interfaceTypes.add(immutableType.castToInterface()); } } return interfaceTypes; } /** * Returns all {@link ImmutableAnnotationType} from the FQN indexer that apply for the given * pattern. Pattern can be with wild cards. * * @param fqnPattern * FQN pattern that can be complete FQN or pattern with wild cards (*). * @param onlyInitialized * Include only initialized types. * @return Returns all {@link ImmutableAnnotationType}s from the FQN indexer that apply for the * given pattern. Patter can be with wild cards. */ public Collection<? extends ImmutableAnnotationType> findAnnotationTypesByPattern(String fqnPattern, boolean onlyInitialized) { // first search for all Collection<? extends ImmutableType> results = findByPattern(fqnPattern, onlyInitialized); // if empty return if (CollectionUtils.isEmpty(results)) { return Collections.emptyList(); } // otherwise filter only for classes Collection<ImmutableAnnotationType> annotationTypes = new ArrayList<>(); for (ImmutableType immutableType : results) { if (immutableType.isAnnotation()) { annotationTypes.add(immutableType.castToAnnotation()); } } return annotationTypes; } /** * Returns all {@link ImmutableClassType} that are exceptions from the FQN indexer and that * apply for the given pattern. Pattern can be with wild cards. * * @param fqnPattern * FQN pattern that can be complete FQN or pattern with wild cards (*). * @param onlyInitialized * Include only initialized types. * @return Returns all {@link ImmutableClassType}s that are exceptions from the FQN indexer and * that apply for the given pattern. Patter can be with wild cards. */ public Collection<? extends ImmutableClassType> findExceptionTypesByPattern(String fqnPattern, boolean onlyInitialized) { // first search for all Collection<? extends ImmutableType> results = findByPattern(fqnPattern, onlyInitialized); // if empty return if (CollectionUtils.isEmpty(results)) { return Collections.emptyList(); } // otherwise filter only for classes Collection<ImmutableClassType> exceptionTypes = new ArrayList<>(); for (ImmutableType immutableType : results) { if (immutableType.isClass()) { ImmutableClassType immutableClassType = immutableType.castToClass(); if (immutableClassType.isException()) { exceptionTypes.add(immutableClassType); } } } return exceptionTypes; } /** * Returns all {@link ImmutableType}s which are instrumented. * * @return Collection containing {@link ImmutableType}s. */ public Collection<? extends ImmutableType> findInstrumentedTypes() { try { return classcache.executeWithReadLock(new Callable<Collection<ImmutableType>>() { @Override public Collection<ImmutableType> call() throws Exception { Collection<ImmutableType> result = new ArrayList<>(); for (ImmutableType type : fqnIndexer.findAll()) { if (type.isClass() && type.isInitialized()) { if (type.castToClass().hasInstrumentationPoints()) { result.add(type); } } } return result; } }); } catch (Exception e) { log.warn("Unexpected exception occurred during read from the FQN indexer", e); return Collections.emptyList(); } } }