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