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;
021    
022    
023    import java.util.List;
024    
025    import org.apache.directory.shared.i18n.I18n;
026    import org.apache.directory.shared.ldap.exception.LdapException;
027    import org.apache.directory.shared.ldap.schema.registries.Registries;
028    import org.apache.directory.shared.ldap.schema.syntaxCheckers.OctetStringSyntaxChecker;
029    
030    
031    /**
032     * A syntax definition. Each attribute stored in a directory has a defined
033     * syntax (i.e. data type) which constrains the structure and format of its
034     * values. The description of each syntax specifies how attribute or assertion
035     * values conforming to the syntax are normally represented when transferred in
036     * LDAP operations. This representation is referred to as the LDAP-specific
037     * encoding to distinguish it from other methods of encoding attribute values.
038     * <p>
039     * According to ldapbis [MODELS]:
040     * </p>
041     * 
042     * <pre>
043     *  4.1.5. LDAP Syntaxes
044     *  
045     *    LDAP Syntaxes of (attribute and assertion) values are described in
046     *    terms of ASN.1 [X.680] and, optionally, have an octet string encoding
047     *    known as the LDAP-specific encoding.  Commonly, the LDAP-specific
048     *    encoding is constrained to string of Universal Character Set (UCS)
049     *    [ISO10646] characters in UTF-8 [UTF-8] form.
050     * 
051     *    Each LDAP syntax is identified by an object identifier (OID).
052     * 
053     *    LDAP syntax definitions are written according to the ABNF:
054     * 
055     *      SyntaxDescription = LPAREN WSP
056     *          numericoid                ; object identifier
057     *          [ SP &quot;DESC&quot; SP qdstring ] ; description
058     *          extensions WSP RPAREN     ; extensions
059     * 
060     *    where:
061     *      [numericoid] is object identifier assigned to this LDAP syntax;
062     *      DESC [qdstring] is a short descriptive string; and
063     *      [extensions] describe extensions.
064     * </pre>
065     * 
066     * @see <a href="http://www.faqs.org/rfcs/rfc2252.html"> RFC2252 Section 4.3.3</a>
067     * @see <a href=
068     *      "http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-09.txt">
069     *      ldapbis [MODELS]</a>
070     * @see DescriptionUtils#getDescription(Syntax)
071     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
072     * @version $Rev: 437007 $
073     */
074    public class LdapSyntax extends AbstractSchemaObject
075    {
076        /** The serialVersionUID */
077        public static final long serialVersionUID = 1L;
078    
079        /** the human readable flag */
080        protected boolean isHumanReadable = false;
081    
082        /** The associated SyntaxChecker */
083        protected SyntaxChecker syntaxChecker;
084    
085    
086        /**
087         * Creates a Syntax object using a unique OID.
088         * 
089         * @param oid the OID for this Syntax
090         */
091        public LdapSyntax( String oid )
092        {
093            super( SchemaObjectType.LDAP_SYNTAX, oid );
094        }
095    
096    
097        /**
098         * Creates a Syntax object using a unique OID.
099         * 
100         * @param oid the OID for this Syntax
101         */
102        public LdapSyntax( String oid, String description )
103        {
104            super( SchemaObjectType.LDAP_SYNTAX, oid );
105            this.description = description;
106        }
107    
108    
109        /**
110         * Creates a Syntax object using a unique OID.
111         * 
112         * @param oid the OID for this Syntax
113         */
114        public LdapSyntax( String oid, String description, boolean isHumanReadable )
115        {
116            super( SchemaObjectType.LDAP_SYNTAX, oid );
117            this.description = description;
118            this.isHumanReadable = isHumanReadable;
119        }
120    
121    
122        /**
123         * Gets whether or not the Syntax is human readable.
124         * 
125         * @return true if the syntax can be interpreted by humans, false otherwise
126         */
127        public boolean isHumanReadable()
128        {
129            return isHumanReadable;
130        }
131    
132    
133        /**
134         * Sets the human readable flag value.
135         * 
136         * @param isHumanReadable the human readable flag value to set
137         */
138        public void setHumanReadable( boolean isHumanReadable )
139        {
140            if ( locked )
141            {
142                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
143            }
144            
145            if ( !isReadOnly )
146            {
147                this.isHumanReadable = isHumanReadable;
148            }
149        }
150    
151    
152        /**
153         * Gets the SyntaxChecker used to validate values in accordance with this
154         * Syntax.
155         * 
156         * @return the SyntaxChecker
157         */
158        public SyntaxChecker getSyntaxChecker()
159        {
160            return syntaxChecker;
161        }
162    
163    
164        /**
165         * Sets the associated SyntaxChecker
166         *
167         * @param syntaxChecker The associated SyntaxChecker
168         */
169        public void setSyntaxChecker( SyntaxChecker syntaxChecker )
170        {
171            if ( locked )
172            {
173                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
174            }
175            
176            if ( !isReadOnly )
177            {
178                this.syntaxChecker = syntaxChecker;
179            }
180        }
181    
182    
183        /**
184         * Update the associated SyntaxChecker, even if the SchemaObject is readOnly
185         *
186         * @param syntaxChecker The associated SyntaxChecker
187         */
188        public void updateSyntaxChecker( SyntaxChecker syntaxChecker )
189        {
190            if ( locked )
191            {
192                throw new UnsupportedOperationException( I18n.err( I18n.ERR_04441, getName() ) );
193            }
194            
195            this.syntaxChecker = syntaxChecker;
196        }
197    
198    
199        /**
200         * @see Object#toString()
201         */
202        public String toString()
203        {
204            return objectType + " " + DescriptionUtils.getDescription( this );
205        }
206    
207    
208        /**
209         * Inject the Syntax into the registries, updating the references to
210         * other SchemaObject
211         *
212         * @param registries The Registries
213         * @exception If the addition failed
214         */
215        public void addToRegistries( List<Throwable> errors, Registries registries ) throws LdapException
216        {
217            if ( registries != null )
218            {
219                try
220                {
221                    // Gets the associated SyntaxChecker
222                    syntaxChecker = registries.getSyntaxCheckerRegistry().lookup( oid );
223                }
224                catch ( LdapException ne )
225                {
226                    // No SyntaxChecker ? Associate the Syntax to a catch all SyntaxChecker
227                    syntaxChecker = new OctetStringSyntaxChecker( oid );
228                }
229    
230                // Add the references for S :
231                // S -> SC
232                if ( syntaxChecker != null )
233                {
234                    registries.addReference( this, syntaxChecker );
235                }
236            }
237        }
238        
239        
240        /**
241         * Remove the SDyntax from the registries, updating the references to
242         * other SchemaObject.
243         * 
244         * If one of the referenced SchemaObject does not exist (), 
245         * an exception is thrown.
246         *
247         * @param registries The Registries
248         * @exception If the Syntx is not valid 
249         */
250        public void removeFromRegistries( List<Throwable> errors, Registries registries ) throws LdapException
251        {
252            if ( registries != null )
253            {
254                /**
255                 * Remove the Syntax references (using and usedBy) : 
256                 * S -> SC
257                 */
258                if ( syntaxChecker != null )
259                {
260                    registries.delReference( this, syntaxChecker );
261                }
262            }
263        }
264    
265    
266        /**
267         * Copy a LdapSyntax
268         */
269        public LdapSyntax copy()
270        {
271            LdapSyntax copy = new LdapSyntax( oid );
272    
273            // Copy the SchemaObject common data
274            copy.copy( this );
275    
276            // Copy the HR flag
277            copy.isHumanReadable = isHumanReadable;
278    
279            // All the references to other Registries object are set to null.
280            copy.syntaxChecker = null;
281    
282            return copy;
283        }
284    
285    
286        /**
287         * @see Object#equals()
288         */
289        public boolean equals( Object o )
290        {
291            if ( !super.equals( o ) )
292            {
293                return false;
294            }
295    
296            if ( !( o instanceof LdapSyntax ) )
297            {
298                return false;
299            }
300    
301            LdapSyntax that = ( LdapSyntax ) o;
302    
303            // IsHR
304            if ( isHumanReadable != that.isHumanReadable )
305            {
306                return false;
307            }
308    
309            // Check the SyntaxChecker (not a equals)
310            return syntaxChecker.getOid().equals( that.syntaxChecker.getOid() );
311        }
312    
313    
314        /**
315         * {@inheritDoc}
316         */
317        public void clear()
318        {
319            // Clear the common elements
320            super.clear();
321    
322            // Clear the references
323            syntaxChecker = null;
324        }
325    }