// Copyright (c) 2006 - 2008, Markus Strauch. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. package net.sf.sdedit.util; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Utility class for matching strings against regular expressions and accessing * substrings that match groups of the regular expression. * * @author Markus Strauch * */ public final class Grep { private Grep() { /* there are no Grep instances */ } private static final Map<String, Pattern> patternCache = new HashMap<String, Pattern>(); private static final Map<Class<?>, Map<String, PropertyDescriptor>> descriptorCache = new HashMap<Class<?>, Map<String, PropertyDescriptor>>(); /** * Matches a string against a regular expression and returns an array of the * substrings corresponding to the groups of the regular expression, or * <tt>null</tt>, if the string does not match the regular expression. * * @param regexp * a regular expression * @param string * a string * @return an array of the substrings corresponding to the groups of the * regular expression, or <tt>null</tt>, if the string does not * match the regular expression */ public static String[] parse(final String regexp, final String string) { //final String escaped = Escaper.escape(string); Pattern pattern = patternCache.get(regexp); if (pattern == null) { pattern = Pattern.compile(regexp); patternCache.put(regexp, pattern); } final Matcher matcher = pattern.matcher(string); if (!matcher.matches()) { return null; } final String[] groups = new String[matcher.groupCount()]; for (int i = 0; i < groups.length; i++) { groups[i] = unescape(matcher.group(i + 1)); } return groups; } private static final String unescape (String string) { if (string == null) { return null; } StringBuffer unescaped = new StringBuffer (); int state = 0; for (int i = 0; i < string.length(); i++) { char c = string.charAt(i); switch (state) { case 0: if (c != '\\') { unescaped.append(c); } else { state = 1; } break; case 1: unescaped.append(c); state = 0; break; default: } } if (state == 1) { unescaped.append('\\'); } return unescaped.toString(); } /** * Matches a string against a regular expression and uses the resulting * groups (corresponding to portions of the regular expression between * braces) for setting properties of a bean. The write method for the i-th * property is called with an object of the write method's parameter type, * that object is created by calling the type's string constructor with the * string of the i-th group. * * @param bean * a bean * @param regexp * a regular expression * @param string * a string to match the regular expression against * @param properties * names of properties of the bean * @return true if the string matched and if the properties could be set * @throws IntrospectionException * if the bean could not be introspected */ public static boolean parseAndSetProperties(final Object bean, final String regexp, final String string, final String... properties) throws IntrospectionException { final String[] parsed = parse(regexp, string); if (parsed == null) { return false; } if (properties.length != parsed.length) { throw new IllegalArgumentException("number of groups does not" + " match number of properties"); } Map<String, PropertyDescriptor> descriptors = descriptorCache.get(bean.getClass()); if (descriptors == null) { BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass()); descriptors = new HashMap<String, PropertyDescriptor>(); for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) { if (descriptor.getWriteMethod() != null) { descriptors.put(descriptor.getName(), descriptor); } } descriptorCache.put(bean.getClass(), descriptors); } for (int i = 0; i < properties.length; i++) { final PropertyDescriptor pd = descriptors.get(properties[i]); if (pd == null) { throw new IllegalArgumentException("property " + properties[i] + " does not exist"); } final Object value = ObjectFactory.createFromString(pd.getPropertyType(), parsed[i]); try { pd.getWriteMethod().invoke(bean, value); } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException("cannot write property " + properties[i]); } } return true; } }