| /* |
| * 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.dm.annotation.plugin.bnd; |
| |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Class containings pattern matching helper methods. |
| * |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class Patterns |
| { |
| // Pattern used to check if a method is void and does not take any params |
| public final static Pattern VOID = Pattern.compile("\\(\\)V"); |
| |
| // Pattern used to check if a method returns an array of Objects |
| public final static Pattern COMPOSITION = Pattern.compile("\\(\\)\\[Ljava/lang/Object;"); |
| |
| // Pattern used to parse service type from "bind(Component, ServiceReference, Service)" signature |
| public final static Pattern BIND_CLASS1 = Pattern.compile("\\((Lorg/apache/felix/dm/Component;)(Lorg/osgi/framework/ServiceReference;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(Component, Service)" signature |
| public final static Pattern BIND_CLASS2 = Pattern.compile("\\((Lorg/apache/felix/dm/Component;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(Component, Map, Service)" signature |
| public final static Pattern BIND_CLASS3 = Pattern.compile("\\((Lorg/apache/felix/dm/Component;)(Ljava/util/Map;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(ServiceReference, Service)" signature |
| public final static Pattern BIND_CLASS4 = Pattern.compile("\\((Lorg/osgi/framework/ServiceReference;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(Service)" signature |
| public final static Pattern BIND_CLASS5 = Pattern.compile("\\(L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(Service, Map)" signature |
| public final static Pattern BIND_CLASS6 = Pattern.compile("\\(L([^;]+);(Ljava/util/Map;)\\)V"); |
| |
| // Pattern used to parse service type from "bind(Map, Service)" signature |
| public final static Pattern BIND_CLASS7 = Pattern.compile("\\((Ljava/util/Map;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse service type from "bind(Service, Dictionary)" signature |
| public final static Pattern BIND_CLASS8 = Pattern.compile("\\(L([^;]+);(Ljava/util/Dictionary;)\\)V"); |
| |
| // Pattern used to parse service type from "bind(Dictionary, Service)" signature |
| public final static Pattern BIND_CLASS9 = Pattern.compile("\\((Ljava/util/Dictionary;)L([^;]+);\\)V"); |
| |
| // Pattern used to parse classes from class descriptors; |
| public final static Pattern CLASS = Pattern.compile("L([^;]+);"); |
| |
| // Pattern used to parse the field on which a Publisher annotation may be applied on |
| public final static Pattern RUNNABLE = Pattern.compile("Ljava/lang/Runnable;"); |
| |
| // Pattern used to parse a field whose type is BundleContext |
| public final static Pattern BUNDLE_CONTEXT = Pattern.compile("Lorg/osgi/framework/BundleContext;"); |
| |
| // Pattern used to parse a field whose type is BundleContext |
| public final static Pattern BUNDLE = Pattern.compile("Lorg/osgi/framework/Bundle;"); |
| |
| // Pattern used to parse a field whose type is DependencyManager |
| public final static Pattern DEPENDENCY_MANAGER = Pattern.compile("Lorg/apache/felix/dm/DependencyManager;"); |
| |
| // Pattern used to parse a field whose type is Component |
| public final static Pattern COMPONENT = Pattern.compile("Lorg/apache/felix/dm/Component;"); |
| |
| // Pattern used to parse a field whose type is ServiceRegistration |
| public final static Pattern SERVICE_REGISTRATION = Pattern.compile("Lorg/osgi/framework/ServiceRegistration;"); |
| |
| // Pattern used to check if a method returns a Map |
| public final static Pattern METHOD_RETURN_MAP = Pattern.compile("\\(\\)Ljava/util/Map;"); |
| |
| // Pattern to detect a configuration updated callback without any config types, like for instance: |
| // updated(Dictionary) |
| // updated(Component, Dictionary) |
| public final static Pattern UPDATED_NO_CONFIG_TYPES = Pattern.compile |
| ("\\(((Ljava/util/Dictionary;)|(Lorg/apache/felix/dm/Component;Ljava/util/Dictionary;))\\)V"); |
| |
| // Pattern to detect a configuration updated callback with some config types, like for instance: |
| // updated(ConfigType1, ConfigType2, ...) |
| // updated(Dictionary, ConfigType1, ConfigType2, ...) |
| // updated(Component, Dictionary, ConfigType1, ConfigType2, ...) |
| public final static Pattern UPDATED_CONFIG_TYPES = Pattern.compile |
| ("((Ljava/util/Dictionary;)|(Lorg/apache/felix/dm/Component;)|(L([^;]+);))"); |
| |
| // Pattern to detect a service dependency type from a method which accepts as argument |
| // a ServiceReference<T> or a ServiceObject<T> |
| static final Pattern GENERIC_TYPES = Pattern.compile( |
| "\\(((Lorg/osgi/framework/ServiceReference;)|(Lorg/osgi/framework/ServiceObjects;))+\\)(V)"); |
| |
| /** |
| * Infer service dependency type from a bind method accepting a ServiceReference or a ServiceObject parameter |
| * @param m_logger |
| */ |
| public static String inferTypeFromGenericType(String methodDescriptor, String signature, Logger m_logger) { |
| String inferredService = null; |
| String plainType = null; |
| Matcher m = GENERIC_TYPES.matcher(methodDescriptor); |
| |
| if (m.matches()) { |
| if (m.group(2) != null) { |
| plainType = "Lorg/osgi/framework/ServiceReference<"; |
| } else if (m.group(3) != null) { |
| plainType = "Lorg/osgi/framework/ServiceObjects<"; |
| } |
| } |
| |
| if (inferredService == null && signature != null && plainType != null) { |
| int start = signature.indexOf(plainType); |
| if (start > -1) { |
| start += plainType.length(); |
| String[] sigs = signature.substring(start).split("[<;>]"); |
| if (sigs.length > 0) { |
| String sig = sigs[0]; |
| if (sig.startsWith("-")) { |
| inferredService = Object.class.getName(); |
| } else { |
| int index = sig.startsWith("+") ? 2 : 1; |
| inferredService = sig.substring(index).replace('/', '.'); |
| } |
| } |
| } |
| } |
| |
| m_logger.debug("inferTypeFromGenericType: methodDescriptor=%s, signature=%s, plainType=%s, inferred service=%s", |
| methodDescriptor, signature, plainType, inferredService); |
| |
| return inferredService; |
| } |
| |
| /** |
| * Parses a class. |
| * @param clazz the class to be parsed (the package is "/" separated). |
| * @param pattern the pattern used to match the class. |
| * @param group the pattern group index where the class can be retrieved. |
| * @return the parsed class. |
| */ |
| public static String parseClass(String clazz, Pattern pattern, int group) |
| { |
| return parseClass(clazz, pattern, group, true); |
| } |
| |
| /** |
| * Parses a class. |
| * @param clazz the class to be parsed (the package is "/" separated). |
| * @param pattern the pattern used to match the class. |
| * @param group the pattern group index where the class can be retrieved. |
| * @param throwException true if an Exception must be thrown in case the clazz does not match the pattern. |
| * @return the parsed class. |
| */ |
| public static String parseClass(String clazz, Pattern pattern, int group, boolean throwException) |
| { |
| Matcher matcher = pattern.matcher(clazz); |
| if (matcher.matches()) |
| { |
| return matcher.group(group).replace("/", "."); |
| } |
| else if (throwException) |
| { |
| throw new IllegalArgumentException("Invalid class descriptor: " + clazz); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Checks if a method descriptor matches a given pattern. |
| * @param the method whose signature descriptor is checked |
| * @param pattern the pattern used to check the method signature descriptor |
| * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern. |
| */ |
| public static void parseMethod(String method, String descriptor, Pattern pattern) |
| { |
| Matcher matcher = pattern.matcher(descriptor); |
| if (!matcher.matches()) |
| { |
| throw new IllegalArgumentException("Invalid method " + method + ", wrong signature: " |
| + descriptor); |
| } |
| } |
| |
| /** |
| * Checks if a field descriptor matches a given pattern. |
| * @param field the field whose type descriptor is checked |
| * @param descriptor the field descriptor to be checked |
| * @param pattern the pattern to use |
| * @throws IllegalArgumentException if the method signature descriptor does not match the given pattern. |
| */ |
| public static void parseField(String field, String descriptor, Pattern pattern) { |
| Matcher matcher = pattern.matcher(descriptor); |
| if (!matcher.matches()) |
| { |
| throw new IllegalArgumentException("Invalid field " + field + ", wrong signature: " |
| + descriptor); |
| } |
| } |
| } |