/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.core.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
/**
* Utility methods for converting between different name types,
* for example from class names -> property names and vice-versa. The
* key aspect of this class is that it has no dependencies outside the JDK!
*/
public class GrailsNameUtils {
private static final String PROPERTY_SET_PREFIX = "set";
/**
* Retrieves the name of a setter for the specified property name
* @param propertyName The property name
* @return The setter equivalent
*/
public static String getSetterName(String propertyName) {
return PROPERTY_SET_PREFIX+propertyName.substring(0,1).toUpperCase()+ propertyName.substring(1);
}
/**
* Calculate the name for a getter method to retrieve the specified property
* @param propertyName
* @return The name for the getter method for this property, if it were to exist, i.e. getConstraints
*/
public static String getGetterName(String propertyName) {
final String suffix;
if(propertyName.length() > 1 &&
Character.isLowerCase(propertyName.charAt(0)) &&
Character.isUpperCase(propertyName.charAt(1))) {
suffix = propertyName;
} else {
suffix = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
}
return "get" + suffix;
}
/**
* Returns the class name for the given logical name and trailing name. For example "person" and "Controller" would evaluate to "PersonController"
*
* @param logicalName The logical name
* @param trailingName The trailing name
* @return The class name
*/
public static String getClassName(String logicalName, String trailingName) {
if (isBlank(logicalName)) {
throw new IllegalArgumentException("Argument [logicalName] cannot be null or blank");
}
String className = logicalName.substring(0,1).toUpperCase() + logicalName.substring(1);
if (trailingName != null) {
className = className + trailingName;
}
return className;
}
/**
* Returns the class name representation of the given name
*
* @param name The name to convert
* @return The property name representation
*/
public static String getClassNameRepresentation(String name) {
StringBuilder buf = new StringBuilder();
if (name != null && name.length() > 0) {
String[] tokens = name.split("[^\\w\\d]");
for (String token1 : tokens) {
String token = token1.trim();
buf.append(token.substring(0, 1).toUpperCase(Locale.ENGLISH))
.append(token.substring(1));
}
}
return buf.toString();
}
/**
* Converts foo-bar into FooBar. Empty and null strings are returned as-is.
*
* @param name The lower case hyphen separated name
* @return The class name equivalent.
*/
private static String getClassNameForLowerCaseHyphenSeparatedName(String name) {
// Handle null and empty strings.
if (isBlank(name)) return name;
if (name.indexOf('-') > -1) {
StringBuilder buf = new StringBuilder();
String[] tokens = name.split("-");
for (String token : tokens) {
if (token == null || token.length() == 0) continue;
buf.append(token.substring(0, 1).toUpperCase())
.append(token.substring(1));
}
return buf.toString();
}
return name.substring(0,1).toUpperCase() + name.substring(1);
}
/**
* Retrieves the logical class name of a Grails artifact given the Grails class
* and a specified trailing name
*
* @param clazz The class
* @param trailingName The trailing name such as "Controller" or "TagLib"
* @return The logical class name
*/
public static String getLogicalName(Class<?> clazz, String trailingName) {
return getLogicalName(clazz.getName(), trailingName);
}
/**
* Retrieves the logical name of the class without the trailing name
* @param name The name of the class
* @param trailingName The trailing name
* @return The logical name
*/
public static String getLogicalName(String name, String trailingName) {
if (!isBlank(trailingName)) {
String shortName = getShortName(name);
if (shortName.indexOf(trailingName) > - 1) {
return shortName.substring(0, shortName.length() - trailingName.length());
}
}
return name;
}
public static String getLogicalPropertyName(String className, String trailingName) {
if (!isBlank(className) && !isBlank(trailingName)) {
if (className.length() == trailingName.length() + 1 && className.endsWith(trailingName)) {
return className.substring(0, 1).toLowerCase();
}
}
return getLogicalName(getPropertyName(className), trailingName);
}
/**
* Shorter version of getPropertyNameRepresentation.
* @param name The name to convert
* @return The property name version
*/
public static String getPropertyName(String name) {
return getPropertyNameRepresentation(name);
}
/**
* Shorter version of getPropertyNameRepresentation.
* @param clazz The clazz to convert
* @return The property name version
*/
public static String getPropertyName(Class<?> clazz) {
return getPropertyNameRepresentation(clazz);
}
/**
* Returns the property name equivalent for the specified class.
*
* @param targetClass The class to get the property name for
* @return A property name reperesentation of the class name (eg. MyClass becomes myClass)
*/
public static String getPropertyNameRepresentation(Class<?> targetClass) {
String shortName = getShortName(targetClass);
return getPropertyNameRepresentation(shortName);
}
/**
* Returns the property name representation of the given name.
*
* @param name The name to convert
* @return The property name representation
*/
public static String getPropertyNameRepresentation(String name) {
// Strip any package from the name.
int pos = name.lastIndexOf('.');
if (pos != -1) {
name = name.substring(pos + 1);
}
// Check whether the name begins with two upper case letters.
if (name.length() > 1 && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1))) {
return name;
}
String propertyName = name.substring(0,1).toLowerCase(Locale.ENGLISH) + name.substring(1);
if (propertyName.indexOf(' ') > -1) {
propertyName = propertyName.replaceAll("\\s", "");
}
return propertyName;
}
/**
* Converts foo-bar into fooBar.
*
* @param name The lower case hyphen separated name
* @return The property name equivalent
*/
public static String getPropertyNameForLowerCaseHyphenSeparatedName(String name) {
return getPropertyName(getClassNameForLowerCaseHyphenSeparatedName(name));
}
/**
* Returns the class name without the package prefix.
*
* @param targetClass The class to get a short name for
* @return The short name of the class
*/
public static String getShortName(Class<?> targetClass) {
String className = targetClass.getName();
return getShortName(className);
}
/**
* Returns the class name without the package prefix.
*
* @param className The class name to get a short name for
* @return The short name of the class
*/
public static String getShortName(String className) {
int i = className.lastIndexOf(".");
if (i > -1) {
className = className.substring(i + 1, className.length());
}
return className;
}
/**
* Retrieves the script name representation of the supplied class. For example
* MyFunkyGrailsScript would be my-funky-grails-script.
*
* @param clazz The class to convert
* @return The script name representation
*/
public static String getScriptName(Class<?> clazz) {
if (clazz == null) {
return null;
}
return getScriptName(clazz.getName());
}
/**
* Retrieves the script name representation of the given class name.
* For example MyFunkyGrailsScript would be my-funky-grails-script.
*
* @param name The class name to convert.
* @return The script name representation.
*/
public static String getScriptName(String name) {
if (name == null) {
return null;
}
if (name.endsWith(".groovy")) {
name = name.substring(0, name.length()-7);
}
String naturalName = getNaturalName(name);
return naturalName.replaceAll("\\s", "-").toLowerCase();
}
/**
* Calculates the class name from a script name in the form my-funk-grails-script.
*
* @param scriptName The script name
* @return A class name
*/
public static String getNameFromScript(String scriptName) {
return getClassNameForLowerCaseHyphenSeparatedName(scriptName);
}
/**
* Returns the name of a plugin given the name of the *GrailsPlugin.groovy
* descriptor file. For example, "DbUtilsGrailsPlugin.groovy" gives
* "db-utils".
* @param descriptorName The simple name of the plugin descriptor.
* @return The plugin name for the descriptor, or <code>null</code>
* if <i>descriptorName</i> is <code>null</code>, or an empty string
* if <i>descriptorName</i> is an empty string.
* @throws IllegalArgumentException if the given descriptor name is
* not valid, i.e. if it doesn't end with "GrailsPlugin.groovy".
*/
public static String getPluginName(String descriptorName) {
if (descriptorName == null || descriptorName.length() == 0) {
return descriptorName;
}
if (!descriptorName.endsWith("GrailsPlugin.groovy")) {
throw new IllegalArgumentException("Plugin descriptor name is not valid: " + descriptorName);
}
int pos = descriptorName.indexOf("GrailsPlugin.groovy");
return getScriptName(descriptorName.substring(0, pos));
}
/**
* Converts a property name into its natural language equivalent eg ('firstName' becomes 'First Name')
* @param name The property name to convert
* @return The converted property name
*/
public static String getNaturalName(String name) {
name = getShortName(name);
List<String> words = new ArrayList<String>();
int i = 0;
char[] chars = name.toCharArray();
for (int j = 0; j < chars.length; j++) {
char c = chars[j];
String w;
if (i >= words.size()) {
w = "";
words.add(i, w);
}
else {
w = words.get(i);
}
if (Character.isLowerCase(c) || Character.isDigit(c)) {
if (Character.isLowerCase(c) && w.length() == 0) {
c = Character.toUpperCase(c);
}
else if (w.length() > 1 && Character.isUpperCase(w.charAt(w.length() - 1))) {
w = "";
words.add(++i,w);
}
words.set(i, w + c);
}
else if (Character.isUpperCase(c)) {
if ((i == 0 && w.length() == 0) || Character.isUpperCase(w.charAt(w.length() - 1))) {
words.set(i, w + c);
}
else {
words.add(++i, String.valueOf(c));
}
}
}
StringBuilder buf = new StringBuilder();
for (Iterator<String> j = words.iterator(); j.hasNext();) {
String word = j.next();
buf.append(word);
if (j.hasNext()) {
buf.append(' ');
}
}
return buf.toString();
}
/**
* <p>Determines whether a given string is <code>null</code>, empty,
* or only contains whitespace. If it contains anything other than
* whitespace then the string is not considered to be blank and the
* method returns <code>false</code>.</p>
* <p>We could use Commons Lang for this, but we don't want GrailsNameUtils
* to have a dependency on any external library to minimise the number of
* dependencies required to bootstrap Grails.</p>
* @param str The string to test.
* @return <code>true</code> if the string is <code>null</code>, or
* blank.
*/
public static boolean isBlank(String str) {
return str == null || str.trim().length() == 0;
}
}