1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.prefs;
18
19
20 import org.apache.ldap.common.Lockable;
21 import org.apache.ldap.common.message.LockableAttributeImpl;
22 import org.apache.ldap.common.message.LockableAttributesImpl;
23 import org.apache.ldap.common.util.PreferencesDictionary;
24 import org.apache.ldap.server.jndi.CoreContextFactory;
25
26 import javax.naming.Context;
27 import javax.naming.NameClassPair;
28 import javax.naming.NamingEnumeration;
29 import javax.naming.NamingException;
30 import javax.naming.directory.*;
31 import javax.naming.ldap.InitialLdapContext;
32 import javax.naming.ldap.LdapContext;
33 import java.util.*;
34 import java.util.prefs.AbstractPreferences;
35 import java.util.prefs.BackingStoreException;
36
37
38 /***
39 * A server side system Perferences implementation. This implementation
40 * presumes the creation of a root system preferences node in advance. This
41 * should be included with the system.ldif that is packaged with the server.
42 *
43 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44 * @version $Rev$
45 */
46 public class ServerSystemPreferences extends AbstractPreferences
47 {
48 /*** an empty array of ModificationItems used to get array from list */
49 private static final ModificationItem[] EMPTY_MODS = new ModificationItem[0];
50
51 /*** an empty array of Strings used to get array from list */
52 private static final String[] EMPTY_STRINGS = new String[0];
53
54 /*** the LDAP context representing this preferences object */
55 private LdapContext ctx;
56
57 /*** the changes (ModificationItems) representing cached alterations to preferences */
58 private ArrayList changes = new ArrayList(3);
59
60 /*** maps changes based on key: key->list of mods (on same key) */
61 private HashMap keyToChange = new HashMap(3);
62
63
64 /***
65 * Creates a preferences object for the system preferences root.
66 */
67 public ServerSystemPreferences()
68 {
69 super( null, "" );
70
71 super.newNode = false;
72
73 Hashtable env = new Hashtable();
74
75 env.put( Context.INITIAL_CONTEXT_FACTORY, CoreContextFactory.class.getName() );
76
77 env.put( Context.PROVIDER_URL, PreferencesUtils.SYSPREF_BASE );
78
79 try
80 {
81 ctx = new InitialLdapContext( env, null );
82 }
83 catch ( NamingException e )
84 {
85 e.printStackTrace();
86 }
87 }
88
89
90 /***
91 * Creates a preferences object using a relative name.
92 */
93 public ServerSystemPreferences( ServerSystemPreferences parent, String name )
94 {
95 super( parent, name );
96
97 LdapContext parentCtx = parent.getLdapContext();
98
99 try
100 {
101 ctx = ( LdapContext ) parentCtx.lookup( "prefNodeName=" + name );
102
103 super.newNode = false;
104 }
105 catch ( NamingException e )
106 {
107 super.newNode = true;
108 }
109
110 if ( super.newNode )
111 {
112 try
113 {
114 setUpNode( name );
115 }
116 catch ( NamingException e )
117 {
118 e.printStackTrace();
119 }
120 }
121 }
122
123
124
125
126
127
128
129 /***
130 * Wrapps this ServerPreferences object as a Dictionary.
131 *
132 * @return a Dictionary that uses this ServerPreferences object as the underlying backing store
133 */
134 public Dictionary wrapAsDictionary()
135 {
136 return new PreferencesDictionary( this );
137 }
138
139
140 /***
141 * Gets access to the LDAP context associated with this ServerPreferences node.
142 *
143 * @return the LDAP context associate with this ServerPreferences node
144 */
145 LdapContext getLdapContext()
146 {
147 return ctx;
148 }
149
150
151 /***
152 * Sets up a new ServerPreferences node by injecting the required information
153 * such as the node name attribute and the objectClass attribute.
154 *
155 * @param name the name of the new ServerPreferences node.
156 */
157 private void setUpNode( String name ) throws NamingException
158 {
159 Attributes attrs = new LockableAttributesImpl();
160
161 Attribute attr = new LockableAttributeImpl( ( Lockable ) attrs, "objectClass" );
162
163 attr.add( "top" );
164
165 attr.add( "prefNode" );
166
167 attr.add( "extensibleObject" );
168
169 attrs.put( attr );
170
171 attr = new LockableAttributeImpl( ( Lockable ) attrs, "prefNodeName" );
172
173 attr.add( name );
174
175 attrs.put( attr );
176
177 LdapContext parent = ( ( ServerSystemPreferences ) parent() ).getLdapContext();
178
179 parent.bind( "prefNodeName=" + name, null, attrs );
180
181 ctx = ( LdapContext ) parent.lookup( "prefNodeName=" + name );
182
183 super.newNode = false;
184 }
185
186
187
188
189
190
191
192 protected void flushSpi() throws BackingStoreException
193 {
194 if ( ctx == null )
195 {
196 throw new BackingStoreException( "Ldap context not available for " + super.absolutePath() );
197 }
198
199
200 if ( changes.isEmpty() )
201 {
202 return;
203 }
204
205 try
206 {
207 ctx.modifyAttributes( "", ( ModificationItem[] ) changes.toArray( EMPTY_MODS ) );
208 }
209 catch ( NamingException e )
210 {
211 throw new BackingStoreException( e );
212 }
213
214 changes.clear();
215
216 keyToChange.clear();
217 }
218
219
220 protected void removeNodeSpi() throws BackingStoreException
221 {
222 try
223 {
224 ctx.destroySubcontext( "" );
225 }
226 catch ( NamingException e )
227 {
228 throw new BackingStoreException( e );
229 }
230
231 ctx = null;
232
233 changes.clear();
234
235 keyToChange.clear();
236 }
237
238
239 protected void syncSpi() throws BackingStoreException
240 {
241 if ( ctx == null )
242 {
243 throw new BackingStoreException( "Ldap context not available for " + super.absolutePath() );
244 }
245
246
247 if ( changes.isEmpty() )
248 {
249 return;
250 }
251
252 try
253 {
254 ctx.modifyAttributes( "", ( ModificationItem[] ) changes.toArray( EMPTY_MODS ) );
255 }
256 catch ( NamingException e )
257 {
258 throw new BackingStoreException( e );
259 }
260
261 changes.clear();
262
263 keyToChange.clear();
264 }
265
266
267 protected String[] childrenNamesSpi() throws BackingStoreException
268 {
269 ArrayList children = new ArrayList();
270
271 NamingEnumeration list = null;
272
273 try
274 {
275 list = ctx.list( "" );
276
277 while ( list.hasMore() )
278 {
279 NameClassPair ncp = ( NameClassPair ) list.next();
280
281 children.add( ncp.getName() );
282 }
283 }
284 catch ( NamingException e )
285 {
286 throw new BackingStoreException( e );
287 }
288
289 return ( String[] ) children.toArray( EMPTY_STRINGS );
290 }
291
292
293 protected String[] keysSpi() throws BackingStoreException
294 {
295 Attributes attrs = null;
296
297 ArrayList keys = new ArrayList();
298
299 try
300 {
301 attrs = ctx.getAttributes( "" );
302
303 NamingEnumeration ids = attrs.getIDs();
304
305 while ( ids.hasMore() )
306 {
307 String id = ( String ) ids.next();
308
309 if ( id.equals( "objectClass" ) || id.equals( "prefNodeName" ) )
310 {
311 continue;
312 }
313
314 keys.add( id );
315 }
316 }
317 catch ( NamingException e )
318 {
319 throw new BackingStoreException( e );
320 }
321
322 return ( String[] ) keys.toArray( EMPTY_STRINGS );
323 }
324
325
326 protected void removeSpi( String key )
327 {
328 Attribute attr = new BasicAttribute( key );
329
330 ModificationItem mi = new ModificationItem( DirContext.REMOVE_ATTRIBUTE, attr );
331
332 addDelta( mi );
333 }
334
335
336 private void addDelta( ModificationItem mi )
337 {
338 String key = mi.getAttribute().getID();
339
340 List deltas = null;
341
342 changes.add( mi );
343
344 if ( keyToChange.containsKey( key ) )
345 {
346 deltas = ( List ) keyToChange.get( key );
347 }
348 else
349 {
350 deltas = new ArrayList();
351 }
352
353 deltas.add( mi );
354
355 keyToChange.put( key, deltas );
356 }
357
358
359 protected String getSpi( String key )
360 {
361 String value = null;
362
363 try
364 {
365 Attribute attr = ctx.getAttributes( "" ).get( key );
366
367 if ( keyToChange.containsKey( key ) )
368 {
369 List mods = ( List ) keyToChange.get( key );
370
371 for ( int ii = 0; ii < mods.size(); ii++ )
372 {
373 ModificationItem mi = ( ModificationItem ) mods.get( ii );
374
375 if ( mi.getModificationOp() == DirContext.REMOVE_ATTRIBUTE )
376 {
377 attr = null;
378 }
379 else
380 {
381 attr = mi.getAttribute();
382 }
383 }
384 }
385
386 if ( attr == null )
387 {
388 return null;
389 }
390
391 value = ( String ) attr.get();
392 }
393 catch ( NamingException e )
394 {
395 e.printStackTrace();
396 }
397
398 return value;
399 }
400
401
402 protected void putSpi( String key, String value )
403 {
404 Attribute attr = new BasicAttribute( key );
405
406 attr.add( value );
407
408 ModificationItem mi = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
409
410 addDelta( mi );
411 }
412
413
414 protected AbstractPreferences childSpi( String name )
415 {
416 return new ServerSystemPreferences( this, name );
417 }
418 }