001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.portal.profile.impl;
018:
019: import java.io.Serializable;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Map;
024:
025: import org.apache.avalon.framework.CascadingRuntimeException;
026: import org.apache.avalon.framework.configuration.Configuration;
027: import org.apache.avalon.framework.configuration.ConfigurationException;
028: import org.apache.avalon.framework.service.ServiceException;
029: import org.apache.avalon.framework.service.ServiceSelector;
030: import org.apache.cocoon.ProcessingException;
031: import org.apache.cocoon.portal.PortalService;
032: import org.apache.cocoon.portal.coplet.CopletFactory;
033: import org.apache.cocoon.portal.coplet.CopletInstanceData;
034: import org.apache.cocoon.portal.coplet.adapter.CopletAdapter;
035: import org.apache.cocoon.portal.layout.Layout;
036: import org.apache.cocoon.portal.layout.LayoutFactory;
037: import org.apache.cocoon.portal.profile.PortalUser;
038: import org.apache.cocoon.portal.profile.ProfileLS;
039: import org.apache.cocoon.portal.util.DeltaApplicableReferencesAdjustable;
040: import org.apache.cocoon.portal.util.ProfileException;
041: import org.apache.cocoon.webapps.authentication.AuthenticationManager;
042: import org.apache.cocoon.webapps.authentication.configuration.ApplicationConfiguration;
043: import org.apache.cocoon.webapps.authentication.user.RequestState;
044: import org.apache.cocoon.webapps.authentication.user.UserHandler;
045: import org.apache.commons.collections.map.LinkedMap;
046: import org.apache.commons.lang.exception.ExceptionUtils;
047: import org.apache.excalibur.source.SourceNotFoundException;
048: import org.apache.excalibur.source.SourceValidity;
049:
050: /**
051: * The profile manager using the authentication framework
052: *
053: * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
054: * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a>
055: * @deprecated Use the {@link org.apache.cocoon.portal.profile.impl.GroupBasedProfileManager}
056: * @version CVS $Id: AuthenticationProfileManager.java 433543 2006-08-22 06:22:54Z crossley $
057: */
058: public class AuthenticationProfileManager extends
059: AbstractUserProfileManager {
060:
061: protected ReadWriteLock lock = new ReadWriteLock();
062:
063: protected Map attributes = new HashMap();
064:
065: /**
066: * Get the current authentication state of the user
067: * @return the current authentication state of the user
068: */
069: protected RequestState getRequestState() {
070: AuthenticationManager authManager = null;
071: try {
072: authManager = (AuthenticationManager) this .manager
073: .lookup(AuthenticationManager.ROLE);
074: return authManager.getState();
075: } catch (ServiceException ce) {
076: // ignore this here
077: return null;
078: } finally {
079: this .manager.release(authManager);
080: }
081: }
082:
083: /**
084: * This loads a new profile
085: */
086: protected Layout loadProfile(String layoutKey,
087: PortalService service, CopletFactory copletFactory,
088: LayoutFactory layoutFactory, ServiceSelector adapterSelector)
089: throws Exception {
090: final RequestState state = this .getRequestState();
091: final UserHandler handler = state.getHandler();
092: final ApplicationConfiguration ac = state
093: .getApplicationConfiguration();
094: if (ac == null) {
095: throw new ProcessingException(
096: "Configuration for portal not found in application configuration.");
097: }
098: final Configuration appConf = ac.getConfiguration("portal");
099: if (appConf == null) {
100: throw new ProcessingException(
101: "Configuration for portal not found in application configuration.");
102: }
103: final Configuration config = appConf.getChild("profiles");
104:
105: HashMap parameters = new HashMap();
106: parameters.put("config", config);
107: parameters.put("handler", handler);
108: CopletDataManager copletDataManager = null;
109: try {
110: this .lock.readLock();
111:
112: // load coplet base data
113: parameters.put("profiletype", "copletbasedata");
114: parameters.put("objectmap", null);
115:
116: Object[] result = this .getProfile(layoutKey, parameters,
117: null, false, service);
118: CopletBaseDataManager copletBaseDataManager = (CopletBaseDataManager) result[0];
119:
120: // load coplet data
121: parameters.put("profiletype", "copletdata");
122: parameters.put("objectmap", copletBaseDataManager
123: .getCopletBaseData());
124: copletDataManager = (CopletDataManager) this
125: .getDeltaProfile(layoutKey, parameters, service,
126: copletFactory, ((Boolean) result[1])
127: .booleanValue());
128: service.setAttribute("CopletData:" + layoutKey,
129: copletDataManager);
130: } finally {
131: this .lock.releaseLocks();
132: }
133: // load coplet instance data
134: parameters.put("profiletype", "copletinstancedata");
135: parameters.put("objectmap", copletDataManager.getCopletData());
136: CopletInstanceDataManager copletInstanceDataManager = (CopletInstanceDataManager) this
137: .getOrCreateProfile(layoutKey, parameters, service,
138: copletFactory);
139: service.setAttribute("CopletInstanceData:" + layoutKey,
140: copletInstanceDataManager);
141:
142: // load layout
143: parameters.put("profiletype", "layout");
144: parameters.put("objectmap", copletInstanceDataManager
145: .getCopletInstanceData());
146: Layout layout = (Layout) this .getOrCreateProfile(layoutKey,
147: parameters, service, layoutFactory);
148: service.setAttribute("Layout:" + layoutKey, layout);
149:
150: // now invoke login on each instance
151: Iterator iter = copletInstanceDataManager
152: .getCopletInstanceData().values().iterator();
153: while (iter.hasNext()) {
154: CopletInstanceData cid = (CopletInstanceData) iter.next();
155: CopletAdapter adapter = null;
156: try {
157: adapter = (CopletAdapter) adapterSelector.select(cid
158: .getCopletData().getCopletBaseData()
159: .getCopletAdapterName());
160: adapter.login(cid);
161: } finally {
162: adapterSelector.release(adapter);
163: }
164: }
165:
166: return layout;
167: }
168:
169: /* (non-Javadoc)
170: * @see org.apache.cocoon.portal.profile.ProfileManager#saveUserCopletInstanceDatas(java.lang.String)
171: */
172: public void saveUserCopletInstanceDatas(String layoutKey) {
173: ProfileLS adapter = null;
174: PortalService service = null;
175: try {
176: adapter = (ProfileLS) this .manager.lookup(ProfileLS.ROLE);
177: service = (PortalService) this .manager
178: .lookup(PortalService.ROLE);
179: if (layoutKey == null) {
180: layoutKey = service.getDefaultLayoutKey();
181: }
182:
183: final RequestState state = this .getRequestState();
184: final UserHandler handler = state.getHandler();
185:
186: final HashMap parameters = new HashMap();
187: parameters.put("type", "user");
188: parameters.put("config", state
189: .getApplicationConfiguration().getConfiguration(
190: "portal").getChild("profiles"));
191: parameters.put("handler", handler);
192: parameters.put("profiletype", "copletinstancedata");
193:
194: final Map key = this .buildKey(service, parameters,
195: layoutKey, false);
196:
197: final CopletInstanceDataManager profileManager = ((CopletInstanceDataManager) service
198: .getAttribute("CopletInstanceData:" + layoutKey));
199: adapter.saveProfile(key, parameters, profileManager);
200: } catch (Exception e) {
201: // TODO
202: throw new CascadingRuntimeException(
203: "Exception during save profile", e);
204: } finally {
205: this .manager.release(adapter);
206: this .manager.release(service);
207: }
208: }
209:
210: /* (non-Javadoc)
211: * @see org.apache.cocoon.portal.profile.ProfileManager#saveUserLayout(java.lang.String)
212: */
213: public void saveUserLayout(String layoutKey) {
214: ProfileLS adapter = null;
215: PortalService service = null;
216: try {
217: adapter = (ProfileLS) this .manager.lookup(ProfileLS.ROLE);
218: service = (PortalService) this .manager
219: .lookup(PortalService.ROLE);
220: if (layoutKey == null) {
221: layoutKey = service.getDefaultLayoutKey();
222: }
223:
224: final RequestState state = this .getRequestState();
225: final UserHandler handler = state.getHandler();
226:
227: final HashMap parameters = new HashMap();
228: parameters.put("type", "user");
229: parameters.put("config", state
230: .getApplicationConfiguration().getConfiguration(
231: "portal").getChild("profiles"));
232: parameters.put("handler", handler);
233: parameters.put("profiletype", "layout");
234:
235: final Map key = this .buildKey(service, parameters,
236: layoutKey, false);
237: final Layout layout = (Layout) service
238: .getAttribute("Layout:" + layoutKey);
239: adapter.saveProfile(key, parameters, layout);
240:
241: } catch (Exception e) {
242: // TODO
243: throw new CascadingRuntimeException(
244: "Exception during save profile", e);
245: } finally {
246: this .manager.release(adapter);
247: this .manager.release(service);
248: }
249: }
250:
251: /**
252: * Gets a profile and applies possible user and role deltas to it.
253: */
254: protected Object getDeltaProfile(String layoutKey, Map parameters,
255: PortalService service, Object factory, boolean forcedLoad)
256: throws Exception {
257: DeltaApplicableReferencesAdjustable result;
258: Object object;
259:
260: parameters.put("type", "global");
261: Object global = this .getProfile(layoutKey, parameters, factory,
262: forcedLoad, service)[0];
263: Object key = this
264: .buildKey(service, parameters, layoutKey, true);
265: result = (DeltaApplicableReferencesAdjustable) this
266: .loadProfile(key, parameters, factory);
267:
268: // load role delta
269: parameters.put("type", "role");
270: try {
271: object = this .getProfile(layoutKey, parameters, factory,
272: forcedLoad, service)[0];
273: if (object != null)
274: result.applyDelta(object);
275: } catch (Exception e) {
276: if (!isSourceNotFoundException(e))
277: throw e;
278: }
279:
280: // load user delta
281: parameters.put("type", "user");
282: try {
283: key = this .buildKey(service, parameters, layoutKey, true);
284: object = this .loadProfile(key, parameters, factory);
285: if (object != null)
286: result.applyDelta(object);
287: } catch (Exception e) {
288: if (!isSourceNotFoundException(e))
289: throw e;
290: }
291:
292: if (result == null)
293: throw new SourceNotFoundException(
294: "Global profile does not exist.");
295:
296: // change references to objects where no delta has been applied
297: result.adjustReferences(global);
298:
299: // FIXME
300: this .attributes.put(key, result);
301:
302: return result;
303: }
304:
305: /**
306: * Gets a user profile and creates it by copying the role or the global profile.
307: */
308: protected Object getOrCreateProfile(String layoutKey,
309: Map parameters, PortalService service, Object factory)
310: throws Exception {
311: Object result;
312:
313: // load user profile
314: parameters.put("type", "user");
315: Map keyMap = this
316: .buildKey(service, parameters, layoutKey, true);
317: try {
318: result = this .loadProfile(keyMap, parameters, factory);
319: } catch (Exception e1) {
320: if (!isSourceNotFoundException(e1))
321: throw e1;
322:
323: // load role profile
324: parameters.put("type", "role");
325: keyMap = this
326: .buildKey(service, parameters, layoutKey, true);
327: try {
328: result = this .loadProfile(keyMap, parameters, factory);
329: } catch (Exception e2) {
330: if (!isSourceNotFoundException(e2))
331: throw e2;
332:
333: // load global profile
334: parameters.put("type", "global");
335: keyMap = this .buildKey(service, parameters, layoutKey,
336: true);
337: result = this .loadProfile(keyMap, parameters, factory);
338: }
339:
340: // save profile as user profile
341: ProfileLS adapter = null;
342: try {
343: adapter = (ProfileLS) this .manager
344: .lookup(ProfileLS.ROLE);
345: parameters.put("type", "user");
346: keyMap = this .buildKey(service, parameters, layoutKey,
347: false);
348:
349: //adapter.saveProfile(keyMap, parameters, result);
350: } finally {
351: this .manager.release(adapter);
352: }
353: }
354:
355: // FIXME
356: this .attributes.put(keyMap, result);
357:
358: return result;
359: }
360:
361: /**
362: * Gets a profile.
363: * @return result[0] is the profile, result[1] is a Boolean,
364: * which signals whether the profile has been loaded or reused.
365: */
366: protected Object[] getProfile(String layoutKey, Map parameters,
367: Object factory, boolean forcedLoad, PortalService service)
368: throws Exception {
369: final Map key = this .buildKey(service, parameters, layoutKey,
370: true);
371:
372: ProfileLS adapter = null;
373: try {
374: adapter = (ProfileLS) this .manager.lookup(ProfileLS.ROLE);
375:
376: Object result = this .checkValidity(key, parameters,
377: forcedLoad, adapter);
378:
379: if (result != null && !(result instanceof SourceValidity)) {
380: return new Object[] { result, Boolean.FALSE };
381: }
382: SourceValidity newValidity = (SourceValidity) result;
383:
384: this .lock.releaseReadLock();
385: this .lock.writeLock();
386:
387: // check validity again in case of another thread has already loaded
388: result = this .checkValidity(key, parameters, forcedLoad,
389: adapter);
390:
391: if (result != null && !(result instanceof SourceValidity)) {
392: return new Object[] { result, Boolean.FALSE };
393: }
394: newValidity = (SourceValidity) result;
395:
396: Object object = adapter.loadProfile(key, parameters);
397: this .prepareObject(object, factory);
398: if (newValidity != null) {
399: this .attributes.put(key, new Object[] { object,
400: newValidity });
401: }
402:
403: return new Object[] { object, Boolean.TRUE };
404: } catch (SourceNotFoundException se) {
405: this .getLogger().warn(
406: "Unable to locate profile: " + se.getMessage());
407: throw se;
408: } catch (ProfileException pe) {
409: this .getLogger().error(
410: "Error loading profile: " + pe.getMessage(), pe);
411: throw pe;
412: } catch (Exception t) {
413: this .getLogger().error("Error loading profile.", t);
414: throw t;
415: } finally {
416: this .manager.release(adapter);
417: }
418: }
419:
420: /**
421: * If the profile is valid itself is returned, otherwise a newly created SourceValidity object is returned.
422: */
423: protected Object checkValidity(Object key, Map parameters,
424: boolean forcedLoad, ProfileLS adapter) {
425: Object[] objects = (Object[]) this .attributes.get(key);
426:
427: SourceValidity sourceValidity = null;
428: int valid = SourceValidity.INVALID;
429: if (objects != null) {
430: sourceValidity = (SourceValidity) objects[1];
431: valid = sourceValidity.isValid();
432: if (!forcedLoad && valid == SourceValidity.VALID)
433: return objects[0];
434: }
435:
436: SourceValidity newValidity = adapter.getValidity(key,
437: parameters);
438: if (!forcedLoad && valid == SourceValidity.UNKNOWN) {
439: if (sourceValidity.isValid(newValidity) == SourceValidity.VALID)
440: return objects[0];
441: }
442:
443: return newValidity;
444: }
445:
446: /**
447: * Loads a profile.
448: */
449: protected Object loadProfile(Object key, Map map, Object factory)
450: throws Exception {
451: ProfileLS adapter = null;
452: try {
453: adapter = (ProfileLS) this .manager.lookup(ProfileLS.ROLE);
454:
455: Object object = adapter.loadProfile(key, map);
456: this .prepareObject(object, factory);
457:
458: return object;
459: } finally {
460: this .manager.release(adapter);
461: }
462: }
463:
464: private boolean isSourceNotFoundException(Throwable t) {
465: while (t != null) {
466: if (t instanceof SourceNotFoundException) {
467: return true;
468: }
469: t = ExceptionUtils.getCause(t);
470: }
471: return false;
472: }
473:
474: protected Map buildKey(PortalService service, Map parameters,
475: String layoutKey, boolean load) throws ProcessingException,
476: ConfigurationException {
477:
478: // TODO Change to KeyManager usage
479: final String type = (String) parameters.get("type");
480: final Configuration config = (Configuration) parameters
481: .get("config");
482: final String profileType = (String) parameters
483: .get("profiletype");
484: final String postFix = (load ? "load" : "save");
485: final UserHandler handler = (UserHandler) parameters
486: .get("handler");
487:
488: String uri = null;
489: if (type == null) {
490: uri = config.getChild(profileType + "-" + postFix)
491: .getAttribute("uri");
492: } else if (type.equals("global")) {
493: uri = config.getChild(profileType + "-global-" + postFix)
494: .getAttribute("uri");
495: } else if (type.equals("role")) {
496: uri = config.getChild(profileType + "-role-" + postFix)
497: .getAttribute("uri");
498: } else if (type.equals("user")) {
499: uri = config.getChild(profileType + "-user-" + postFix)
500: .getAttribute("uri");
501: }
502:
503: Map key = new LinkedMap();
504: key.put("baseuri", uri);
505: key.put("separator", "?");
506: key.put("portal", service.getPortalName());
507: key.put("layout", layoutKey);
508: if (type != null) {
509: key.put("type", type);
510: if ("role".equals(type) || "user".equals(type)) {
511: key.put("role", handler.getContext().getContextInfo()
512: .get("role"));
513: }
514: if ("user".equals(type)) {
515: key.put("user", handler.getUserId());
516: }
517: }
518: return key;
519: }
520:
521: static class ReadWriteLock {
522: private Thread activeWriter = null;
523: private HashSet activeReaders = new HashSet();
524: private int waitingWriters = 0;
525:
526: public void readLock() throws InterruptedException {
527: synchronized (ReadWriteLock.this ) {
528: while (this .activeWriter != null
529: || this .waitingWriters != 0) {
530: ReadWriteLock.this .wait();
531: }
532: this .activeReaders.add(Thread.currentThread());
533: }
534: }
535:
536: public void writeLock() throws InterruptedException {
537: synchronized (ReadWriteLock.this ) {
538: Thread current = Thread.currentThread();
539:
540: if (this .activeWriter != current) {
541: this .waitingWriters++;
542: while (this .activeWriter != null
543: || this .activeReaders.size() != 0) {
544: ReadWriteLock.this .wait();
545: }
546: this .waitingWriters--;
547: this .activeWriter = current;
548: }
549: }
550: }
551:
552: public void releaseReadLock() {
553: synchronized (ReadWriteLock.this ) {
554: Thread current = Thread.currentThread();
555:
556: this .activeReaders.remove(current);
557: if (this .activeReaders.size() == 0
558: && this .waitingWriters > 0) {
559: ReadWriteLock.this .notifyAll();
560: }
561: }
562: }
563:
564: public void releaseLocks() {
565: synchronized (ReadWriteLock.this ) {
566: Thread current = Thread.currentThread();
567: boolean notify = false;
568:
569: if (this .activeWriter == current) {
570: this .activeWriter = null;
571: notify = true;
572: }
573:
574: this .activeReaders.remove(current);
575: if (this .activeReaders.size() == 0
576: && this .waitingWriters > 0) {
577: notify = true;
578: }
579:
580: if (notify) {
581: ReadWriteLock.this .notifyAll();
582: }
583: }
584: }
585: }
586:
587: /* (non-Javadoc)
588: * @see org.apache.cocoon.portal.profile.ProfileManager#getUser()
589: */
590: public PortalUser getUser() {
591: final RequestState state = this .getRequestState();
592: return new User(state);
593: }
594:
595: protected static final class User implements PortalUser,
596: Serializable {
597:
598: protected final RequestState state;
599:
600: public User(RequestState state) {
601: this .state = state;
602: }
603:
604: /* (non-Javadoc)
605: * @see org.apache.cocoon.portal.profile.PortalUser#getGroup()
606: */
607: public String getGroup() {
608: // TODO Auto-generated method stub
609: return null;
610: }
611:
612: /* (non-Javadoc)
613: * @see org.apache.cocoon.portal.profile.PortalUser#getUserName()
614: */
615: public String getUserName() {
616: return this .state.getHandler().getUserId();
617: }
618:
619: /* (non-Javadoc)
620: * @see org.apache.cocoon.portal.profile.PortalUser#isUserInRole(java.lang.String)
621: */
622: public boolean isUserInRole(String role) {
623: return this.state.getHandler().isUserInRole(role);
624: }
625: }
626:
627: }
|