Clover coverage report - Ledge Components - SNAPSHOT
Coverage timestamp: Fri Nov 17 2006 05:13:20 CET
file stats: LOC: 404   Methods: 3
NCLOC: 285   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
NamingPolicy.java 61.5% 81% 100% 74.6%
coverage coverage
 1    //
 2    // Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.
 3    // All rights reserved.
 4    //
 5    // Redistribution and use in source and binary forms, with or without modification,
 6    // are permitted provided that the following conditions are met:
 7    //
 8    // * Redistributions of source code must retain the above copyright notice,
 9    // this list of conditions and the following disclaimer.
 10    // * Redistributions in binary form must reproduce the above copyright notice,
 11    // this list of conditions and the following disclaimer in the documentation
 12    // and/or other materials provided with the distribution.
 13    // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.
 14    // nor the names of its contributors may be used to endorse or promote products
 15    // derived from this software without specific prior written permission.
 16    //
 17    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 18    // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 19    // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 20    // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 21    // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 22    // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 23    // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 24    // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 25    // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 26    // POSSIBILITY OF SUCH DAMAGE.
 27    //
 28    package org.objectledge.authentication;
 29   
 30    import java.util.ArrayList;
 31    import java.util.List;
 32    import java.util.NoSuchElementException;
 33    import java.util.Properties;
 34   
 35    import javax.naming.CompoundName;
 36    import javax.naming.InvalidNameException;
 37    import javax.naming.Name;
 38   
 39    import org.jcontainer.dna.Configuration;
 40    import org.jcontainer.dna.ConfigurationException;
 41    import org.objectledge.parameters.Parameters;
 42   
 43    /**
 44    * Specifies a policy of naming accounts in the system.
 45    *
 46    * @author <a href="mailto:rafal@caltha.pl">Rafal Krzewski</a>
 47    * @version $Id: NamingPolicy.java,v 1.5 2006/02/08 18:19:37 zwierzem Exp $
 48    */
 49    public class NamingPolicy
 50    {
 51    private String loginProperty;
 52   
 53    private Properties syntax = new Properties();
 54   
 55    private Token[] tokens;
 56   
 57    /**
 58    * Creates an instance of the NamingPolicyComponent.
 59    *
 60    * @param config the configuration.
 61    * @throws ConfigurationException if the configuration is invalid.
 62    */
 63  782 public NamingPolicy(Configuration config)
 64    throws ConfigurationException
 65    {
 66  782 loginProperty = config.getChild("login-property").getAttribute("name", null);
 67  782 if(loginProperty == null)
 68    {
 69  782 loginProperty = config.getChild("login-property").getValue(null);
 70    }
 71   
 72  782 Configuration syntaxConfig = config.getChild("syntax");
 73  782 Configuration tokensConfig = config.getChild("tokens");
 74  782 if(config.getChild("syntax").getChild("ldap-syntax", false) != null)
 75    {
 76  782 syntax.put("jndi.syntax.direction", "right_to_left");
 77  782 syntax.put("jndi.syntax.separator", ",");
 78  782 syntax.put("jndi.syntax.separator.ava", ",");
 79  782 syntax.put("jndi.syntax.separator.typeval", "=");
 80  782 syntax.put("jndi.syntax.ignorecase", "true");
 81  782 syntax.put("jndi.syntax.escape", "\\");
 82    }
 83    else
 84    {
 85  0 Configuration[] syntaxProperties = syntaxConfig.getChildren("property");
 86  0 for(int i=0; i<syntaxProperties.length; i++)
 87    {
 88  0 syntax.put(syntaxProperties[i].getAttribute("name"),
 89    syntaxProperties[i].getValue(syntaxProperties[i].getAttribute("value", null)));
 90    }
 91    }
 92  782 Configuration[] tokenConfig = tokensConfig.getChildren("token");
 93  782 tokens = new Token[tokenConfig.length];
 94  782 boolean loginFound = false;
 95  782 for(int i=0; i<tokenConfig.length; i++)
 96    {
 97  3128 tokens[i] = new Token(tokenConfig[i]);
 98  3128 if(tokens[i].specifies(loginProperty))
 99    {
 100  782 loginFound = true;
 101    }
 102    }
 103  782 if(tokens.length > 1 && syntax.get("jndi.syntax.separator") == null)
 104    {
 105  0 throw new ConfigurationException("multiple tokens defined, but syntax does not "+
 106    "specify jndi.syntax.separator",
 107    syntaxConfig.getPath(), syntaxConfig.getLocation());
 108    }
 109  782 if(!loginFound)
 110    {
 111  0 throw new ConfigurationException("no token specifies "+loginProperty+" property",
 112    tokensConfig.getPath(), tokensConfig.getLocation());
 113    }
 114    }
 115   
 116    /**
 117    * Returns a distinguished name constructed from provided parameters in conformance to
 118    * configured syntax.
 119    *
 120    * @param parameters the parameters to compose name of.
 121    * @return the distinguished name.
 122    */
 123  506 public String getDn(Parameters parameters)
 124    {
 125  506 StringBuilder target = new StringBuilder();
 126  506 String sep = (String)syntax.get("jndi.syntax.separator");
 127  506 for(int i=0; i<tokens.length; i++)
 128    {
 129  2024 tokens[i].render(parameters, target);
 130  2024 if(i<tokens.length-1)
 131    {
 132  1518 target.append(sep);
 133    }
 134    }
 135  506 return target.toString();
 136    }
 137   
 138    /**
 139    * Retrieves the login name from the distinguished name.
 140    *
 141    * @param dn the distinguished name.
 142    * @return the login name.
 143    * @throws InvalidNameException if the name does not conform to the defined syntax.
 144    */
 145  138 public String getLogin(String dn)
 146    throws InvalidNameException
 147    {
 148  138 Name name = new CompoundName(dn, syntax);
 149  138 if(name.size() != tokens.length)
 150    {
 151  46 throw new InvalidNameException("invalid name, expecting "+tokens.length+" elements");
 152    }
 153  92 for(int i=0; i<name.size(); i++)
 154    {
 155  92 if(tokens[i].specifies(loginProperty))
 156    {
 157  92 return tokens[i].get(name.get(name.size()-1-i), loginProperty);
 158    }
 159    else
 160    {
 161  0 if(!tokens[i].match(name.get(name.size()-1-i)))
 162    {
 163  0 throw new InvalidNameException("invalied name, element "+
 164    name.get(name.size()-1-i)+ " does not match "+tokens[i].toString());
 165    }
 166    }
 167    }
 168    ///CLOVER:ON
 169  0 throw new IllegalStateException();
 170    ///CLOVER:OFF
 171    }
 172   
 173    /**
 174    * Represents syntax of a compound disthinguished name element.
 175    *
 176    * @author <a href="mailto:rafal@caltha.pl">Rafal Krzewski</a>
 177    * @version $Id: NamingPolicy.java,v 1.5 2006/02/08 18:19:37 zwierzem Exp $
 178    */
 179    public static class Token
 180    {
 181    /** constant string elements, first and last may be null. */
 182    private String[] strings;
 183   
 184    /** embedded property names, alwas has string.length - 1 elements. */
 185    private String[] properties;
 186   
 187    /**
 188    * Creates token instance from a configuration element.
 189    *
 190    * @param config the configuration element.
 191    * @throws ConfigurationException if the configuration is invalid.
 192    */
 193    public Token(Configuration config)
 194    throws ConfigurationException
 195    {
 196    Configuration[] elements = config.getChildren();
 197    if(elements.length == 0)
 198    {
 199    throw new ConfigurationException("at least one element required", config.getPath(),
 200    config.getLocation());
 201    }
 202    List<String> stringSpecs = new ArrayList<String>(elements.length/2);
 203    List<String> propertySpecs = new ArrayList<String>(elements.length/2);
 204    for(int i=0; i<elements.length; i++)
 205    {
 206    if(elements[i].getName().equals("string"))
 207    {
 208    String value = elements[i].getAttribute("value", null);
 209    if(value == null)
 210    {
 211    value = elements[i].getValue();
 212    }
 213    stringSpecs.add(value);
 214    }
 215    else
 216    {
 217    if(stringSpecs.size() == 0)
 218    {
 219    stringSpecs.add(null);
 220    }
 221    String name = elements[i].getAttribute("name", null);
 222    if(name == null)
 223    {
 224    name = elements[i].getValue();
 225    }
 226    propertySpecs.add(name);
 227    }
 228    }
 229    if(stringSpecs.size() == propertySpecs.size())
 230    {
 231    stringSpecs.add(null);
 232    }
 233    strings = new String[stringSpecs.size()];
 234    stringSpecs.toArray(strings);
 235    properties = new String[propertySpecs.size()];
 236    propertySpecs.toArray(properties);
 237    }
 238   
 239    /**
 240    * Renders token image based on provided parameters into an output buffer.
 241    *
 242    * @param parameters the parameters to use for rendering.
 243    * @param target the output buffer.
 244    */
 245    public void render(Parameters parameters, StringBuilder target)
 246    {
 247    for(int i=0; i<strings.length + properties.length; i++)
 248    {
 249    if(i%2 == 0)
 250    {
 251    if(strings[i/2] != null)
 252    {
 253    target.append(strings[i/2]);
 254    }
 255    }
 256    else
 257    {
 258    String value = parameters.get(properties[i/2],null);
 259    if(value != null)
 260    {
 261    target.append(value);
 262    }
 263    else
 264    {
 265    throw new NoSuchElementException("undefined property "+properties[i/2]);
 266    }
 267    }
 268    }
 269    }
 270   
 271    /**
 272    * Checks if the given token image matches the specified syntax.
 273    *
 274    * @param image the token image.
 275    * @return <code>true</code> if the given token image matches the specified syntax.
 276    */
 277    public boolean match(String image)
 278    {
 279    int lastPos = 0;
 280    for(int i=0; i<strings.length; i++)
 281    {
 282    if(strings[i] != null)
 283    {
 284    int pos = image.indexOf(strings[i], lastPos);
 285    if(pos >= 0)
 286    {
 287    lastPos = pos+strings[i].length();
 288    }
 289    else
 290    {
 291    return false;
 292    }
 293    }
 294    }
 295    return true;
 296    }
 297   
 298    /**
 299    * Retrieves a property from given token image.
 300    *
 301    * @param image the token image.
 302    * @param propertyName the property name.
 303    * @return the property value.
 304    * @throws IllegalArgumentException if the token does not specify this property.
 305    * @throws InvalidNameException if the token does not conform to defined syntax.
 306    */
 307    public String get(String image, String propertyName)
 308    throws IllegalArgumentException, InvalidNameException
 309    {
 310    int lastPos = 0;
 311    int nextPos = image.length();
 312    for(int i=0; i<strings.length+properties.length; i++)
 313    {
 314    if(i%2 == 0)
 315    {
 316    if(strings[i/2] != null)
 317    {
 318    int pos = image.indexOf(strings[i/2], lastPos);
 319    if(pos >= 0)
 320    {
 321    lastPos = pos+strings[i/2].length();
 322    }
 323    else
 324    {
 325    throw new InvalidNameException("invalid token "+image+" "+
 326    strings[i/2]+" is missing");
 327    }
 328    }
 329    if(i/2+1 < strings.length)
 330    {
 331    if(strings[i/2+1] != null)
 332    {
 333    int pos = image.indexOf(strings[i/2+1], lastPos);
 334    if(pos >= 0)
 335    {
 336    nextPos = pos;
 337    }
 338    else
 339    {
 340    throw new InvalidNameException("invalid token "+image+" "+
 341    strings[i/2+1]+" is missing");
 342    }
 343    }
 344    else
 345    {
 346    nextPos = image.length();
 347    }
 348    }
 349    }
 350    else
 351    {
 352    if(properties[i/2].equals(propertyName))
 353    {
 354    return image.substring(lastPos, nextPos);
 355    }
 356    }
 357    }
 358    throw new IllegalArgumentException("token does not specify "+propertyName+" property");
 359    }
 360   
 361    /**
 362    * Checks if this token specifies a property.
 363    *
 364    * @param propertyName the name of the property.
 365    * @return <code>true</code> if this token specifies a property.
 366    */
 367    public boolean specifies(String propertyName)
 368    {
 369    for(int i=0; i<properties.length; i++)
 370    {
 371    if(properties[i].equals(propertyName))
 372    {
 373    return true;
 374    }
 375    }
 376    return false;
 377    }
 378   
 379    /**
 380    * Returns a string representation of the token's syntax.
 381    *
 382    * @return a string representation of the token's syntax.
 383    */
 384    public String toString()
 385    {
 386    StringBuilder target = new StringBuilder();
 387    for(int i=0; i<strings.length + properties.length; i++)
 388    {
 389    if(i%2 == 0)
 390    {
 391    if(strings[i/2] != null)
 392    {
 393    target.append(strings[i/2]);
 394    }
 395    }
 396    else
 397    {
 398    target.append('<').append(properties[i/2]).append('>');
 399    }
 400    }
 401    return target.toString();
 402    }
 403    }
 404    }