001: package de.webman.acl.resolver;
002:
003: import java.util.Hashtable;
004: import com.teamkonzept.lib.PropertyManager;
005: import com.teamkonzept.lib.TKConfigurationException;
006: import com.teamkonzept.lib.TKException;
007: import com.teamkonzept.lib.TKVector;
008: import de.webman.acl.EventFactory;
009: import de.webman.acl.Login;
010: import de.webman.acl.Policy;
011: import de.webman.acl.PolicyFactory;
012: import com.teamkonzept.webman.mainint.WebmanExceptionHandler;
013:
014: /**
015: * Base class for access right resolvers providing core functionality
016: * for subclasses implementing the <CODE>Resolver</CODE> interface.
017: *
018: * @version 1.0
019: * @since 1.0
020: * @author © 2001 Webman AG
021: */
022: public abstract class ResolverBase implements Resolver {
023:
024: // $Header: /cvsroot/webman-cms/source/webman/de/webman/acl/resolver/ResolverBase.java,v 1.1.6.1 2002/05/30 10:23:55 uli Exp $
025:
026: // Constants
027:
028: /**
029: * Dummy object serving as value for hashtable entries.
030: */
031: private static final Object DUMMY = new Object();
032:
033: /**
034: * Empty vector serving as value for cache entries.
035: */
036: private static final TKVector EMPTY = new TKVector(0);
037:
038: // Attributes
039:
040: /**
041: * The login object.
042: */
043: private Login login = null;
044:
045: /**
046: * The hash code of the resolver.
047: */
048: private int hash = 0;
049:
050: /**
051: * The resolution results cache.
052: */
053: private Hashtable resolutionCache = null;
054:
055: /**
056: * The checking results cache.
057: */
058: private Hashtable checkingCache = null;
059:
060: /**
061: * The string representation of the resolver.
062: */
063: private String string = null;
064:
065: // Constructors
066:
067: /**
068: * Provide instantion only to package classes or subclasses.
069: *
070: * @param login the initial login object.
071: */
072: protected ResolverBase(Login login) {
073: this .login = login;
074: }
075:
076: // Standard methods
077:
078: /**
079: * Checks wether the resolver and the given object can be treated as equal.
080: *
081: * @param object the object to be proved upon equality.
082: * @return <CODE>true</CODE> if both objects can be treated as equal,
083: * otherwise <CODE>false</CODE>.
084: */
085: public final boolean equals(Object object) {
086: if (object == null) {
087: return false;
088: }
089:
090: if (object.getClass() != getClass()) {
091: return false;
092: }
093:
094: return ((ResolverBase) object).login.getID().equals(
095: this .login.getID());
096: }
097:
098: /**
099: * Returns the hash code of the resolver.
100: *
101: * @return the hash code of the resolver.
102: */
103: public final int hashCode() {
104: if (this .hash == 0) {
105: this .hash = this .login.getID().intValue();
106: }
107:
108: return this .hash;
109: }
110:
111: /**
112: * Returns the string representation of the resolver.
113: *
114: * @return the string representation of the resolver.
115: */
116: public final String toString() {
117: if (this .string == null) {
118: this .string = (new StringBuffer(getClass().getName()))
119: .append('.').append(login.getID()).toString();
120: }
121:
122: return this .string;
123: }
124:
125: // Implementation of 'com.teamkonzept.lib.ConfigurationListener'.
126:
127: /**
128: * Informs the resolver about changes in its configuration.
129: *
130: * @exception com.teamkonzept.lib.TKException if an error occured during configuration.
131: */
132: public final void configurationChanged() throws TKException {
133: // Configuration value initialization.
134: boolean cacheResolution = false;
135: boolean cacheChecking = false;
136:
137: // Configuration value loading.
138: try {
139: // Obtain property manager.
140: PropertyManager manager = PropertyManager
141: .getPropertyManager(PROPERTY_GROUP_NAME);
142:
143: // Get resolution and checking cache properties.
144: cacheResolution = Boolean.valueOf(
145: manager.getValue(PROPERTY_CACHE_RESOLUTION_RESULTS,
146: DEFAULT_CACHE_RESOLUTION_RESULTS))
147: .booleanValue();
148: cacheChecking = Boolean.valueOf(
149: manager.getValue(PROPERTY_CACHE_CHECKING_RESULTS,
150: DEFAULT_CACHE_CHECKING_RESULTS))
151: .booleanValue();
152: } catch (TKConfigurationException tkce) {
153: // Fall back to default.
154: cacheResolution = Boolean.valueOf(
155: DEFAULT_CACHE_RESOLUTION_RESULTS).booleanValue();
156: cacheChecking = Boolean.valueOf(
157: DEFAULT_CACHE_CHECKING_RESULTS).booleanValue();
158: }
159:
160: // Configuration value evaluation.
161: if (cacheResolution && resolutionCache == null) {
162: // Initialize resolution cache.
163: resolutionCache = new Hashtable();
164: }
165:
166: if (!cacheResolution && resolutionCache != null) {
167: // Destroy resolution cache.
168: resolutionCache = null;
169: }
170:
171: if (Checker.class.isAssignableFrom(this .getClass())) {
172: if (cacheChecking && checkingCache == null) {
173: // Initialize checking cache.
174: checkingCache = new Hashtable();
175: }
176:
177: if (!cacheChecking && checkingCache != null) {
178: // Destroy checking cache.
179: checkingCache = null;
180: }
181: }
182: }
183:
184: // Implementation of 'com.teamkonzept.webman.accesscontrol.resolver.Resolver'.
185:
186: /**
187: * Assigns the login object of the resolver.
188: *
189: * @param login the login object to be assigned.
190: */
191: public final void setLogin(Login login) {
192: this .login = login;
193: }
194:
195: /**
196: * Returns the assigned login object.
197: *
198: * @return the assigned login object.
199: */
200: public final Login getLogin() {
201: return this .login;
202: }
203:
204: /**
205: * This method is provided for the implementation of the actual
206: * access right resolution algorithm, i.e. the calculation of all
207: * allowed events for a login (user or group) in the current application
208: * state. The application state is determined by the context, an object
209: * type and an object reference.
210: * <P>
211: * If the optional arguments are omitted, only the context-wide
212: * access rights are resolved, otherwise the context-wide as well
213: * as the object-specific access rights are resolved.
214: * <P>
215: * The hashed collection is passed recursively to ensure the uniqueness
216: * of the calculated events conveniently.
217: *
218: * @param collection the distinct collection of permitted events.
219: * @param context the ID if the current context (<I>required</I>).
220: * @param type the current object type (<I>optional</I>).
221: * @param reference the current object reference (<I>optional</I>).
222: * @exception com.teamkonzept.lib.TKException if an error occured during
223: * access right resolution.
224: */
225: public abstract void resolve(Hashtable collection, Integer context,
226: Integer type, Integer reference) throws TKException;
227:
228: // Convenience methods
229:
230: /**
231: * Performs access right resolution for all parents of the assigned
232: * login object.
233: *
234: * @param collection the distinct collection of allowed events.
235: * @param context the ID if the current context (<I>required</I>).
236: * @param type the current object type (<I>optional</I>).
237: * @param reference the current object reference (<I>optional</I>).
238: * @exception com.teamkonzept.lib.TKException if an error occured during
239: * access right resolution.
240: */
241: protected final void resolveParents(Hashtable collection,
242: Integer context, Integer type, Integer reference)
243: throws TKException {
244: try {
245: // Get parents.
246: TKVector parents = this .login.getParents();
247:
248: if (parents != null) {
249: int index = 0;
250: int size = parents.size();
251:
252: while (index < size) {
253: // Call each parent's resolver.
254: ResolverFactory.getInstance().getResolver(
255: (Login) parents.elementAt(index++))
256: .resolve(collection, context, type,
257: reference);
258: }
259: }
260: } catch (Exception x) {
261: throw WebmanExceptionHandler.getException(x);
262: }
263: }
264:
265: /**
266: * Performs access right checking for all parents of the assigned
267: * login object.
268: *
269: * @param event the ID if the event to be checked (<I>required</I>).
270: * @param context the ID if the current context (<I>required</I>).
271: * @param type the current object type (<I>optional</I>).
272: * @param reference the current object reference (<I>optional</I>).
273: * @exception com.teamkonzept.lib.TKException if an error occured during
274: * access right checking.
275: */
276: protected final boolean checkParents(Integer event,
277: Integer context, Integer type, Integer reference)
278: throws TKException {
279: boolean value = false;
280:
281: try {
282: // Get parents.
283: TKVector parents = this .login.getParents();
284:
285: if (parents != null) {
286: int index = 0;
287: int size = parents.size();
288:
289: while (index < size && !value) {
290: // Call each parent's checker.
291: value = ResolverFactory.getInstance().getChecker(
292: (Login) parents.elementAt(index++)).check(
293: event, context, type, reference);
294: }
295: }
296: } catch (Exception x) {
297: throw WebmanExceptionHandler.getException(x);
298: }
299:
300: return value;
301: }
302:
303: /**
304: * Retrieves and processes the events associated with the given policies.
305: *
306: * @param collection the distinct collection of allowed events.
307: * @param policies the policies.
308: * @exception com.teamkonzept.lib.TKException if an error occured during event retrieval.
309: */
310: protected final void processPolicies(Hashtable collection,
311: TKVector policies) throws TKException {
312: try {
313: if (policies != null) {
314: int index = 0;
315: int size = policies.size();
316:
317: while (index < size) {
318: // Get policy object.
319: Policy policy = PolicyFactory.getInstance()
320: .getPolicy(
321: (Integer) policies
322: .elementAt(index++));
323:
324: // Get events of policy.
325: processEvents(collection, EventFactory
326: .getInstance().getEventProxies(
327: policy.getID()), policy.isAllowed());
328: }
329: }
330: } catch (Exception x) {
331: throw WebmanExceptionHandler.getException(x);
332: }
333: }
334:
335: /**
336: * Depending on the access flag, the given events are added to the
337: * collection or removed respectively.
338: *
339: * @param collection the distinct collection of allowed events.
340: * @param events the events.
341: * @param access the flag indicating wether the events are allowed or denied.
342: * @exception com.teamkonzept.lib.TKException if an error occured during event retrieval.
343: */
344: protected final void processEvents(Hashtable collection,
345: TKVector events, boolean access) throws TKException {
346: try {
347: if (events != null) {
348: int index = 0;
349: int size = events.size();
350:
351: if (access) {
352: // Add events.
353: while (index < size) {
354: collection
355: .put(events.elementAt(index++), DUMMY);
356: }
357: } else {
358: // Remove events.
359: while (index < size) {
360: collection.remove(events.elementAt(index++));
361: }
362: }
363: }
364: } catch (Exception x) {
365: throw WebmanExceptionHandler.getException(x);
366: }
367: }
368:
369: // Caching methods
370:
371: /**
372: * Writes the given result into the cache.
373: * <P>
374: * The other parameters are used to identify the result.
375: *
376: * @param context the ID of the context.
377: * @param type the object type.
378: * @param reference the object reference.
379: * @param access the access mode.
380: * @param result the result to be cached.
381: */
382: protected final void resolutionCacheWrite(Integer context,
383: Integer type, Integer reference, Boolean access,
384: TKVector result) {
385: if (resolutionCache != null) {
386: resolutionCache.put(toKey(null, context, type, reference,
387: access), result != null ? result : EMPTY);
388: }
389: }
390:
391: /**
392: * Writes the given result into the cache.
393: * <P>
394: * The other parameters are used to identify the result.
395: *
396: * @param event the ID of the event.
397: * @param context the ID of the context.
398: * @param type the object type.
399: * @param reference the object reference.
400: * @param result the result to be cached.
401: */
402: protected final void checkingCacheWrite(Integer event,
403: Integer context, Integer type, Integer reference,
404: Boolean result) {
405: if (checkingCache != null) {
406: checkingCache.put(toKey(event, context, type, reference,
407: null), result != null ? result : Boolean.FALSE);
408: }
409: }
410:
411: /**
412: * Attempts to read a result from the cache.
413: * <P>
414: * The parameters are used to identify the result.
415: *
416: * @param context the ID of the context.
417: * @param type the object type.
418: * @param reference the object reference.
419: * @param access the access mode.
420: * @return the result as found in the cache.
421: */
422: protected final TKVector resolutionCacheRead(Integer context,
423: Integer type, Integer reference, Boolean access) {
424: return resolutionCache != null ? (TKVector) resolutionCache
425: .get(toKey(null, context, type, reference, access))
426: : (TKVector) null;
427: }
428:
429: /**
430: * Attempts to read a result from the cache.
431: * <P>
432: * The parameters are used to identify the result.
433: *
434: * @param event the ID of the event.
435: * @param context the ID of the context.
436: * @param type the object type.
437: * @param reference the object reference.
438: * @return the result as found in the cache.
439: */
440: protected final Boolean checkingCacheRead(Integer event,
441: Integer context, Integer type, Integer reference) {
442: return checkingCache != null ? (Boolean) checkingCache
443: .get(toKey(event, context, type, reference, null))
444: : (Boolean) null;
445: }
446:
447: /**
448: * Returns an unique caching key.
449: * <P>
450: * The parameters are used to generate the key.
451: *
452: * @param event the ID of the event.
453: * @param context the ID of the context.
454: * @param type the object type.
455: * @param reference the object reference.
456: * @param access the access mode.
457: * @return an unique caching key.
458: */
459: protected final Object toKey(Integer event, Integer context,
460: Integer type, Integer reference, Boolean access) {
461: return new Integer((new StringBuffer()).append(event).append(
462: '.').append(context).append('.').append(type).append(
463: '.').append(reference).append('.').append(access)
464: .toString().hashCode());
465: }
466:
467: }
|