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.trigger;
21
22
23 import org.apache.directory.server.constants.ApacheSchemaConstants;
24 import org.apache.directory.server.constants.ServerDNConstants;
25 import org.apache.directory.server.core.CoreSession;
26 import org.apache.directory.server.core.DefaultCoreSession;
27 import org.apache.directory.server.core.DirectoryService;
28 import org.apache.directory.server.core.authn.LdapPrincipal;
29 import org.apache.directory.server.core.entry.ClonedServerEntry;
30 import org.apache.directory.server.core.entry.ServerEntry;
31 import org.apache.directory.server.core.filtering.EntryFilteringCursor;
32 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
33 import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
34 import org.apache.directory.server.core.partition.PartitionNexus;
35 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
36 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
37 import org.apache.directory.shared.ldap.constants.SchemaConstants;
38 import org.apache.directory.shared.ldap.entry.EntryAttribute;
39 import org.apache.directory.shared.ldap.entry.Modification;
40 import org.apache.directory.shared.ldap.entry.Value;
41 import org.apache.directory.shared.ldap.filter.EqualityNode;
42 import org.apache.directory.shared.ldap.filter.ExprNode;
43 import org.apache.directory.shared.ldap.message.AliasDerefMode;
44 import org.apache.directory.shared.ldap.name.LdapDN;
45 import org.apache.directory.shared.ldap.schema.NormalizerMappingResolver;
46 import org.apache.directory.shared.ldap.schema.OidNormalizer;
47 import org.apache.directory.shared.ldap.trigger.TriggerSpecification;
48 import org.apache.directory.shared.ldap.trigger.TriggerSpecificationParser;
49 import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import javax.naming.directory.SearchControls;
54 import java.text.ParseException;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.HashMap;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Map;
61
62
63
64
65
66
67
68
69
70
71 public class TriggerSpecCache
72 {
73
74 private static final String PRESCRIPTIVE_TRIGGER_ATTR = "prescriptiveTriggerSpecification";
75
76
77 private static final Logger LOG = LoggerFactory.getLogger( TriggerSpecCache.class );
78
79
80 private final Map<String, List<TriggerSpecification>> triggerSpecs = new HashMap<String, List<TriggerSpecification>>();
81
82 private final PartitionNexus nexus;
83
84 private final TriggerSpecificationParser triggerSpecParser;
85
86
87
88
89
90
91
92
93 public TriggerSpecCache( DirectoryService directoryService ) throws Exception
94 {
95 this.nexus = directoryService.getPartitionNexus();
96 final AttributeTypeRegistry registry = directoryService.getRegistries().getAttributeTypeRegistry();
97 triggerSpecParser = new TriggerSpecificationParser( new NormalizerMappingResolver()
98 {
99 public Map<String, OidNormalizer> getNormalizerMapping() throws Exception
100 {
101 return registry.getNormalizerMapping();
102 }
103 });
104 initialize( directoryService );
105 }
106
107
108 private void initialize( DirectoryService directoryService ) throws Exception
109 {
110
111
112
113 Iterator<String> suffixes = nexus.listSuffixes( null );
114
115 while ( suffixes.hasNext() )
116 {
117 String suffix = suffixes.next();
118 LdapDN baseDn = new LdapDN( suffix );
119 ExprNode filter = new EqualityNode<String>( SchemaConstants.OBJECT_CLASS_AT,
120 new ClientStringValue( ApacheSchemaConstants.TRIGGER_EXECUTION_SUBENTRY_OC ) );
121 SearchControls ctls = new SearchControls();
122 ctls.setSearchScope( SearchControls.SUBTREE_SCOPE );
123
124 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
125 adminDn.normalize( directoryService.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
126 CoreSession adminSession = new DefaultCoreSession(
127 new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), directoryService );
128 EntryFilteringCursor results = nexus.search( new SearchOperationContext(
129 adminSession, baseDn, AliasDerefMode.DEREF_ALWAYS, filter, ctls ) );
130
131 while ( results.next() )
132 {
133 ClonedServerEntry resultEntry = results.get();
134 LdapDN subentryDn = resultEntry.getDn();
135 EntryAttribute triggerSpec = resultEntry.get( PRESCRIPTIVE_TRIGGER_ATTR );
136
137 if ( triggerSpec == null )
138 {
139 LOG.warn( "Found triggerExecutionSubentry '" + subentryDn + "' without any " + PRESCRIPTIVE_TRIGGER_ATTR );
140 continue;
141 }
142
143 LdapDN normSubentryName = subentryDn.normalize( directoryService.getRegistries()
144 .getAttributeTypeRegistry().getNormalizerMapping() );
145 subentryAdded( normSubentryName, resultEntry );
146 }
147
148 results.close();
149 }
150 }
151
152
153 private boolean hasPrescriptiveTrigger( ServerEntry entry ) throws Exception
154 {
155
156 EntryAttribute triggerSpec = entry.get( PRESCRIPTIVE_TRIGGER_ATTR );
157
158 return triggerSpec != null;
159 }
160
161
162 public void subentryAdded( LdapDN normName, ServerEntry entry ) throws Exception
163 {
164
165 EntryAttribute triggerSpec = entry.get( PRESCRIPTIVE_TRIGGER_ATTR );
166
167 if ( triggerSpec == null )
168 {
169 return;
170 }
171
172 List<TriggerSpecification> subentryTriggerSpecs = new ArrayList<TriggerSpecification>();
173
174 for ( Value<?> value:triggerSpec )
175 {
176 TriggerSpecification item = null;
177
178 try
179 {
180 item = triggerSpecParser.parse( ( String ) value.get() );
181 subentryTriggerSpecs.add( item );
182 }
183 catch ( ParseException e )
184 {
185 String msg = "TriggerSpecification parser failure on '" + item + "'. Cannnot add Trigger Specificaitons to TriggerSpecCache.";
186 LOG.error( msg, e );
187 }
188
189 }
190
191 triggerSpecs.put( normName.toString(), subentryTriggerSpecs );
192 }
193
194
195 public void subentryDeleted( LdapDN normName, ServerEntry entry ) throws Exception
196 {
197 if ( !hasPrescriptiveTrigger( entry ) )
198 {
199 return;
200 }
201
202 triggerSpecs.remove( normName.toString() );
203 }
204
205
206 public void subentryModified( ModifyOperationContext opContext, ServerEntry entry ) throws Exception
207 {
208 if ( !hasPrescriptiveTrigger( entry ) )
209 {
210 return;
211 }
212
213 LdapDN normName = opContext.getDn();
214 List<Modification> mods = opContext.getModItems();
215
216 boolean isTriggerSpecModified = false;
217
218 for ( Modification mod : mods )
219 {
220 isTriggerSpecModified |= mod.getAttribute().contains( PRESCRIPTIVE_TRIGGER_ATTR );
221 }
222
223 if ( isTriggerSpecModified )
224 {
225 subentryDeleted( normName, entry );
226 subentryAdded( normName, entry );
227 }
228 }
229
230
231 public List<TriggerSpecification> getSubentryTriggerSpecs( String subentryDn )
232 {
233 List<TriggerSpecification> subentryTriggerSpecs = triggerSpecs.get( subentryDn );
234 if ( subentryTriggerSpecs == null )
235 {
236 return Collections.emptyList();
237 }
238 return Collections.unmodifiableList( subentryTriggerSpecs );
239 }
240
241
242 public void subentryRenamed( LdapDN oldName, LdapDN newName )
243 {
244 triggerSpecs.put( newName.toString(), triggerSpecs.remove( oldName.toString() ) );
245 }
246 }