001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.schema.normalizers;
021    
022    
023    import java.io.UnsupportedEncodingException;
024    
025    import org.apache.directory.shared.i18n.I18n;
026    import org.apache.directory.shared.ldap.entry.BinaryValue;
027    import org.apache.directory.shared.ldap.exception.LdapException;
028    import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
029    import org.apache.directory.shared.ldap.schema.AttributeType;
030    import org.apache.directory.shared.ldap.schema.MatchingRule;
031    import org.apache.directory.shared.ldap.schema.Normalizer;
032    import org.apache.directory.shared.ldap.schema.SchemaManager;
033    import org.apache.directory.shared.ldap.util.StringTools;
034    import org.slf4j.Logger;
035    import org.slf4j.LoggerFactory;
036    
037    
038    /**
039     * A DN Name component Normalizer which uses the bootstrap registries to find
040     * the appropriate normalizer for the attribute of the name component with which
041     * to normalize the name component value.
042     *
043     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044     * @version $Rev: 928296 $
045     */
046    public class ConcreteNameComponentNormalizer implements NameComponentNormalizer
047    {
048        /** The LoggerFactory used by this Interceptor */
049        private static Logger LOG = LoggerFactory.getLogger( ConcreteNameComponentNormalizer.class );
050    
051        /** the schemaManager used to dynamically resolve Normalizers */
052        private final SchemaManager schemaManager;
053        
054    
055        /**
056         * Creates a DN Name component Normalizer which uses the bootstrap
057         * registries to find the appropriate normalizer for the attribute of the
058         * name component with which to normalize the name component value.
059         *
060         * @param schemaManager the schemaManager used to dynamically resolve Normalizers
061         */
062        public ConcreteNameComponentNormalizer( SchemaManager schemaManager )
063        {
064            this.schemaManager = schemaManager;
065        }
066    
067        
068        private String unescape( String value )
069        {
070            char[] newVal = new char[value.length()];
071            int escaped = 0;
072            char high = 0;
073            char low = 0;
074            int pos = 0;
075            
076            for ( char c:value.toCharArray() )
077            {
078                switch ( escaped )
079                {
080                    case 0 :
081                        if ( c == '\\' )
082                        {
083                            escaped = 1;
084                        }
085                        else
086                        {
087                            newVal[pos++] = c;
088                        }
089                        
090                        break;
091    
092                    case 1 :
093                        escaped++;
094                        high = c;
095                        break;
096                        
097                    case 2 :
098                        escaped=0;
099                        low = c;
100                        newVal[pos++] = (char)StringTools.getHexValue( high, low );
101                        
102                }
103            }
104            
105            return new String( newVal, 0, pos );
106        }
107    
108        /**
109         * @see NameComponentNormalizer#normalizeByName(String, String)
110         */
111        public Object normalizeByName( String name, String value ) throws LdapException
112        {
113            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( name );
114            
115            if ( attributeType.getSyntax().isHumanReadable() )
116            {
117                return lookup( name ).normalize( value );
118            }
119            else
120            {
121                try
122                {
123                    String unescaped = unescape( value );
124                    byte[] valBytes = unescaped.getBytes( "UTF-8" );
125                    
126                    return lookup( name ).normalize( new BinaryValue( valBytes ) ); 
127                }
128                catch ( UnsupportedEncodingException uee )
129                {
130                    String message = I18n.err( I18n.ERR_04222 );
131                    LOG.error( message );
132                    throw new LdapException( message );
133                }
134            }
135            
136        }
137    
138    
139        /**
140         * @see NameComponentNormalizer#normalizeByName(String, String)
141         */
142        public Object normalizeByName( String name, byte[] value ) throws LdapException
143        {
144            AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( name );
145            
146            if ( !attributeType.getSyntax().isHumanReadable() )
147            {
148                return lookup( name ).normalize( new BinaryValue( value ) );
149            }
150            else
151            {
152                try
153                {
154                    String valStr = new String( value, "UTF-8" );
155                    return lookup( name ).normalize( valStr ); 
156                }
157                catch ( UnsupportedEncodingException uee )
158                {
159                    String message = I18n.err( I18n.ERR_04223 );
160                    LOG.error( message );
161                    throw new LdapException( message );
162                }
163            }
164        }
165    
166    
167        /**
168         * @see NameComponentNormalizer#normalizeByOid(String, String)
169         */
170        public Object normalizeByOid( String oid, String value ) throws LdapException
171        {
172            return lookup( oid ).normalize( value );
173        }
174    
175    
176        /**
177         * @see NameComponentNormalizer#normalizeByOid(String, String)
178         */
179        public Object normalizeByOid( String oid, byte[] value ) throws LdapException
180        {
181            return lookup( oid ).normalize( new BinaryValue( value ) );
182        }
183    
184    
185        /**
186         * Looks up the Normalizer to use for a name component using the attributeId
187         * for the name component.  First the attribute is resolved, then its
188         * equality matching rule is looked up.  The normalizer of that matching
189         * rule is returned.
190         *
191         * @param id the name or oid of the attribute in the name component to
192         * normalize the value of
193         * @return the Normalizer to use for normalizing the value of the attribute
194         * @throws LdapException if there are failures resolving the Normalizer
195         */
196        private Normalizer lookup( String id ) throws LdapException
197        {
198            AttributeType type = schemaManager.lookupAttributeTypeRegistry( id );
199            MatchingRule mrule = type.getEquality();
200            
201            if ( mrule == null )
202            {
203                return new NoOpNormalizer( id );
204            }
205            
206            return mrule.getNormalizer();
207        }
208    
209    
210        /**
211         * @see NameComponentNormalizer#isDefined(String)
212         */
213        public boolean isDefined( String id )
214        {
215            return schemaManager.getAttributeTypeRegistry().contains( id );
216        }
217    
218    
219        public String normalizeName( String attributeName ) throws LdapException
220        {
221            return schemaManager.getAttributeTypeRegistry().getOidByName( attributeName );
222        }
223    }