1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.mitosis.operation;
21
22
23 import org.apache.directory.mitosis.common.CSN;
24 import org.apache.directory.mitosis.common.CSNFactory;
25 import org.apache.directory.mitosis.common.Constants;
26 import org.apache.directory.mitosis.configuration.ReplicationConfiguration;
27 import org.apache.directory.server.constants.ServerDNConstants;
28 import org.apache.directory.server.core.CoreSession;
29 import org.apache.directory.server.core.DefaultCoreSession;
30 import org.apache.directory.server.core.DirectoryService;
31 import org.apache.directory.server.core.authn.LdapPrincipal;
32 import org.apache.directory.server.core.entry.DefaultServerAttribute;
33 import org.apache.directory.server.core.entry.ServerAttribute;
34 import org.apache.directory.server.core.entry.ServerEntry;
35 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
36 import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
37 import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
38 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
39 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
40 import org.apache.directory.server.core.partition.Partition;
41 import org.apache.directory.server.core.partition.PartitionNexus;
42 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
43 import org.apache.directory.server.schema.registries.Registries;
44 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
45 import org.apache.directory.shared.ldap.constants.SchemaConstants;
46 import org.apache.directory.shared.ldap.entry.EntryAttribute;
47 import org.apache.directory.shared.ldap.entry.Modification;
48 import org.apache.directory.shared.ldap.entry.ModificationOperation;
49 import org.apache.directory.shared.ldap.filter.PresenceNode;
50 import org.apache.directory.shared.ldap.message.AliasDerefMode;
51 import org.apache.directory.shared.ldap.name.LdapDN;
52 import org.apache.directory.shared.ldap.name.Rdn;
53
54 import javax.naming.NameAlreadyBoundException;
55 import javax.naming.NamingException;
56 import javax.naming.directory.SearchControls;
57
58 import java.util.List;
59 import java.util.UUID;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 public class OperationFactory
87 {
88 private final String replicaId;
89 private final PartitionNexus nexus;
90 private final CSNFactory csnFactory;
91
92
93 private final AttributeTypeRegistry attributeRegistry;
94
95
96 private Registries registries;
97
98
99 private DirectoryService ds;
100
101
102 public OperationFactory( DirectoryService directoryService, ReplicationConfiguration cfg )
103 {
104 replicaId = cfg.getReplicaId();
105 nexus = directoryService.getPartitionNexus();
106 csnFactory = cfg.getCsnFactory();
107 registries = directoryService.getRegistries();
108 attributeRegistry = registries.getAttributeTypeRegistry();
109 this.ds = directoryService;
110 }
111
112
113
114
115
116
117 public Operation newAdd( LdapDN normalizedName, ServerEntry entry ) throws Exception
118 {
119 return newAdd( newCSN(), normalizedName, entry );
120 }
121
122
123
124
125
126
127
128
129 private Operation newAdd( CSN csn, LdapDN normalizedName, ServerEntry entry ) throws Exception
130 {
131
132 checkBeforeAdd( normalizedName );
133
134
135 ServerEntry cloneEntry = ( ServerEntry ) entry.clone();
136 cloneEntry.removeAttributes( Constants.ENTRY_UUID );
137 cloneEntry.removeAttributes( Constants.ENTRY_DELETED );
138 cloneEntry.put( Constants.ENTRY_UUID, UUID.randomUUID().toString() );
139 cloneEntry.put( Constants.ENTRY_DELETED, "FALSE" );
140
141
142
143
144 cloneEntry.put( Constants.ENTRY_CSN, csn.toOctetString() );
145
146 return new AddEntryOperation( registries, csn, cloneEntry );
147 }
148
149
150
151
152
153
154
155 public Operation newDelete( LdapDN normalizedName ) throws NamingException
156 {
157 CSN csn = newCSN();
158 CompositeOperation result = new CompositeOperation( registries, csn );
159
160
161 result.add( new ReplaceAttributeOperation( registries, csn, normalizedName,
162 new DefaultServerAttribute(
163 Constants.ENTRY_DELETED,
164 attributeRegistry.lookup( Constants.ENTRY_DELETED ),
165 "TRUE" ) ) );
166
167 return addDefaultOperations( result, csn, normalizedName );
168 }
169
170
171
172
173
174
175
176
177
178
179 public Operation newModify( ModifyOperationContext opContext ) throws NamingException
180 {
181 List<Modification> items = opContext.getModItems();
182 LdapDN normalizedName = opContext.getDn();
183
184 CSN csn = newCSN();
185 CompositeOperation result = new CompositeOperation( registries, csn );
186
187
188 for ( Modification item:items )
189 {
190 result.add(
191 newModify(
192 csn,
193 normalizedName,
194 item.getOperation(),
195 (ServerAttribute)item.getAttribute() ) );
196 }
197
198
199 result.add(
200 new ReplaceAttributeOperation(
201 registries,
202 csn,
203 normalizedName,
204 new DefaultServerAttribute(
205 Constants.ENTRY_DELETED,
206 attributeRegistry.lookup( Constants.ENTRY_DELETED ),
207 "FALSE" ) ) );
208
209 return addDefaultOperations( result, csn, normalizedName );
210 }
211
212
213
214
215
216
217
218
219 private Operation newModify( CSN csn, LdapDN normalizedName, ModificationOperation modOp, ServerAttribute attribute )
220 {
221 switch ( modOp )
222 {
223 case ADD_ATTRIBUTE:
224 return new AddAttributeOperation( registries, csn, normalizedName, attribute );
225
226 case REPLACE_ATTRIBUTE:
227 return new ReplaceAttributeOperation( registries, csn, normalizedName, attribute );
228
229 case REMOVE_ATTRIBUTE:
230 return new DeleteAttributeOperation( registries, csn, normalizedName, attribute );
231
232 default:
233 throw new IllegalArgumentException( "Unknown modOp: " + modOp );
234 }
235 }
236
237
238
239
240
241
242
243
244
245 public Operation newModifyRn( LdapDN oldName, Rdn newRdn, boolean deleteOldRn ) throws Exception
246 {
247 LdapDN newParentName = ( LdapDN ) oldName.clone();
248 newParentName.remove( oldName.size() - 1 );
249
250 return newMove( oldName, newParentName, newRdn, deleteOldRn );
251 }
252
253
254
255
256
257
258
259
260 public Operation newMove( LdapDN oldName, LdapDN newParentName ) throws Exception
261 {
262 return newMove( oldName, newParentName, oldName.getRdn(), true );
263 }
264
265
266
267
268
269
270
271 public Operation newMove( LdapDN oldName, LdapDN newParentName, Rdn newRdn, boolean deleteOldRn )
272 throws Exception
273 {
274
275 CSN csn = newCSN();
276 CompositeOperation result = new CompositeOperation( registries, csn );
277
278
279 SearchControls ctrl = new SearchControls();
280 ctrl.setSearchScope( SearchControls.SUBTREE_SCOPE );
281
282 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
283 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
284 CoreSession adminSession = new DefaultCoreSession(
285 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), ds );
286
287 EntryFilteringCursor cursor = nexus.search(
288 new SearchOperationContext( adminSession, oldName, AliasDerefMode.DEREF_ALWAYS,
289 new PresenceNode( SchemaConstants.OBJECT_CLASS_AT_OID ), ctrl ) );
290
291 while ( cursor.next() )
292 {
293 ServerEntry entry = cursor.get();
294
295
296 LdapDN oldEntryName = entry.getDn();
297 oldEntryName.normalize( attributeRegistry.getNormalizerMapping() );
298
299
300 result.add(
301 new ReplaceAttributeOperation(
302 registries,
303 csn,
304 oldEntryName,
305 new DefaultServerAttribute(
306 Constants.ENTRY_DELETED,
307 attributeRegistry.lookup( Constants.ENTRY_DELETED ),
308 "TRUE" ) ) );
309
310
311 if ( oldEntryName.size() == oldName.size() )
312 {
313 if ( deleteOldRn )
314 {
315
316 String oldRDNAttributeID = oldName.getRdn().getUpType();
317 EntryAttribute oldRDNAttribute = entry.get( oldRDNAttributeID );
318
319 if ( oldRDNAttribute != null )
320 {
321 boolean removed = oldRDNAttribute.remove( (String)oldName.getRdn().getUpValue() );
322
323 if ( removed && oldRDNAttribute.size() == 0 )
324 {
325
326 entry.removeAttributes( oldRDNAttributeID );
327 }
328 }
329 }
330
331
332 String newRDNAttributeID = newRdn.getUpType();
333 String newRDNAttributeValue = ( String ) newRdn.getUpValue();
334 EntryAttribute newRDNAttribute = entry.get( newRDNAttributeID );
335
336 if ( newRDNAttribute != null )
337 {
338 newRDNAttribute.add( newRDNAttributeValue );
339 }
340 else
341 {
342 entry.put( newRDNAttributeID, newRDNAttributeValue );
343 }
344 }
345
346
347 LdapDN newEntryName = ( LdapDN ) newParentName.clone();
348 newEntryName.add( newRdn );
349
350 for ( int i = oldEntryName.size() - newEntryName.size(); i > 0; i-- )
351 {
352 newEntryName.add( oldEntryName.get( oldEntryName.size() - i ) );
353 }
354
355 newEntryName.normalize( attributeRegistry.getNormalizerMapping() );
356
357
358 result.add( newAdd( csn, newEntryName, entry ) );
359
360
361
362
363 addDefaultOperations( result, csn, oldEntryName );
364 }
365
366 return result;
367 }
368
369
370
371
372
373
374
375
376
377 private void checkBeforeAdd( LdapDN newEntryName ) throws Exception
378 {
379 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
380 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
381 CoreSession adminSession = new DefaultCoreSession(
382 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), ds );
383
384 if ( nexus.hasEntry( new EntryOperationContext( adminSession, newEntryName ) ) )
385 {
386 ServerEntry entry = nexus.lookup( new LookupOperationContext( adminSession, newEntryName ) );
387 EntryAttribute deleted = entry.get( Constants.ENTRY_DELETED );
388 Object value = deleted == null ? null : deleted.get();
389
390
391
392
393
394
395 if ( value != null && "TRUE".equalsIgnoreCase( value.toString() ) )
396 {
397 return;
398 }
399
400 throw new NameAlreadyBoundException( newEntryName.toString() + " already exists." );
401 }
402 }
403
404
405
406
407
408
409
410
411 private CompositeOperation addDefaultOperations( CompositeOperation result, CSN csn, LdapDN normalizedName ) throws NamingException
412 {
413 result.add(
414 new ReplaceAttributeOperation(
415 registries,
416 csn,
417 normalizedName,
418 new DefaultServerAttribute(
419 Constants.ENTRY_DELETED,
420 attributeRegistry.lookup( Constants.ENTRY_CSN ),
421 csn.toOctetString() ) ) );
422
423 return result;
424 }
425
426
427
428
429
430 private CSN newCSN()
431 {
432 return csnFactory.newInstance( replicaId );
433 }
434 }