001 /* 002 * Copyright 2004-2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.metro.info; 020 021 import java.io.Serializable; 022 import java.beans.Introspector; 023 import java.lang.reflect.Method; 024 025 026 /** 027 * A descriptor that describes a value that must be placed 028 * in components Context. It contains information about; 029 * <ul> 030 * <li>key: the key that component uses to look up entry</li> 031 * <li>classname: the class/interface of the entry</li> 032 * <li>isOptional: true if entry is optional rather than required</li> 033 * </ul> 034 * 035 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 036 * @version 1.0.4 037 */ 038 public final class EntryDescriptor implements Serializable, Comparable 039 { 040 /** 041 * Serial version identifier. 042 */ 043 static final long serialVersionUID = 1L; 044 045 /** 046 * Constant prefix for get operations. 047 */ 048 public static final String GET = "get"; 049 050 /** 051 * Utility function that covers a supplied method to a 052 * entry name. 053 * @see Introspector#decapitalize(String) 054 * @param method the method 055 * @return the key 056 */ 057 public static String getEntryKey( Method method ) 058 { 059 String name = method.getName(); 060 if( name.startsWith( GET ) ) 061 { 062 String remainder = name.substring( GET.length() ); 063 return Introspector.decapitalize( remainder ); 064 } 065 else 066 { 067 final String error = 068 "Unrecognized context accessor method signature [" 069 + name 070 + "]"; 071 throw new IllegalArgumentException( error ); 072 } 073 } 074 075 /** 076 * Optional constant. 077 */ 078 public static final boolean OPTIONAL = true; 079 080 /** 081 * Required constant. 082 */ 083 public static final boolean REQUIRED = false; 084 085 /** 086 * The name the component uses to lookup entry. 087 */ 088 private final String m_key; 089 090 /** 091 * The class/interface of the Entry. 092 */ 093 private final String m_classname; 094 095 /** 096 * True if entry is optional, false otherwise. 097 */ 098 private final boolean m_optional; 099 100 /** 101 * Immutable state of the entry. 102 */ 103 private final boolean m_volatile; 104 105 /** 106 * Construct an non-volotile required EntryDescriptor. 107 * @param key the context entry key 108 * @param classname the classname of the context entry 109 * @exception NullPointerException if the key or type value are null 110 */ 111 public EntryDescriptor( final String key, final String classname ) 112 throws NullPointerException 113 { 114 this( key, classname, false ); 115 } 116 117 /** 118 * Construct an non-volotile EntryDescriptor. 119 * @param key the context entry key 120 * @param classname the classname of the context entry 121 * @param optional TRUE if this is an optional entry 122 * @exception NullPointerException if the key or type value are null 123 */ 124 public EntryDescriptor( final String key, 125 final String classname, 126 final boolean optional ) throws NullPointerException 127 { 128 this( key, classname, optional, false ); 129 } 130 131 /** 132 * Construct an EntryDescriptor. 133 * @param key the context entry key 134 * @param classname the classname of the context entry 135 * @param optional TRUE if this is an optional entry 136 * @param isVolatile TRUE if the entry is consider to be immutable 137 * @exception NullPointerException if the key or type value are null 138 */ 139 public EntryDescriptor( final String key, 140 final String classname, 141 final boolean optional, 142 final boolean isVolatile ) throws NullPointerException 143 { 144 if ( null == key ) 145 { 146 throw new NullPointerException( "key" ); 147 } 148 if ( null == classname ) 149 { 150 throw new NullPointerException( "classname" ); 151 } 152 153 m_key = key; 154 m_classname = classname; 155 m_optional = optional; 156 m_volatile = isVolatile; 157 } 158 159 /** 160 * Return the key that Component uses to lookup entry. 161 * 162 * @return the key that Component uses to lookup entry. 163 */ 164 public String getKey() 165 { 166 return m_key; 167 } 168 169 /** 170 * Return the type of value that is stored in the context entry. 171 * 172 * @return the context entry classname 173 */ 174 public String getClassname() 175 { 176 return m_classname; 177 } 178 179 /** 180 * Return true if entry is optional, false otherwise. 181 * 182 * @return true if entry is optional, false otherwise. 183 */ 184 public boolean getOptional() 185 { 186 return m_optional; 187 } 188 189 /** 190 * Return true if entry is optional, false otherwise. 191 * 192 * @return true if entry is optional, false otherwise. 193 */ 194 public boolean isOptional() 195 { 196 return getOptional(); 197 } 198 199 /** 200 * Return true if entry is required, false otherwise. 201 * 202 * @return true if entry is required, false otherwise. 203 */ 204 public boolean isRequired() 205 { 206 return !isOptional(); 207 } 208 209 /** 210 * Return true if entry is volotile. 211 * 212 * @return the volatile state of the entry 213 */ 214 public boolean isVolatile() 215 { 216 return getVolatile(); 217 } 218 219 /** 220 * Return true if entry is volotile. 221 * 222 * @return the volatile state of the entry 223 */ 224 public boolean getVolatile() 225 { 226 return m_volatile; 227 } 228 229 /** 230 * Test is the supplied object is equal to this object. 231 * @param other the object to compare with this instance 232 * @return true if the object are equivalent 233 */ 234 public boolean equals( Object other ) 235 { 236 if( other == null ) 237 { 238 return false; 239 } 240 241 if( !( other instanceof EntryDescriptor ) ) 242 { 243 return false; 244 } 245 246 EntryDescriptor entry = (EntryDescriptor) other; 247 248 if( m_optional != entry.m_optional ) 249 { 250 return false; 251 } 252 253 if( m_volatile != entry.m_volatile ) 254 { 255 return false; 256 } 257 258 if( !m_key.equals( entry.m_key ) ) 259 { 260 return false; 261 } 262 263 if( !m_classname.equals( entry.m_classname ) ) 264 { 265 return false; 266 } 267 268 return true; 269 } 270 271 /** 272 * Return the hashcode for the object. 273 * @return the hashcode value 274 */ 275 public int hashCode() 276 { 277 int hash = m_key.hashCode(); 278 hash ^= m_classname.hashCode(); 279 if( m_volatile ) 280 { 281 hash = hash + 1806621635; 282 } 283 else 284 { 285 hash = hash - 1236275651; 286 } 287 if( m_optional ) 288 { 289 hash = hash + 1232368545; 290 } 291 else 292 { 293 hash = hash - 923798133; 294 } 295 return hash; 296 } 297 298 /** 299 * Compare this entry with another entry. 300 * @param other the other object 301 * @return the comparative index 302 */ 303 public int compareTo( Object other ) 304 { 305 if( null == other ) 306 { 307 throw new NullPointerException( "other" ); 308 } 309 EntryDescriptor entry = (EntryDescriptor) other; 310 if( getOptional() == entry.getOptional() ) 311 { 312 return m_key.compareTo( entry.getKey() ); 313 } 314 else if( isRequired() ) 315 { 316 return -1; 317 } 318 else 319 { 320 return 1; 321 } 322 } 323 }