Frames | No Frames |
1: /* 2: * Copyright 2003-2005 The Apache Software Foundation 3: * Copyright 2005 Stephen McConnell 4: * 5: * Licensed under the Apache License, Version 2.0 (the "License"); 6: * you may not use this file except in compliance with the License. 7: * You may obtain a copy of the License at 8: * 9: * http://www.apache.org/licenses/LICENSE-2.0 10: * 11: * Unless required by applicable law or agreed to in writing, software 12: * distributed under the License is distributed on an "AS IS" BASIS, 13: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14: * See the License for the specific language governing permissions and 15: * limitations under the License. 16: */ 17: package net.dpml.cli.validation; 18: 19: import java.util.List; 20: import java.util.ListIterator; 21: 22: import net.dpml.cli.resource.ResourceConstants; 23: import net.dpml.cli.resource.ResourceHelper; 24: 25: /** 26: * The <code>ClassValidator</code> validates the string argument 27: * values are class names. 28: * 29: * The following example shows how to validate the 'logger' 30: * argument value is a class name, that can be instantiated. 31: * 32: * <pre> 33: * ... 34: * ClassValidator validator = new ClassValidator(); 35: * validator.setInstance(true); 36: * 37: * ArgumentBuilder builder = new ArgumentBuilder(); 38: * Argument logger = 39: * builder.withName("logger"); 40: * .withValidator(validator); 41: * </pre> 42: * 43: * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a> 44: * @version @PROJECT-VERSION@ 45: */ 46: public class ClassValidator implements Validator 47: { 48: /** i18n */ 49: private static final ResourceHelper RESOURCES = 50: ResourceHelper.getResourceHelper(); 51: 52: /** whether the class argument is loadable */ 53: private boolean m_loadable; 54: 55: /** whether to create an instance of the class */ 56: private boolean m_instance; 57: 58: /** the classloader to load classes from */ 59: private ClassLoader m_loader; 60: 61: /** 62: * Validate each argument value in the specified List against this instances 63: * permitted attributes. 64: * 65: * If a value is valid then it's <code>String</code> value in the list is 66: * replaced with it's <code>Class</code> value or instance. 67: * 68: * @param values the list of values to validate 69: * @see net.dpml.cli.validation.Validator#validate(java.util.List) 70: * @exception InvalidArgumentException if a value is invalid 71: */ 72: public void validate( final List values ) throws InvalidArgumentException 73: { 74: for( final ListIterator i = values.listIterator(); i.hasNext();) 75: { 76: final String name = (String) i.next(); 77: 78: if( !isPotentialClassName( name ) ) 79: { 80: throw new InvalidArgumentException( 81: RESOURCES.getMessage( 82: ResourceConstants.CLASSVALIDATOR_BAD_CLASSNAME, 83: name ) ); 84: } 85: 86: if( m_loadable || m_instance ) 87: { 88: final ClassLoader theLoader = getClassLoader(); 89: 90: try 91: { 92: final Class clazz = theLoader.loadClass( name ); 93: if( m_instance ) 94: { 95: i.set( clazz.newInstance() ); 96: } 97: else 98: { 99: i.set( clazz ); 100: } 101: } 102: catch( final ClassNotFoundException exp ) 103: { 104: throw new InvalidArgumentException( 105: RESOURCES.getMessage( 106: ResourceConstants.CLASSVALIDATOR_CLASS_NOTFOUND, 107: name ) ); 108: } 109: catch( final IllegalAccessException exp ) 110: { 111: throw new InvalidArgumentException( 112: RESOURCES.getMessage( 113: ResourceConstants.CLASSVALIDATOR_CLASS_ACCESS, 114: name, 115: exp.getMessage() ) ); 116: } 117: catch( final InstantiationException exp ) 118: { 119: throw new InvalidArgumentException( 120: RESOURCES.getMessage( 121: ResourceConstants.CLASSVALIDATOR_CLASS_CREATE, 122: name ) ); 123: } 124: } 125: } 126: } 127: 128: /** 129: * Returns whether the argument value must represent a 130: * class that is loadable. 131: * 132: * @return whether the argument value must represent a 133: * class that is loadable. 134: */ 135: public boolean isLoadable() 136: { 137: return m_loadable; 138: } 139: 140: /** 141: * Specifies whether the argument value must represent a 142: * class that is loadable. 143: * 144: * @param loadable whether the argument value must 145: * represent a class that is loadable. 146: */ 147: public void setLoadable( boolean loadable ) 148: { 149: m_loadable = loadable; 150: } 151: 152: /** 153: * Returns the {@link ClassLoader} used to resolve and load 154: * the classes specified by the argument values. 155: * 156: * @return the {@link ClassLoader} used to resolve and load 157: * the classes specified by the argument values. 158: */ 159: public ClassLoader getClassLoader() 160: { 161: if( m_loader == null ) 162: { 163: m_loader = getClass().getClassLoader(); 164: } 165: return m_loader; 166: } 167: 168: /** 169: * Specifies the {@link ClassLoader} used to resolve and load 170: * the classes specified by the argument values. 171: * 172: * @param loader the {@link ClassLoader} used to resolve and load 173: * the classes specified by the argument values. 174: */ 175: public void setClassLoader( ClassLoader loader ) 176: { 177: m_loader = loader; 178: } 179: 180: /** 181: * Returns whether the argument value must represent a 182: * class that can be instantiated. 183: * 184: * @return whether the argument value must represent a 185: * class that can be instantiated. 186: */ 187: public boolean isInstance() 188: { 189: return m_instance; 190: } 191: 192: /** 193: * Specifies whether the argument value must represent a 194: * class that can be instantiated. 195: * 196: * @param instance whether the argument value must 197: * represent a class that can be instantiated. 198: */ 199: public void setInstance( boolean instance ) 200: { 201: m_instance = instance; 202: } 203: 204: /** 205: * Returns whether the specified name is allowed as 206: * a Java class name. 207: * @param name the potential classname 208: * @return true if the name is a potential classname 209: */ 210: protected boolean isPotentialClassName( final String name ) 211: { 212: final char[] chars = name.toCharArray(); 213: 214: boolean expectingStart = true; 215: 216: for( int i = 0; i < chars.length; ++i ) 217: { 218: final char c = chars[i]; 219: 220: if( expectingStart ) 221: { 222: if( !Character.isJavaIdentifierStart( c ) ) 223: { 224: return false; 225: } 226: expectingStart = false; 227: } 228: else 229: { 230: if( c == '.' ) 231: { 232: expectingStart = true; 233: } 234: else if( !Character.isJavaIdentifierPart( c ) ) 235: { 236: return false; 237: } 238: } 239: } 240: 241: return !expectingStart; 242: } 243: }