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.entry;
021    
022    import javax.naming.NamingException;
023    
024    import org.apache.directory.shared.ldap.schema.SyntaxChecker;
025    import org.slf4j.Logger;
026    import org.slf4j.LoggerFactory;
027    
028    
029    /**
030     * A wrapper around byte[] values in entries.
031     *
032     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
033     * @version $Rev$, $Date$
034     */
035    public abstract class AbstractValue<T> implements Value<T>
036    {
037        /** logger for reporting errors that might not be handled properly upstream */
038        private static final Logger LOG = LoggerFactory.getLogger( AbstractValue.class );
039    
040        
041        /** the wrapped binary value */
042        protected T wrapped;
043        
044        /** the canonical representation of the wrapped value */
045        protected T normalizedValue;
046    
047        /** A flag set when the value has been normalized */
048        protected boolean normalized;
049    
050        /** cached results of the isValid() method call */
051        protected Boolean valid;
052    
053        /** A flag set if the normalized data is different from the wrapped data */
054        protected transient boolean same;
055        
056        /**
057         * Reset the value
058         */
059        public void clear()
060        {
061            wrapped = null;
062            normalized = false;
063            normalizedValue = null;
064            valid = null;
065        }
066    
067        
068        /**
069         * {@inheritDoc}
070         */
071        public Value<T> clone()
072        {
073            try
074            {
075                return (Value<T>)super.clone();
076            }
077            catch ( CloneNotSupportedException cnse )
078            {
079                // Do nothing
080                return null;
081            }
082        }
083        
084        
085        /**
086         * Gets a reference to the wrapped binary value.
087         * 
088         * Warning ! The value is not copied !!!
089         *
090         * @return a direct handle on the binary value that is wrapped
091         */
092        public T getReference()
093        {
094            return wrapped;
095        }
096    
097        
098        /**
099         * Gets a copy of the wrapped binary value.
100         * 
101         * @return a copy of the binary value that is wrapped
102         */
103        public T get()
104        {
105            // Just call the specific Client copy method.
106            return getCopy();
107        }
108    
109        
110        /**
111         * Gets the normalized (canonical) representation for the wrapped value.
112         * If the wrapped value is null, null is returned, otherwise the normalized
113         * form is returned.  If the normalized Value is null, then the wrapped 
114         * value is returned
115         *
116         * @return gets the normalized value
117         */
118        public T getNormalizedValue()
119        {
120            if ( isNull() )
121            {
122                return null;
123            }
124    
125            if ( normalizedValue == null )
126            {
127                return getCopy();
128            }
129    
130            return getNormalizedValueCopy();
131        }
132    
133    
134        /**
135         * Gets a reference to the the normalized (canonical) representation 
136         * for the wrapped value.
137         *
138         * @return gets a reference to the normalized value
139         */
140        public T getNormalizedValueReference()
141        {
142            if ( isNull() )
143            {
144                return null;
145            }
146    
147            if ( normalizedValue == null )
148            {
149                return wrapped;
150            }
151    
152            return normalizedValue;
153    
154        }
155    
156        
157        /**
158         * Check if the contained value is null or not
159         * 
160         * @return <code>true</code> if the inner value is null.
161         */
162        public final boolean isNull()
163        {
164            return wrapped == null; 
165        }
166        
167        
168        /**
169         * @return Tells if the wrapped value and the normalized value are the same 
170         */
171        public final boolean isSame()
172        {
173            return same;
174        }
175    
176        
177        /**
178         * Check if the Valid flag is set or not. This flag is set by a call
179         * to the isValid( SyntaxChecker ) method for client values. It is overridden
180         * for server values.
181         * 
182         * if the flag is not set, returns <code>false</code>
183         *
184         * @see ServerValue#isValid()
185         */
186        public boolean isValid()
187        {
188            if ( valid != null )
189            {
190                return valid;
191            }
192    
193            return false;
194        }
195    
196    
197        /**
198         * Uses the syntaxChecker associated with the attributeType to check if the
199         * value is valid.  Repeated calls to this method do not attempt to re-check
200         * the syntax of the wrapped value every time if the wrapped value does not
201         * change. Syntax checks only result on the first check, and when the wrapped
202         * value changes.
203         *
204         * @see ServerValue#isValid()
205         */
206        public final boolean isValid( SyntaxChecker syntaxChecker ) throws NamingException
207        {
208            if ( valid != null )
209            {
210                return valid;
211            }
212            
213            if ( syntaxChecker == null )
214            {
215                String message = "Cannot validate " + toString() + " with a null SyntaxChecker";
216                LOG.error( message );
217                throw new NamingException( message );
218            }
219            
220            valid = syntaxChecker.isValidSyntax( getReference() );
221            return valid;
222        }
223    
224    
225        /**
226         * Normalize the value. In order to use this method, the Value
227         * must be schema aware.
228         * 
229         * @exception NamingException If the value cannot be normalized
230         */
231        public void normalize() throws NamingException
232        {
233            normalized = true;
234            normalizedValue = wrapped;
235        }
236    
237    
238        /**
239         * Sets this value's wrapped value to a copy of the src array.
240         *
241         * @param wrapped the byte array to use as the wrapped value
242         */
243        public abstract void set( T wrapped );
244    
245        
246        /**
247         * Tells if the value has already be normalized or not.
248         *
249         * @return <code>true</code> if the value has already been normalized.
250         */
251        public final boolean isNormalized()
252        {
253            return normalized;
254        }
255    
256        
257        /**
258         * Set the normalized flag.
259         * 
260         * @param the value : true or false
261         */
262        public final void setNormalized( boolean normalized )
263        {
264            this.normalized = normalized;
265        }
266    }