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.server.xdbm.tools;
021    
022    
023    import java.util.Set;
024    import java.util.UUID;
025    
026    import org.apache.directory.server.core.entry.DefaultServerEntry;
027    import org.apache.directory.server.core.entry.ServerEntry;
028    import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
029    import org.apache.directory.server.schema.registries.Registries;
030    import org.apache.directory.server.xdbm.ForwardIndexEntry;
031    import org.apache.directory.server.xdbm.Index;
032    import org.apache.directory.server.xdbm.IndexEntry;
033    import org.apache.directory.server.xdbm.Store;
034    import org.apache.directory.shared.ldap.constants.SchemaConstants;
035    import org.apache.directory.shared.ldap.csn.CsnFactory;
036    import org.apache.directory.shared.ldap.cursor.Cursor;
037    import org.apache.directory.shared.ldap.entry.Entry;
038    import org.apache.directory.shared.ldap.entry.EntryAttribute;
039    import org.apache.directory.shared.ldap.entry.client.DefaultClientAttribute;
040    import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
041    import org.apache.directory.shared.ldap.name.LdapDN;
042    import org.apache.directory.shared.ldap.schema.SchemaUtils;
043    
044    
045    /**
046     * A utility class for loading example LDIF data.
047     *
048     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049     * @version $Rev$, $Date$
050     */
051    public class StoreUtils
052    {
053        /** CSN factory instance */
054        private static final CsnFactory CSN_FACTORY = new CsnFactory( 0 );
055    
056        /**
057         * Initializes and loads a store with the example data shown in
058         * <a href="http://cwiki.apache.org/confluence/display/DIRxSRVx11/Structure+and+Organization">
059         * Structure and Organization</a>
060         *
061         * TODO might want to make this load an LDIF instead in the future
062         * TODO correct size of spaces in user provided DN
063         * 
064         * @param store the store object to be initialized
065         * @param registries oid registries
066         * @throws Exception on access exceptions
067         */
068        public static void loadExampleData( Store<ServerEntry> store, Registries registries ) throws Exception
069        {
070            store.setSuffixDn( "o=Good Times Co." );
071    
072            LdapDN suffixDn = new LdapDN( "o=Good Times Co." );
073            suffixDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
074            
075            AttributeTypeRegistry attributeRegistry = registries.getAttributeTypeRegistry();
076    
077            store.init( registries );
078    
079            // Entry #1
080            DefaultServerEntry entry = new DefaultServerEntry( registries, suffixDn );
081            entry.add( "objectClass", "organization" );
082            entry.add( "o", "Good Times Co." );
083            entry.add( "postalCode", "1" );
084            entry.add( "postOfficeBox", "1" );
085            injectEntryInStore( store, entry );
086    
087            
088            // Entry #2
089            LdapDN dn = new LdapDN( "ou=Sales,o=Good Times Co." );
090            dn.normalize( attributeRegistry.getNormalizerMapping() );
091            entry = new DefaultServerEntry( registries, dn );
092            entry.add( "objectClass", "top", "organizationalUnit" );
093            entry.add( "ou", "Sales" );
094            entry.add( "postalCode", "1" );
095            entry.add( "postOfficeBox", "1" );
096            injectEntryInStore( store, entry );
097    
098            // Entry #3
099            dn = new LdapDN( "ou=Board of Directors,o=Good Times Co." );
100            dn.normalize( attributeRegistry.getNormalizerMapping() );
101            entry = new DefaultServerEntry( registries, dn );
102            entry.add( "objectClass", "top", "organizationalUnit" );
103            entry.add( "ou", "Board of Directors" );
104            entry.add( "postalCode", "1" );
105            entry.add( "postOfficeBox", "1" );
106            injectEntryInStore( store, entry );
107            
108            // Entry #4
109            dn = new LdapDN( "ou=Engineering,o=Good Times Co." );
110            dn.normalize( attributeRegistry.getNormalizerMapping() );
111            entry = new DefaultServerEntry( registries, dn );
112            entry.add( "objectClass", "top", "organizationalUnit" );
113            entry.add( "ou", "Engineering" );
114            entry.add( "postalCode", "2" );
115            entry.add( "postOfficeBox", "2" );
116            injectEntryInStore( store, entry );
117            
118            // Entry #5
119            dn = new LdapDN( "cn=JOhnny WAlkeR,ou=Sales,o=Good Times Co." );
120            dn.normalize( attributeRegistry.getNormalizerMapping() );
121            entry = new DefaultServerEntry( registries, dn );
122            entry.add( "objectClass", "top", "person", "organizationalPerson" );
123            entry.add( "ou", "Sales" );
124            entry.add( "cn", "JOhnny WAlkeR");
125            entry.add( "sn", "WAlkeR");
126            entry.add( "postalCode", "3" );
127            entry.add( "postOfficeBox", "3" );
128            injectEntryInStore( store, entry );
129            
130            // Entry #6
131            dn = new LdapDN( "cn=JIM BEAN,ou=Sales,o=Good Times Co." );
132            dn.normalize( attributeRegistry.getNormalizerMapping() );
133            entry = new DefaultServerEntry( registries, dn );
134            entry.add( "objectClass", "top", "person", "organizationalPerson" );
135            entry.add( "ou", "Sales" );
136            entry.add( "cn",  "JIM BEAN");
137            entry.add( "surName", "BEAN");
138            entry.add( "postalCode", "4" );
139            entry.add( "postOfficeBox", "4" );
140            injectEntryInStore( store, entry );
141    
142            // Entry #7
143            dn = new LdapDN( "ou=Apache,ou=Board of Directors,o=Good Times Co." );
144            dn.normalize( attributeRegistry.getNormalizerMapping() );
145            entry = new DefaultServerEntry( registries, dn );
146            entry.add( "objectClass", "top", "organizationalUnit" );
147            entry.add( "ou", "Apache" );
148            entry.add( "postalCode", "5" );
149            entry.add( "postOfficeBox", "5" );
150            injectEntryInStore( store, entry );
151            
152            // Entry #8
153            dn = new LdapDN( "cn=Jack Daniels,ou=Engineering,o=Good Times Co." );
154            dn.normalize( attributeRegistry.getNormalizerMapping() );
155            entry = new DefaultServerEntry( registries, dn );
156            entry.add( "objectClass", "top", "person", "organizationalPerson" );
157            entry.add( "ou", "Engineering" );
158            entry.add( "cn",  "Jack Daniels");
159            entry.add( "SN",  "Daniels");
160            entry.add( "postalCode", "6" );
161            entry.add( "postOfficeBox", "6" );
162            injectEntryInStore( store, entry );
163    
164            // aliases -------------
165    
166            // Entry #9
167            dn = new LdapDN( "commonName=Jim Bean,ou=Apache,ou=Board of Directors,o=Good Times Co." );
168            dn.normalize( attributeRegistry.getNormalizerMapping() );
169            entry = new DefaultServerEntry( registries, dn );
170            entry.add( "objectClass", "top", "alias", "extensibleObject" );
171            entry.add( "ou", "Apache" );
172            entry.add( "commonName",  "Jim Bean");
173            entry.add( "aliasedObjectName", "cn=Jim Bean,ou=Sales,o=Good Times Co." );
174            injectEntryInStore( store, entry );
175    
176            // Entry #10
177            dn = new LdapDN( "commonName=Jim Bean,ou=Board of Directors,o=Good Times Co." );
178            dn.normalize( attributeRegistry.getNormalizerMapping() );
179            entry = new DefaultServerEntry( registries, dn );
180            entry.add( "objectClass", "top", "alias", "extensibleObject" );
181            entry.add( "commonName",  "Jim Bean");
182            entry.add( "aliasedObjectName", "cn=Jim Bean,ou=Sales,o=Good Times Co." );
183            injectEntryInStore( store, entry );
184    
185            // Entry #11
186            dn = new LdapDN( "2.5.4.3=Johnny Walker,ou=Engineering,o=Good Times Co." );
187            dn.normalize( attributeRegistry.getNormalizerMapping() );
188            entry = new DefaultServerEntry( registries, dn );
189            entry.add( "objectClass", "top", "alias", "extensibleObject" );
190            entry.add( "ou", "Engineering" );
191            entry.add( "2.5.4.3",  "Johnny Walker");
192            entry.add( "aliasedObjectName", "cn=Johnny Walker,ou=Sales,o=Good Times Co." );
193            injectEntryInStore( store, entry );
194        }
195        
196        
197        /**
198         * This is primarily a convenience method used to extract all the attributes
199         * associated with an entry.
200         *
201         * @param store the store to get the attributes from
202         * @param id the id of the entry to get index information for
203         * @return the index names and values as an Attributes object
204         * @throws Exception if there are failures accessing the underlying store
205         */
206        @SuppressWarnings("unchecked")
207        public Entry getAttributes( Store store, Long id ) throws Exception
208        {
209            Entry entry = new DefaultClientEntry();
210    
211            // Get the distinguishedName to id mapping
212            entry.put( "_nDn", store.getEntryDn( id ) );
213            entry.put( "_upDn", store.getEntryUpdn( id ) );
214            entry.put( "_parent", Long.toString( store.getParentId( id ) ) );
215    
216            // Get all standard index attribute to value mappings
217            for ( Index index : ( Set<Index> )store.getUserIndices() )
218            {
219                Cursor<ForwardIndexEntry> list = index.reverseCursor();
220                ForwardIndexEntry recordForward = new ForwardIndexEntry();
221                recordForward.setId( id );
222                list.before( recordForward );
223    
224                while ( list.next() )
225                {
226                    IndexEntry rec = list.get();
227                    String val = rec.getValue().toString();
228                    String attrId = index.getAttribute().getName();
229                    EntryAttribute attr = entry.get( attrId );
230    
231                    if ( attr == null )
232                    {
233                        attr = new DefaultClientAttribute( attrId );
234                    }
235                    
236                    attr.add( val );
237                    entry.put( attr );
238                }
239            }
240    
241            // Get all existence mappings for this id creating a special key
242            // that looks like so 'existence[attribute]' and the value is set to id
243            Cursor<IndexEntry> list = store.getPresenceIndex().reverseCursor();
244            ForwardIndexEntry recordForward = new ForwardIndexEntry();
245            recordForward.setId( id );
246            list.before( recordForward );
247            StringBuffer val = new StringBuffer();
248            
249            while ( list.next() )
250            {
251                IndexEntry rec = list.get();
252                val.append( "_existence[" );
253                val.append( rec.getValue().toString() );
254                val.append( "]" );
255    
256                String valStr = val.toString();
257                EntryAttribute attr = entry.get( valStr );
258                
259                if ( attr == null )
260                {
261                    attr = new DefaultClientAttribute( valStr );
262                }
263                
264                attr.add( rec.getId().toString() );
265                entry.put( attr );
266                val.setLength( 0 );
267            }
268    
269            // Get all parent child mappings for this entry as the parent using the
270            // key 'child' with many entries following it.
271            Cursor<IndexEntry> children = store.getOneLevelIndex().forwardCursor();
272            ForwardIndexEntry longRecordForward = new ForwardIndexEntry();
273            recordForward.setId( id );
274            children.before( longRecordForward );
275    
276            EntryAttribute childAttr = new DefaultClientAttribute( "_child" );
277            entry.put( childAttr );
278            
279            while ( children.next() )
280            {
281                IndexEntry rec = children.get();
282                childAttr.add( rec.getId().toString() );
283            }
284    
285            return entry;
286        }
287    
288    
289        /**
290         * 
291         * adds a given <i>ServerEntry</i> to the store after injecting entryCSN and entryUUID operational
292         * attributes
293         *
294         * @param store the store
295         * @param dn the normalized DN
296         * @param entry the server entry
297         * @throws Exception in case of any problems in adding the entry to the store
298         */
299        public static void injectEntryInStore( Store<ServerEntry> store, ServerEntry entry ) throws Exception
300        {
301            entry.add( SchemaConstants.ENTRY_CSN_AT, CSN_FACTORY.newInstance().toString() );
302            entry.add( SchemaConstants.ENTRY_UUID_AT, SchemaUtils.uuidToBytes( UUID.randomUUID() ) );
303            
304            store.add( entry );
305        }
306    }