View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.prefs;
21  
22  
23  import org.apache.directory.server.constants.ApacheSchemaConstants;
24  import org.apache.directory.server.core.DirectoryService;
25  import org.apache.directory.server.core.entry.ClonedServerEntry;
26  import org.apache.directory.server.core.entry.DefaultServerAttribute;
27  import org.apache.directory.server.core.entry.ServerAttribute;
28  import org.apache.directory.server.core.entry.ServerEntry;
29  import org.apache.directory.server.core.entry.ServerModification;
30  import org.apache.directory.server.core.filtering.EntryFilteringCursor;
31  import org.apache.directory.shared.ldap.constants.SchemaConstants;
32  import org.apache.directory.shared.ldap.entry.EntryAttribute;
33  import org.apache.directory.shared.ldap.entry.Modification;
34  import org.apache.directory.shared.ldap.entry.ModificationOperation;
35  import org.apache.directory.shared.ldap.message.AliasDerefMode;
36  import org.apache.directory.shared.ldap.name.LdapDN;
37  import org.apache.directory.shared.ldap.schema.AttributeType;
38  import org.apache.directory.shared.ldap.util.PreferencesDictionary;
39  
40  import javax.naming.InvalidNameException;
41  import javax.naming.NamingException;
42  
43  import java.util.ArrayList;
44  import java.util.Dictionary;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.prefs.AbstractPreferences;
48  import java.util.prefs.BackingStoreException;
49  import java.util.prefs.Preferences;
50  
51  
52  /**
53   * A server side system {@link Preferences} implementation.  This implementation
54   * presumes the creation of a root system preferences node in advance.  This
55   * should be included with the system.ldif that is packaged with the server.
56   *
57   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
58   * @version $Rev: 679249 $
59   */
60  public class ServerSystemPreferences extends AbstractPreferences
61  {
62      /** an empty array of Strings used to get array from list */
63      private static final String[] EMPTY_STRINGS = new String[0];
64  
65      /** the changes representing cached alterations to preferences */
66      private List<Modification> changes = new ArrayList<Modification>( 3 );
67  
68      /** maps changes based on key: key->list of mods (on same key) */
69      private HashMap<String, List<Modification>> keyToChange = new HashMap<String, List<Modification>>( 3 );
70      
71      private LdapDN dn;
72      
73      private DirectoryService directoryService;
74      
75  
76  
77      /**
78       * Creates a preferences object for the system preferences root.
79       * @param directoryService the directory service core
80       */
81      public ServerSystemPreferences( DirectoryService directoryService )
82      {
83          super( null, "" );
84          super.newNode = false;
85          
86          try
87          {
88              dn = new LdapDN( "prefNodeName=sysPrefRoot,ou=system" );
89          }
90          catch ( InvalidNameException e )
91          {
92              // never happens
93          }
94          
95          this.directoryService = directoryService;
96      }
97  
98      
99      public void close() throws NamingException
100     {
101     }
102 
103 
104     /**
105      * Creates a preferences object using a relative name.
106      * 
107      * @param name the name of the preference node to create
108      * @param parent the parent of the preferences node to create
109      */
110     public ServerSystemPreferences( ServerSystemPreferences parent, String name )
111     {
112         super( parent, name );
113 
114         this.directoryService = parent.directoryService;
115         LdapDN parentDn = ( ( ServerSystemPreferences ) parent() ).dn;
116         try
117         {
118             dn = new LdapDN( "prefNodeName=" + name + "," + parentDn.getUpName() );
119             dn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
120             
121             if ( ! directoryService.getAdminSession().exists( dn ) )
122             {
123                 ServerEntry entry = directoryService.newEntry( dn );
124                 entry.add( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, 
125                     ApacheSchemaConstants.PREF_NODE_OC, SchemaConstants.EXTENSIBLE_OBJECT_OC );
126                 entry.add( "prefNodeName", name );
127     
128                 directoryService.getAdminSession().add( entry );
129                 
130                 super.newNode = false;
131             }
132         }
133         catch ( Exception e )
134         {
135             throw new ServerSystemPreferenceException( "Failed to set up node.", e );
136         }
137     }
138 
139 
140     // ------------------------------------------------------------------------
141     // Utility Methods
142     // ------------------------------------------------------------------------
143 
144     /**
145      * Wraps this ServerPreferences object as a Dictionary.
146      *
147      * @return a Dictionary that uses this ServerPreferences object as the underlying backing store
148      */
149     public Dictionary<String, String> wrapAsDictionary()
150     {
151         return new PreferencesDictionary( this );
152     }
153 
154 
155     // ------------------------------------------------------------------------
156     // Protected SPI Methods
157     // ------------------------------------------------------------------------
158 
159     protected void flushSpi() throws BackingStoreException
160     {
161         if ( changes.isEmpty() )
162         {
163             return;
164         }
165 
166         try
167         {
168             directoryService.getAdminSession().modify( dn, changes );
169         }
170         catch ( Exception e )
171         {
172             throw new BackingStoreException( e );
173         }
174 
175         changes.clear();
176         keyToChange.clear();
177     }
178 
179 
180     protected void removeNodeSpi() throws BackingStoreException
181     {
182         try
183         {
184             directoryService.getAdminSession().delete( dn );
185         }
186         catch ( Exception e )
187         {
188             throw new BackingStoreException( e );
189         }
190 
191         changes.clear();
192         keyToChange.clear();
193     }
194 
195 
196     protected void syncSpi() throws BackingStoreException
197     {
198         if ( changes.isEmpty() )
199         {
200             return;
201         }
202 
203         try
204         {
205             directoryService.getAdminSession().modify( dn, changes );
206         }
207         catch ( Exception e )
208         {
209             throw new BackingStoreException( e );
210         }
211 
212         changes.clear();
213         keyToChange.clear();
214     }
215 
216 
217     protected String[] childrenNamesSpi() throws BackingStoreException
218     {
219         List<String> children = new ArrayList<String>();
220         EntryFilteringCursor list;
221 
222         try
223         {
224             list = directoryService.getAdminSession().list( dn, AliasDerefMode.DEREF_ALWAYS, null );
225             list.beforeFirst();
226             while ( list.next() )
227             {
228                 ClonedServerEntry entry = list.get();
229                 children.add( ( String ) entry.getDn().getRdn().getValue() );
230             }
231         }
232         catch ( Exception e )
233         {
234             throw new BackingStoreException( e );
235         }
236 
237         return children.toArray( EMPTY_STRINGS );
238     }
239 
240 
241     protected String[] keysSpi() throws BackingStoreException
242     {
243         List<String> keys = new ArrayList<String>();
244 
245         try
246         {
247             ServerEntry entry = directoryService.getAdminSession().lookup( dn );
248             for ( EntryAttribute attr : entry )
249             {
250                 ServerAttribute sa = ( ServerAttribute ) attr;
251                 String oid = sa.getAttributeType().getOid();
252                 
253                 if ( oid.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) )
254                 {
255                     continue;
256                 }
257                 
258                 keys.add( sa.getUpId() );
259             }
260         }
261         catch ( Exception e )
262         {
263             throw new BackingStoreException( e );
264         }
265 
266         return keys.toArray( EMPTY_STRINGS );
267     }
268 
269 
270     protected void removeSpi( String key ) 
271     {
272         AttributeType at;
273         try
274         {
275             at = directoryService.getRegistries().getAttributeTypeRegistry().lookup( key );
276             ServerAttribute attr = new DefaultServerAttribute( at );
277             Modification mi = new ServerModification( ModificationOperation.REMOVE_ATTRIBUTE, attr );
278             addDelta( mi );
279         }
280         catch ( NamingException e )
281         {
282             e.printStackTrace();
283         }
284     }
285 
286 
287     private void addDelta( Modification mi )
288     {
289         String key = mi.getAttribute().getUpId();
290         List<Modification> deltas;
291         changes.add( mi );
292         
293         if ( keyToChange.containsKey( key ) )
294         {
295             deltas = keyToChange.get( key );
296         }
297         else
298         {
299             deltas = new ArrayList<Modification>();
300         }
301 
302         deltas.add( mi );
303         keyToChange.put( key, deltas );
304     }
305 
306 
307     protected String getSpi( String key )
308     {
309         try
310         {
311             EntryAttribute attr = directoryService.getAdminSession().lookup( dn ).get( key );
312             
313             if ( keyToChange.containsKey( key ) )
314             {
315                 for ( Modification mod : keyToChange.get( key ) )
316                 {
317                     if ( mod.getOperation() == ModificationOperation.REMOVE_ATTRIBUTE )
318                     {
319                         attr = null;
320                     }
321                     else
322                     {
323                         attr = mod.getAttribute();
324                     }
325                 }
326             }
327 
328             if ( attr == null )
329             {
330                 return null;
331             }
332             else
333             {
334                 return attr.getString();
335             }
336         }
337         catch ( Exception e )
338         {
339             throw new ServerSystemPreferenceException( "Failed to get SPI.", e );
340         }
341     }
342 
343 
344     protected void putSpi( String key, String value )
345     {
346         AttributeType at;
347         try
348         {
349             at = directoryService.getRegistries().getAttributeTypeRegistry().lookup( key );
350             ServerAttribute attr = new DefaultServerAttribute( at, value );
351             Modification mi = new ServerModification( ModificationOperation.REPLACE_ATTRIBUTE, attr );
352             addDelta( mi );
353         }
354         catch ( NamingException e )
355         {
356             e.printStackTrace();
357         }
358     }
359 
360 
361     protected AbstractPreferences childSpi( String name )
362     {
363         return new ServerSystemPreferences( this, name );
364     }
365 }