001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.betwixt.strategy;
018
019 import java.util.Iterator;
020 import java.util.Map;
021
022 import org.apache.commons.betwixt.ElementDescriptor;
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025
026 /**
027 * A default implementation of the plural name stemmer which
028 * tests for some common english plural/singular patterns and
029 * then uses a simple starts-with algorithm
030 *
031 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
032 * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
033 * @version $Revision: 438373 $
034 */
035 public class DefaultPluralStemmer implements PluralStemmer {
036
037 /** Log used for logging (Doh!) */
038 protected static Log log = LogFactory.getLog( DefaultPluralStemmer.class );
039
040 /**
041 * <p>Algorithm supports common english plural patterns.</p>
042 *
043 * <p>First, common english plural constructions will be tried.
044 * If the property doesn't end with <code>'y'</code> then this method will look for
045 * a property with which has <code>'es'</code> appended.
046 * If the property ends with <code>'y'</code> then a property with the <code>'y'</code>
047 * replaced by <code>'ies'</code> will be searched for.</p>
048 *
049 * <p>If no matches are found then - if one exists - a property starting with the
050 * singular name will be returned.</p>
051 *
052 * @param propertyName the property name string to match
053 * @param map the <code>Map</code> containing the <code>ElementDescriptor</code>'s
054 * to be searched
055 * @return The plural descriptor for the given singular property name.
056 * If more than one descriptor matches, then the best match is returned.
057 */
058 public ElementDescriptor findPluralDescriptor( String propertyName, Map map ) {
059 int foundKeyCount = 0;
060 String keyFound = null;
061 ElementDescriptor answer = (ElementDescriptor) map.get( propertyName + "s" );
062
063 if ( answer == null && !propertyName.endsWith( "y" )) {
064 answer = (ElementDescriptor) map.get( propertyName + "es" );
065 }
066
067 if ( answer == null ) {
068 int length = propertyName.length();
069 if ( propertyName.endsWith( "y" ) && length > 1 ) {
070 String key = propertyName.substring(0, length - 1) + "ies";
071 answer = (ElementDescriptor) map.get( key );
072 }
073
074 if ( answer == null ) {
075 // lets find the first one that starts with the propertyName
076 for ( Iterator iter = map.keySet().iterator(); iter.hasNext(); ) {
077 String key = (String) iter.next();
078 if ( key.startsWith( propertyName ) ) {
079 if (answer == null) {
080 answer = (ElementDescriptor) map.get(key);
081 if (key.equals(propertyName)) {
082 // we found the best match..
083 break;
084 }
085 foundKeyCount++;
086 keyFound = key;
087
088 } else {
089 // check if we have a better match,,
090 if (keyFound.length() > key.length()) {
091 answer = (ElementDescriptor) map.get(key);
092 keyFound = key;
093 }
094 foundKeyCount++;
095
096 }
097 }
098 }
099 }
100 }
101 if (foundKeyCount > 1) {
102 log.warn("More than one type matches, using closest match "+answer.getQualifiedName());
103 }
104 return answer;
105
106 }
107 }