1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.operational;
18
19
20 import java.util.HashSet;
21 import java.util.Map;
22
23 import javax.naming.Name;
24 import javax.naming.NamingEnumeration;
25 import javax.naming.NamingException;
26 import javax.naming.directory.Attributes;
27 import javax.naming.directory.BasicAttribute;
28 import javax.naming.directory.BasicAttributes;
29 import javax.naming.directory.DirContext;
30 import javax.naming.directory.ModificationItem;
31 import javax.naming.directory.SearchControls;
32 import javax.naming.directory.SearchResult;
33 import javax.naming.ldap.LdapContext;
34
35 import org.apache.ldap.common.filter.ExprNode;
36 import org.apache.ldap.common.schema.AttributeType;
37 import org.apache.ldap.common.schema.UsageEnum;
38 import org.apache.ldap.common.util.DateUtils;
39 import org.apache.ldap.server.configuration.InterceptorConfiguration;
40 import org.apache.ldap.server.enumeration.SearchResultFilter;
41 import org.apache.ldap.server.enumeration.SearchResultFilteringEnumeration;
42 import org.apache.ldap.server.interceptor.BaseInterceptor;
43 import org.apache.ldap.server.interceptor.Interceptor;
44 import org.apache.ldap.server.interceptor.NextInterceptor;
45 import org.apache.ldap.server.invocation.InvocationStack;
46 import org.apache.ldap.server.jndi.ContextFactoryConfiguration;
47 import org.apache.ldap.server.partition.ContextPartitionNexus;
48 import org.apache.ldap.server.schema.AttributeTypeRegistry;
49
50
51 /***
52 * An {@link Interceptor} that adds or modifies the default attributes
53 * of entries. There are four default attributes for now;
54 * <tt>'creatorsName'</tt>, <tt>'createTimestamp'</tt>, <tt>'modifiersName'</tt>,
55 * and <tt>'modifyTimestamp'</tt>.
56 *
57 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
58 * @version $Rev: 264732 $, $Date: 2005-08-30 04:04:51 -0400 (Tue, 30 Aug 2005) $
59 */
60 public class OperationalAttributeService extends BaseInterceptor
61 {
62 /***
63 * the database search result filter to register with filter service
64 */
65 private final SearchResultFilter SEARCH_FILTER = new SearchResultFilter()
66 {
67 public boolean accept( LdapContext ctx, SearchResult result, SearchControls controls )
68 throws NamingException
69 {
70 if ( controls.getReturningAttributes() == null )
71 {
72 return filter( result.getAttributes() );
73 }
74
75 return true;
76 }
77 };
78
79 /***
80 * the root nexus of the system
81 */
82 private ContextPartitionNexus nexus;
83
84 private AttributeTypeRegistry registry;
85
86
87 /***
88 * Creates the operational attribute management service interceptor.
89 */
90 public OperationalAttributeService()
91 {
92 }
93
94
95 public void init( ContextFactoryConfiguration factoryCfg, InterceptorConfiguration cfg ) throws NamingException
96 {
97 nexus = factoryCfg.getPartitionNexus();
98 registry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
99 }
100
101
102 public void destroy()
103 {
104 }
105
106
107 /***
108 * Adds extra operational attributes to the entry before it is added.
109 */
110 public void add( NextInterceptor nextInterceptor, String upName, Name normName, Attributes entry ) throws NamingException
111 {
112 String principal = getPrincipal().getName();
113
114 BasicAttribute attribute = new BasicAttribute( "creatorsName" );
115 attribute.add( principal );
116 entry.put( attribute );
117
118 attribute = new BasicAttribute( "createTimestamp" );
119 attribute.add( DateUtils.getGeneralizedTime() );
120 entry.put( attribute );
121
122 nextInterceptor.add( upName, normName, entry );
123 }
124
125
126 public void modify( NextInterceptor nextInterceptor, Name name, int modOp, Attributes attrs) throws NamingException
127 {
128 nextInterceptor.modify( name, modOp, attrs );
129
130
131 Attributes attributes = new BasicAttributes( true );
132 BasicAttribute attribute = new BasicAttribute( "modifiersName" );
133 attribute.add( getPrincipal().getName() );
134 attributes.put( attribute );
135
136 attribute = new BasicAttribute( "modifyTimestamp" );
137 attribute.add( DateUtils.getGeneralizedTime() );
138 attributes.put( attribute );
139
140 nexus.modify( name, DirContext.REPLACE_ATTRIBUTE, attributes );
141 }
142
143
144 public void modify( NextInterceptor nextInterceptor, Name name, ModificationItem[] items ) throws NamingException
145 {
146 nextInterceptor.modify( name, items );
147
148
149 Attributes attributes = new BasicAttributes( true );
150 BasicAttribute attribute = new BasicAttribute( "modifiersName" );
151 attribute.add( getPrincipal().getName() );
152 attributes.put( attribute );
153
154 attribute = new BasicAttribute( "modifyTimestamp" );
155 attribute.add( DateUtils.getGeneralizedTime() );
156 attributes.put( attribute );
157
158 nexus.modify( name, DirContext.REPLACE_ATTRIBUTE, attributes );
159 }
160
161
162 public void modifyRn( NextInterceptor nextInterceptor, Name name, String newRn, boolean deleteOldRn ) throws NamingException
163 {
164 nextInterceptor.modifyRn( name, newRn, deleteOldRn );
165
166
167 Attributes attributes = new BasicAttributes( true );
168 BasicAttribute attribute = new BasicAttribute( "modifiersName" );
169 attribute.add( getPrincipal().getName() );
170 attributes.put( attribute );
171
172 attribute = new BasicAttribute( "modifyTimestamp" );
173 attribute.add( DateUtils.getGeneralizedTime() );
174 attributes.put( attribute );
175
176 Name newDn = name.getSuffix( 1 ).add( newRn );
177 nexus.modify( newDn, DirContext.REPLACE_ATTRIBUTE, attributes );
178 }
179
180
181 public void move( NextInterceptor nextInterceptor, Name name, Name newParentName ) throws NamingException
182 {
183 nextInterceptor.move( name, newParentName );
184
185
186 Attributes attributes = new BasicAttributes( true );
187 BasicAttribute attribute = new BasicAttribute( "modifiersName" );
188 attribute.add( getPrincipal().getName() );
189 attributes.put( attribute );
190
191 attribute = new BasicAttribute( "modifyTimestamp" );
192 attribute.add( DateUtils.getGeneralizedTime() );
193 attributes.put( attribute );
194
195 nexus.modify( newParentName, DirContext.REPLACE_ATTRIBUTE, attributes );
196 }
197
198
199 public void move( NextInterceptor nextInterceptor, Name name, Name newParentName, String newRn, boolean deleteOldRn ) throws NamingException
200 {
201 nextInterceptor.move( name, newParentName, newRn, deleteOldRn );
202
203
204 Attributes attributes = new BasicAttributes( true );
205 BasicAttribute attribute = new BasicAttribute( "modifiersName" );
206 attribute.add( getPrincipal().getName() );
207 attributes.put( attribute );
208
209 attribute = new BasicAttribute( "modifyTimestamp" );
210 attribute.add( DateUtils.getGeneralizedTime() );
211 attributes.put( attribute );
212
213 nexus.modify( newParentName, DirContext.REPLACE_ATTRIBUTE, attributes );
214 }
215
216
217 public Attributes lookup( NextInterceptor nextInterceptor, Name name ) throws NamingException
218 {
219 Attributes result = nextInterceptor.lookup( name );
220 if ( result == null )
221 {
222 return null;
223 }
224 filter( result );
225 return result;
226 }
227
228
229 public Attributes lookup( NextInterceptor nextInterceptor, Name name, String[] attrIds ) throws NamingException
230 {
231 Attributes result = nextInterceptor.lookup( name, attrIds );
232 if ( result == null )
233 {
234 return null;
235 }
236
237 filter( name, result, attrIds );
238 return result;
239 }
240
241
242 public NamingEnumeration list( NextInterceptor nextInterceptor, Name base ) throws NamingException
243 {
244 NamingEnumeration e = nextInterceptor.list( base );
245 LdapContext ctx =
246 ( LdapContext ) InvocationStack.getInstance().peek().getCaller();
247 return new SearchResultFilteringEnumeration( e, new SearchControls(), ctx, SEARCH_FILTER );
248 }
249
250
251 public NamingEnumeration search( NextInterceptor nextInterceptor,
252 Name base, Map env, ExprNode filter,
253 SearchControls searchCtls ) throws NamingException
254 {
255 NamingEnumeration e = nextInterceptor.search( base, env, filter, searchCtls );
256 if ( searchCtls.getReturningAttributes() != null )
257 {
258 return e;
259 }
260
261 LdapContext ctx =
262 ( LdapContext ) InvocationStack.getInstance().peek().getCaller();
263 return new SearchResultFilteringEnumeration( e, searchCtls, ctx, SEARCH_FILTER );
264 }
265
266
267 /***
268 * Filters out the operational attributes within a search results attributes. The attributes are directly
269 * modified.
270 *
271 * @param attributes the resultant attributes to filter
272 * @return true always
273 */
274 private boolean filter( Attributes attributes ) throws NamingException
275 {
276 NamingEnumeration list = attributes.getIDs();
277
278 while ( list.hasMore() )
279 {
280 String attrId = ( String ) list.next();
281
282 AttributeType type = null;
283
284 if ( registry.hasAttributeType( attrId ) )
285 {
286 type = registry.lookup( attrId );
287 }
288
289 if ( type != null && type.getUsage() != UsageEnum.USERAPPLICATIONS )
290 {
291 attributes.remove( attrId );
292 }
293 }
294 return true;
295 }
296
297
298 private void filter( Name dn, Attributes entry, String[] ids )
299 throws NamingException
300 {
301
302 if ( ids == null )
303 {
304 OperationalAttributeService.this.filter( entry );
305 return;
306 }
307
308 if ( dn.size() == 0 )
309 {
310 HashSet idsSet = new HashSet( ids.length );
311
312 for ( int ii = 0; ii < ids.length; ii++ )
313 {
314 idsSet.add( ids[ii].toLowerCase() );
315 }
316
317 NamingEnumeration list = entry.getIDs();
318
319 while ( list.hasMore() )
320 {
321 String attrId = ( ( String ) list.nextElement() ).toLowerCase();
322
323 if ( !idsSet.contains( attrId ) )
324 {
325 entry.remove( attrId );
326 }
327 }
328 }
329
330
331
332
333 }
334 }