/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.felix.ipojo.manipulator.spi.helper; import org.apache.felix.ipojo.manipulator.spi.BindingContext; import org.apache.felix.ipojo.manipulator.spi.Predicate; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.MethodNode; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.regex.Pattern; /** * Ready-to-use {@link Predicate} implementations. * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class Predicates { public static Node node() { return new Node(); } public static Reference reference(String refId) { return new Reference(refId); } public static Matcher pattern(String regex) { return new Matcher(regex); } /** * Restrict to the given {@link ElementType}. * @param type expected {@link ElementType} */ public static Predicate on(final ElementType type) { return new Predicate() { public boolean matches(BindingContext context) { return context.getElementType().equals(type); } }; } /** * Always return {@literal true}. */ public static Predicate alwaysTrue() { return new Predicate() { public boolean matches(BindingContext context) { return true; } }; } /** * Successful if all given predicates are satisfied. * @param predicates predicates to be satisfied */ public static Predicate and(final Predicate... predicates) { // Optimization if (predicates.length == 1) { return predicates[0]; } return new Predicate() { public boolean matches(BindingContext context) { for (Predicate predicate : predicates) { // Quit with first failure if (!predicate.matches(context)) { return false; } } return true; } }; } /** * Successful if at least one of the given predicates is satisfied. * @param predicates predicates to be satisfied (at least one) */ public static Predicate or(final Collection<Predicate> predicates) { // Optimization if (predicates.size() == 1) { return predicates.iterator().next(); } return new Predicate() { public boolean matches(BindingContext context) { for (Predicate predicate : predicates) { // Quit with first success if (predicate.matches(context)) { return true; } } // No predicate were matching return false; } }; } /** * Successful if at least one of the given predicates is satisfied. * @param predicates predicates to be satisfied (at least one) */ public static Predicate or(final Predicate... predicates) { return or(Arrays.asList(predicates)); } /** * Restrict to the supported {@link ElementType}(s) of the annotation (use the @Target, if provided). * @param annotationType annotation to explore */ public static Predicate onlySupportedElements(final Class<? extends Annotation> annotationType) { Target target = annotationType.getAnnotation(Target.class); if (target == null) { return alwaysTrue(); } Collection<Predicate> supportedTypes = new HashSet<Predicate>(); for (ElementType type : target.value()) { supportedTypes.add(on(type)); } return or(supportedTypes); } public static class Reference { private String refId; public Reference(String refId) { this.refId = refId; } /** * Restrict execution if the {@link org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench} * contains the given reference's name. */ public Predicate exists() { return new Predicate() { public boolean matches(BindingContext context) { return context.getWorkbench().getIds().containsKey(refId); } }; } } public static class Matcher { private Pattern pattern; public Matcher(String regex) { pattern = Pattern.compile(regex); } /** * Restrict execution if the annotation's classname matches the given pattern. */ public Predicate matches() { return new Predicate() { public boolean matches(BindingContext context) { return pattern.matcher(context.getAnnotationType().getClassName()).matches(); } }; } } public static class Node { /** * Restrict execution if the supported {@literal Node} has the given name. */ public Predicate named(final String expected) { return new Predicate() { public boolean matches(BindingContext context) { if (context.getFieldNode() != null) { FieldNode field = context.getFieldNode(); return field.name.equals(expected); } if (context.getMethodNode() != null) { MethodNode method = context.getMethodNode(); return method.name.equals(expected); } if (context.getClassNode() != null) { ClassNode clazz = context.getClassNode(); return clazz.name.equals(expected); } // Parameters have no name in bytecode return false; } }; } } }