1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.event;
21
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.concurrent.ArrayBlockingQueue;
27 import java.util.concurrent.CopyOnWriteArrayList;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.ThreadPoolExecutor;
30 import java.util.concurrent.TimeUnit;
31
32 import org.apache.directory.server.core.DirectoryService;
33 import org.apache.directory.server.core.entry.ClonedServerEntry;
34 import org.apache.directory.server.core.entry.ServerEntry;
35 import org.apache.directory.server.core.interceptor.BaseInterceptor;
36 import org.apache.directory.server.core.interceptor.NextInterceptor;
37 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
38 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
39 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
40 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
41 import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
42 import org.apache.directory.server.core.interceptor.context.OperationContext;
43 import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
44 import org.apache.directory.server.core.normalization.NormalizingVisitor;
45 import org.apache.directory.server.core.partition.ByPassConstants;
46 import org.apache.directory.server.schema.ConcreteNameComponentNormalizer;
47 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
48 import org.apache.directory.server.schema.registries.OidRegistry;
49 import org.apache.directory.shared.ldap.filter.ExprNode;
50 import org.apache.directory.shared.ldap.name.LdapDN;
51 import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65
66 public class EventInterceptor extends BaseInterceptor
67 {
68 private final static Logger LOG = LoggerFactory.getLogger( EventInterceptor.class );
69
70
71 private List<RegistrationEntry> registrations = new CopyOnWriteArrayList<RegistrationEntry>();
72 private DirectoryService ds;
73 private NormalizingVisitor filterNormalizer;
74 private Evaluator evaluator;
75 private ExecutorService executor;
76
77
78 @Override
79 public void init( DirectoryService ds ) throws Exception
80 {
81 LOG.info( "Initializing ..." );
82 super.init( ds );
83
84 this.ds = ds;
85 OidRegistry oidRegistry = ds.getRegistries().getOidRegistry();
86 AttributeTypeRegistry attributeRegistry = ds.getRegistries().getAttributeTypeRegistry();
87 NameComponentNormalizer ncn = new ConcreteNameComponentNormalizer( attributeRegistry, oidRegistry );
88 filterNormalizer = new NormalizingVisitor( ncn, ds.getRegistries() );
89 evaluator = new ExpressionEvaluator( oidRegistry, attributeRegistry );
90 executor = new ThreadPoolExecutor( 1, 10, 1000, TimeUnit.MILLISECONDS,
91 new ArrayBlockingQueue<Runnable>( 100 ) );
92
93 this.ds.setEventService( new DefaultEventService() );
94 LOG.info( "Initialization complete." );
95 }
96
97
98 private void fire( final OperationContext opContext, EventType type, final DirectoryListener listener )
99 {
100 switch ( type )
101 {
102 case ADD:
103 executor.execute( new Runnable()
104 {
105 public void run()
106 {
107 listener.entryAdded( ( AddOperationContext ) opContext );
108 }
109 });
110 break;
111 case DELETE:
112 executor.execute( new Runnable()
113 {
114 public void run()
115 {
116 listener.entryDeleted( ( DeleteOperationContext ) opContext );
117 }
118 });
119 break;
120 case MODIFY:
121 executor.execute( new Runnable()
122 {
123 public void run()
124 {
125 listener.entryModified( ( ModifyOperationContext ) opContext );
126 }
127 });
128 break;
129 case MOVE:
130 executor.execute( new Runnable()
131 {
132 public void run()
133 {
134 listener.entryMoved( ( MoveOperationContext ) opContext );
135 }
136 });
137 break;
138 case RENAME:
139 executor.execute( new Runnable()
140 {
141 public void run()
142 {
143 listener.entryRenamed( ( RenameOperationContext ) opContext );
144 }
145 });
146 break;
147 }
148 }
149
150
151 public void add( NextInterceptor next, final AddOperationContext opContext ) throws Exception
152 {
153 next.add( opContext );
154 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), opContext.getEntry() );
155
156 if ( selecting.isEmpty() )
157 {
158 return;
159 }
160
161 for ( final RegistrationEntry registration : selecting )
162 {
163 if ( EventType.isAdd( registration.getCriteria().getEventMask() ) )
164 {
165 fire( opContext, EventType.ADD, registration.getListener() );
166 }
167 }
168 }
169
170
171 public void delete( NextInterceptor next, final DeleteOperationContext opContext ) throws Exception
172 {
173 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), opContext.getEntry() );
174 next.delete( opContext );
175
176 if ( selecting.isEmpty() )
177 {
178 return;
179 }
180
181 for ( final RegistrationEntry registration : selecting )
182 {
183 if ( EventType.isDelete( registration.getCriteria().getEventMask() ) )
184 {
185 fire( opContext, EventType.DELETE, registration.getListener() );
186 }
187 }
188 }
189
190
191 public void modify( NextInterceptor next, final ModifyOperationContext opContext ) throws Exception
192 {
193 ClonedServerEntry oriEntry = opContext.lookup( opContext.getDn(), ByPassConstants.LOOKUP_BYPASS );
194 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), oriEntry );
195 next.modify( opContext );
196
197 if ( selecting.isEmpty() )
198 {
199 return;
200 }
201
202 for ( final RegistrationEntry registration : selecting )
203 {
204 if ( EventType.isModify( registration.getCriteria().getEventMask() ) )
205 {
206 fire( opContext, EventType.MODIFY, registration.getListener() );
207 }
208 }
209 }
210
211
212 public void rename( NextInterceptor next, RenameOperationContext opContext ) throws Exception
213 {
214 ClonedServerEntry oriEntry = opContext.lookup( opContext.getDn(), ByPassConstants.LOOKUP_BYPASS );
215 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), oriEntry );
216 next.rename( opContext );
217
218 if ( selecting.isEmpty() )
219 {
220 return;
221 }
222
223 opContext.setAlteredEntry( opContext.lookup( opContext.getNewDn(), ByPassConstants.LOOKUP_BYPASS ) );
224
225 for ( final RegistrationEntry registration : selecting )
226 {
227 if ( EventType.isRename( registration.getCriteria().getEventMask() ) )
228 {
229 fire( opContext, EventType.RENAME, registration.getListener() );
230 }
231 }
232 }
233
234
235 public void moveAndRename( NextInterceptor next, final MoveAndRenameOperationContext opContext ) throws Exception
236 {
237 ClonedServerEntry oriEntry = opContext.lookup( opContext.getDn(), ByPassConstants.LOOKUP_BYPASS );
238 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), oriEntry );
239 next.moveAndRename( opContext );
240
241 if ( selecting.isEmpty() )
242 {
243 return;
244 }
245
246 opContext.setAlteredEntry( opContext.lookup( opContext.getNewDn(), ByPassConstants.LOOKUP_BYPASS ) );
247
248 for ( final RegistrationEntry registration : selecting )
249 {
250 if ( EventType.isMoveAndRename( registration.getCriteria().getEventMask() ) )
251 {
252 executor.execute( new Runnable()
253 {
254 public void run()
255 {
256 registration.getListener().entryMovedAndRenamed( opContext );
257 }
258 });
259 }
260 }
261 }
262
263
264 public void move( NextInterceptor next, MoveOperationContext opContext ) throws Exception
265 {
266 ClonedServerEntry oriEntry = opContext.lookup( opContext.getDn(), ByPassConstants.LOOKUP_BYPASS );
267 List<RegistrationEntry> selecting = getSelectingRegistrations( opContext.getDn(), oriEntry );
268 next.move( opContext );
269
270 if ( selecting.isEmpty() )
271 {
272 return;
273 }
274
275 for ( final RegistrationEntry registration : selecting )
276 {
277 if ( EventType.isMove( registration.getCriteria().getEventMask() ) )
278 {
279 fire( opContext, EventType.MOVE, registration.getListener() );
280 }
281 }
282 }
283
284
285 List<RegistrationEntry> getSelectingRegistrations( LdapDN name, ServerEntry entry ) throws Exception
286 {
287 if ( registrations.isEmpty() )
288 {
289 return Collections.emptyList();
290 }
291
292 List<RegistrationEntry> selecting = new ArrayList<RegistrationEntry>();
293
294 for ( RegistrationEntry registration : registrations )
295 {
296 NotificationCriteria criteria = registration.getCriteria();
297
298 if ( evaluator.evaluate( criteria.getFilter(), criteria.getBase().toNormName(), entry ) )
299 {
300 selecting.add( registration );
301 }
302 }
303
304 return selecting;
305 }
306
307
308
309
310
311
312
313 class DefaultEventService implements EventService
314 {
315
316
317
318 public void addListener( DirectoryListener listener )
319 {
320 registrations.add( new RegistrationEntry( listener ) );
321 }
322
323
324
325
326
327 public void addListener( DirectoryListener listener, NotificationCriteria criteria ) throws Exception
328 {
329 criteria.getBase().normalize( ds.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
330 ExprNode result = ( ExprNode ) criteria.getFilter().accept( filterNormalizer );
331 criteria.setFilter( result );
332 registrations.add( new RegistrationEntry( listener, criteria ) );
333 }
334
335
336 public void removeListener( DirectoryListener listener )
337 {
338 for ( RegistrationEntry entry : registrations )
339 {
340 if ( entry.getListener() == listener )
341 {
342 registrations.remove( entry );
343 }
344 }
345 }
346
347
348 public List<RegistrationEntry> getRegistrationEntries()
349 {
350 return Collections.unmodifiableList( registrations );
351 }
352 }
353 }