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 */
020package org.apache.directory.api.ldap.model.schema;
021
022
023import java.util.ArrayList;
024import java.util.List;
025
026import org.apache.directory.api.i18n.I18n;
027
028
029/**
030 * A dITStructureRule definition. A dITStructureRules is a rule governing the
031 * structure of the DIT by specifying a permitted superior to subordinate entry
032 * relationship. A structure rule relates a nameForm, and therefore a STRUCTURAL
033 * objectClass, to superior dITStructureRules. This permits entries of the
034 * STRUCTURAL objectClass identified by the nameForm to exist in the DIT as
035 * subordinates to entries governed by the indicated superior dITStructureRules.
036 * Hence dITStructureRules only apply to structural object classes.
037 * <p>
038 * According to ldapbis [MODELS]:
039 * </p>
040 * 
041 * <pre>
042 *  DIT structure rule descriptions are written according to the ABNF:
043 *  
044 *    DITStructureRuleDescription = LPAREN WSP
045 *        ruleid                    ; rule identifier
046 *        [ SP &quot;NAME&quot; SP qdescrs ]  ; short names (descriptors)
047 *        [ SP &quot;DESC&quot; SP qdstring ] ; description
048 *        [ SP &quot;OBSOLETE&quot; ]         ; not active
049 *        SP &quot;FORM&quot; SP oid          ; NameForm
050 *        [ SP &quot;SUP&quot; ruleids ]      ; superior rules
051 *        extensions WSP RPAREN     ; extensions
052 * 
053 *    ruleids = ruleid / ( LPAREN WSP ruleidlist WSP RPAREN )
054 * 
055 *    ruleidlist = ruleid *( SP ruleid )
056 * 
057 *    ruleid = number
058 * 
059 *  where:
060 *    [ruleid] is the rule identifier of this DIT structure rule;
061 *    NAME [qdescrs] are short names (descriptors) identifying this DIT
062 *        structure rule;
063 *    DESC [qdstring] is a short descriptive string;
064 *    OBSOLETE indicates this DIT structure rule use is not active;
065 *    FORM is specifies the name form associated with this DIT structure
066 *        rule;
067 *    SUP identifies superior rules (by rule id); and
068 *    [extensions] describe extensions.
069 *  
070 *  If no superior rules are identified, the DIT structure rule applies
071 *  to an autonomous administrative point (e.g. the root vertex of the
072 *  subtree controlled by the subschema) [X.501].
073 * </pre>
074 * 
075 * @see <a href="http://www.faqs.org/rfcs/rfc2252.html">RFC2252 Section 6.33</a>
076 * @see <a
077 *      href="http://www.ietf.org/internet-drafts/draft-ietf-ldapbis-models-11.txt">ldapbis
078 *      [MODELS]</a>
079 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
080 */
081public class DitStructureRule extends AbstractSchemaObject
082{
083    /** The mandatory serialVersionUID */
084    public static final long serialVersionUID = 1L;
085
086    /** The rule ID. A DSR does not have an OID */
087    private int ruleId;
088
089    /** The associated NameForm */
090    private String form;
091
092    /** The list of superiors rules */
093    private List<Integer> superRules;
094
095
096    /**
097     * Creates a new instance of DitStructureRule
098     * 
099     * @param ruleId The RuleId for this DitStructureRule
100     */
101    public DitStructureRule( int ruleId )
102    {
103        super( SchemaObjectType.DIT_STRUCTURE_RULE, null );
104        this.ruleId = ruleId;
105        form = null;
106        superRules = new ArrayList<>();
107    }
108
109
110    /**
111     *  @return The associated NameForm's OID
112     */
113    public String getForm()
114    {
115        return form;
116    }
117
118
119    /**
120     * Sets the associated NameForm's OID
121     *
122     * @param form The NameForm's OID
123     */
124    public void setForm( String form )
125    {
126        if ( locked )
127        {
128            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
129        }
130
131        this.form = form;
132    }
133
134
135    /**
136     * @return The Rule ID
137     */
138    public int getRuleId()
139    {
140        return ruleId;
141    }
142
143
144    /**
145     * Sets the rule identifier of this DIT structure rule;
146     *
147     * @param ruleId the rule identifier of this DIT structure rule;
148     */
149    public void setRuleId( int ruleId )
150    {
151        if ( locked )
152        {
153            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
154        }
155
156        this.ruleId = ruleId;
157    }
158
159
160    /**
161     * @return The list of superiors RuleIDs
162     */
163    public List<Integer> getSuperRules()
164    {
165        return superRules;
166    }
167
168
169    /**
170     * Sets the list of superior RuleIds
171     * 
172     * @param superRules the list of superior RuleIds
173     */
174    public void setSuperRules( List<Integer> superRules )
175    {
176        if ( locked )
177        {
178            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
179        }
180
181        this.superRules = superRules;
182    }
183
184
185    /**
186     * Adds a new superior RuleId
187     *
188     * @param superRule The superior RuleID to add
189     */
190    public void addSuperRule( Integer superRule )
191    {
192        if ( locked )
193        {
194            throw new UnsupportedOperationException( I18n.err( I18n.ERR_13700_CANNOT_MODIFY_LOCKED_SCHEMA_OBJECT, getName() ) );
195        }
196
197        superRules.add( superRule );
198    }
199
200
201    /**
202     * The DIT structure rule does not have an OID
203     * 
204     * {@inheritDoc}
205     */
206    @Override
207    public String getOid()
208    {
209        // We cannot throw exception here. E.g. SchemaObjectWrapper will try to use this in hashcode.
210        return null;
211    }
212
213
214    /**
215     * {@inheritDoc}
216     */
217    @Override
218    public String toString()
219    {
220        return SchemaObjectRenderer.OPEN_LDAP_SCHEMA_RENDERER.render( this );
221    }
222
223
224    /**
225     * {@inheritDoc}
226     */
227    @Override
228    public DitStructureRule copy()
229    {
230        DitStructureRule copy = new DitStructureRule( ruleId );
231
232        // Copy the SchemaObject common data
233        copy.copy( this );
234
235        // Copy the Superiors rules
236        copy.superRules = new ArrayList<>();
237
238        // Copy the form
239        copy.form = form;
240
241        for ( int superRule : superRules )
242        {
243            copy.superRules.add( superRule );
244        }
245
246        return copy;
247    }
248
249    
250    /**
251     * @see Object#equals(Object)
252     */
253    @Override
254    public int hashCode()
255    {
256        int hash = h;
257        
258        hash = hash * 17 + ruleId;
259        
260        if ( form != null )
261        {
262            hash = hash * 17 + form.hashCode();
263        }
264        
265        if ( superRules != null )
266        {
267            int tempHash = 0;
268            
269            for ( int superRule : superRules )
270            {
271                tempHash += superRule;
272            }
273            
274            hash = hash * 17 + tempHash;
275        }
276        
277        return hash;
278    }
279
280
281    /**
282     * {@inheritDoc}
283     */
284    @Override
285    public boolean equals( Object o )
286    {
287        if ( !super.equals( o ) )
288        {
289            return false;
290        }
291
292        if ( !( o instanceof DitStructureRule ) )
293        {
294            return false;
295        }
296
297        @SuppressWarnings("unused")
298        DitStructureRule that = ( DitStructureRule ) o;
299
300        // TODO : complete the test
301        return true;
302    }
303
304
305    /**
306     * {@inheritDoc}
307     */
308    @Override
309    public void clear()
310    {
311        // Clear the common elements
312        super.clear();
313
314        // Clear the references
315        superRules.clear();
316    }
317}