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.server.core.api.partition;
021
022
023import java.io.IOException;
024import java.io.OutputStream;
025
026import javax.naming.InvalidNameException;
027
028import org.apache.directory.api.ldap.model.entry.Entry;
029import org.apache.directory.api.ldap.model.exception.LdapException;
030import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
031import org.apache.directory.api.ldap.model.exception.LdapOtherException;
032import org.apache.directory.api.ldap.model.name.Dn;
033import org.apache.directory.api.ldap.model.schema.SchemaManager;
034import org.apache.directory.api.util.Strings;
035import org.apache.directory.server.core.api.DnFactory;
036import org.apache.directory.server.i18n.I18n;
037
038
039/**
040 * A {@link Partition} that helps users to implement their own partition.
041 * Most methods are implemented by default.  Please look at the description of
042 * each methods for the detail of implementations.
043 *
044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
045 */
046public abstract class AbstractPartition implements Partition
047{
048    /** <tt>true</tt> if and only if this partition is initialized. */
049    protected boolean initialized;
050
051    /** The partition ContextEntry */
052    protected Entry contextEntry;
053
054    /** The SchemaManager instance */
055    protected SchemaManager schemaManager;
056
057    /** The DnFactory to use to create DN */
058    protected DnFactory dnFactory;
059
060    /** The partition ID */
061    protected String id;
062
063    /** The root Dn for this partition */
064    protected Dn suffixDn;
065
066    /** the value of last successful add/update operation's CSN */
067    private String contextCsn;
068    
069    /** a flag to detect the change in context CSN */
070    protected volatile boolean ctxCsnChanged = false;
071
072    /**
073     * {@inheritDoc}
074     */
075    @Override
076    public void initialize() throws LdapException
077    {
078        if ( initialized )
079        {
080            // Already initialized.
081            return;
082        }
083
084        try
085        {
086            doInit();
087            initialized = true;
088        }
089        catch ( Exception e )
090        {
091            throw new LdapOtherException( e.getMessage(), e );
092        }
093        finally
094        {
095            if ( !initialized )
096            {
097                try
098                {
099                    destroy( null );
100                }
101                catch ( Exception e )
102                {
103                    throw new LdapOtherException( e.getMessage(), e );
104                }
105            }
106        }
107    }
108
109
110    /**
111     * {@inheritDoc}
112     */
113    @Override
114    public void repair() throws LdapException
115    {
116        // Do nothing. It will be handled by the implementation classes
117    }
118
119
120    /**
121     * Override this method to put your initialization code.
122     * 
123     * @param partitionTxn The transaction to use
124     * @throws LdapException If the destroy call failed
125     */
126    protected abstract void doDestroy( PartitionTxn partitionTxn ) throws LdapException;
127
128
129    /**
130     * Override this method to put your initialization code.
131     * 
132     * @throws LdapException If the initialization failed
133     * @throws InvalidNameException If the initialization failed
134     */
135    protected abstract void doInit() throws InvalidNameException, LdapException;
136
137
138    /**
139     * Override this method to implement a repair method
140     * 
141     * @throws LdapException If the repair failed
142     */
143    protected abstract void doRepair() throws LdapException;
144
145
146    /**
147     * Calls <code>doDestroy()</code> where you have to put your destroy code in,
148     * and clears default properties.  Once this method is invoked, <code>isInitialized()</code>
149     * will return <tt>false</tt>.
150     */
151    @Override
152    public final void destroy( PartitionTxn partitionTxn ) throws LdapException
153    {
154        try
155        {
156            doDestroy( partitionTxn );
157        }
158        finally
159        {
160            initialized = false;
161        }
162    }
163
164
165    /**
166     * {@inheritDoc}
167     */
168    @Override
169    public final boolean isInitialized()
170    {
171        return initialized;
172    }
173
174
175    /**
176     * {@inheritDoc}
177     */
178    @Override
179    public void setSchemaManager( SchemaManager schemaManager )
180    {
181        this.schemaManager = schemaManager;
182    }
183
184
185    /**
186     * {@inheritDoc}
187     */
188    @Override
189    public final SchemaManager getSchemaManager()
190    {
191        return schemaManager;
192    }
193
194
195    /**
196     * {@inheritDoc}
197     */
198    @Override
199    public final String getId()
200    {
201        return id;
202    }
203
204
205    /**
206     * {@inheritDoc}
207     */
208    @Override
209    public void setId( String id )
210    {
211        checkInitialized( "id" );
212        this.id = id;
213    }
214
215
216    /**
217     * {@inheritDoc}
218     */
219    @Override
220    public final Dn getSuffixDn()
221    {
222        return suffixDn;
223    }
224
225
226    /**
227     * {@inheritDoc}
228     */
229    @Override
230    public void setSuffixDn( Dn suffixDn ) throws LdapInvalidDnException
231    {
232        checkInitialized( "suffixDn" );
233
234        if ( suffixDn.isSchemaAware() )
235        {
236            this.suffixDn = suffixDn;
237        }
238        else
239        {
240            this.suffixDn = new Dn( schemaManager, suffixDn );
241        }
242    }
243
244
245    /**
246     * {@inheritDoc}
247     */
248    @Override
249    public void dumpIndex( PartitionTxn partitionTxn, OutputStream stream, String name ) throws IOException
250    {
251        stream.write( Strings.getBytesUtf8( "Nothing to dump for index " + name ) );
252    }
253
254
255    /**
256     * Check that the operation is done on an initialized store
257     * 
258     * @param property The property that was initialized
259     */
260    protected void checkInitialized( String property )
261    {
262        if ( initialized )
263        {
264            throw new IllegalStateException( I18n.err( I18n.ERR_576, property ) );
265        }
266    }
267
268
269    /**
270     * @return the contextEntry
271     */
272    public Entry getContextEntry()
273    {
274        return contextEntry;
275    }
276
277
278    /**
279     * @param contextEntry the contextEntry to set
280     */
281    public void setContextEntry( Entry contextEntry )
282    {
283        this.contextEntry = contextEntry;
284    }
285
286
287    /**
288     * {@inheritDoc}
289     */
290    @Override
291    public String getContextCsn( PartitionTxn partitionTxn )
292    {
293        return contextCsn;
294    }
295
296    
297    /**
298     * Replaces the current context CSN with the given CSN value if they are not same and
299     * sets the ctxCsnChanged flag to true.
300     * 
301     * @param csn the CSN value
302     */
303    protected void setContextCsn( String csn )
304    {
305        if ( !csn.equals( contextCsn ) )
306        {
307            contextCsn = csn;
308            ctxCsnChanged = true;
309        }
310    }
311
312
313    /**
314     * {@inheritDoc}
315     */
316    @Override
317    public void sync() throws LdapException
318    {
319        // Do nothing by default
320    }
321}