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
039: .getLog(DefaultPluralStemmer.class);
040:
041: /**
042: * <p>Algorithm supports common english plural patterns.</p>
043: *
044: * <p>First, common english plural constructions will be tried.
045: * If the property doesn't end with <code>'y'</code> then this method will look for
046: * a property with which has <code>'es'</code> appended.
047: * If the property ends with <code>'y'</code> then a property with the <code>'y'</code>
048: * replaced by <code>'ies'</code> will be searched for.</p>
049: *
050: * <p>If no matches are found then - if one exists - a property starting with the
051: * singular name will be returned.</p>
052: *
053: * @param propertyName the property name string to match
054: * @param map the <code>Map</code> containing the <code>ElementDescriptor</code>'s
055: * to be searched
056: * @return The plural descriptor for the given singular property name.
057: * If more than one descriptor matches, then the best match is returned.
058: */
059: public ElementDescriptor findPluralDescriptor(String propertyName,
060: Map map) {
061: int foundKeyCount = 0;
062: String keyFound = null;
063: ElementDescriptor answer = (ElementDescriptor) map
064: .get(propertyName + "s");
065:
066: if (answer == null && !propertyName.endsWith("y")) {
067: answer = (ElementDescriptor) map.get(propertyName + "es");
068: }
069:
070: if (answer == null) {
071: int length = propertyName.length();
072: if (propertyName.endsWith("y") && length > 1) {
073: String key = propertyName.substring(0, length - 1)
074: + "ies";
075: answer = (ElementDescriptor) map.get(key);
076: }
077:
078: if (answer == null) {
079: // lets find the first one that starts with the propertyName
080: for (Iterator iter = map.keySet().iterator(); iter
081: .hasNext();) {
082: String key = (String) iter.next();
083: if (key.startsWith(propertyName)) {
084: if (answer == null) {
085: answer = (ElementDescriptor) map.get(key);
086: if (key.equals(propertyName)) {
087: // we found the best match..
088: break;
089: }
090: foundKeyCount++;
091: keyFound = key;
092:
093: } else {
094: // check if we have a better match,,
095: if (keyFound.length() > key.length()) {
096: answer = (ElementDescriptor) map
097: .get(key);
098: keyFound = key;
099: }
100: foundKeyCount++;
101:
102: }
103: }
104: }
105: }
106: }
107: if (foundKeyCount > 1) {
108: log.warn("More than one type matches, using closest match "
109: + answer.getQualifiedName());
110: }
111: return answer;
112:
113: }
114: }
|