0001: /**********************************************************************************
0002: * $URL: https://source.sakaiproject.org/svn/authz/tags/sakai_2-4-1/authz-impl/impl/src/java/org/sakaiproject/authz/impl/BaseAuthzGroupService.java $
0003: * $Id: BaseAuthzGroupService.java 15122 2006-09-22 00:40:48Z ggolden@umich.edu $
0004: ***********************************************************************************
0005: *
0006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007: *
0008: * Licensed under the Educational Community License, Version 1.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.opensource.org/licenses/ecl1.php
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: **********************************************************************************/package org.sakaiproject.authz.impl;
0021:
0022: import java.util.Collection;
0023: import java.util.HashSet;
0024: import java.util.Iterator;
0025: import java.util.List;
0026: import java.util.Map;
0027: import java.util.Set;
0028: import java.util.Stack;
0029: import java.util.Vector;
0030:
0031: import org.apache.commons.logging.Log;
0032: import org.apache.commons.logging.LogFactory;
0033: import org.sakaiproject.authz.api.AuthzGroup;
0034: import org.sakaiproject.authz.api.AuthzGroupService;
0035: import org.sakaiproject.authz.api.AuthzPermissionException;
0036: import org.sakaiproject.authz.api.FunctionManager;
0037: import org.sakaiproject.authz.api.GroupAlreadyDefinedException;
0038: import org.sakaiproject.authz.api.GroupIdInvalidException;
0039: import org.sakaiproject.authz.api.GroupNotDefinedException;
0040: import org.sakaiproject.authz.api.GroupProvider;
0041: import org.sakaiproject.authz.api.Role;
0042: import org.sakaiproject.authz.api.SecurityService;
0043: import org.sakaiproject.component.api.ServerConfigurationService;
0044: import org.sakaiproject.component.cover.ComponentManager;
0045: import org.sakaiproject.entity.api.Edit;
0046: import org.sakaiproject.entity.api.Entity;
0047: import org.sakaiproject.entity.api.EntityManager;
0048: import org.sakaiproject.entity.api.HttpAccess;
0049: import org.sakaiproject.entity.api.Reference;
0050: import org.sakaiproject.entity.api.ResourceProperties;
0051: import org.sakaiproject.event.api.EventTrackingService;
0052: import org.sakaiproject.exception.PermissionException;
0053: import org.sakaiproject.javax.PagingPosition;
0054: import org.sakaiproject.site.cover.SiteService;
0055: import org.sakaiproject.time.api.Time;
0056: import org.sakaiproject.time.api.TimeService;
0057: import org.sakaiproject.tool.api.SessionManager;
0058: import org.sakaiproject.user.api.UserDirectoryService;
0059: import org.sakaiproject.user.api.UserNotDefinedException;
0060: import org.sakaiproject.util.StorageUser;
0061: import org.w3c.dom.Document;
0062: import org.w3c.dom.Element;
0063:
0064: /**
0065: * <p>
0066: * BaseAuthzGroupService is a Sakai azGroup service implementation.
0067: * </p>
0068: * <p>
0069: * To support the public view feature, an AuthzGroup named TEMPLATE_PUBVIEW must exist, with a role named ROLE_PUBVIEW - all the abilities in this role become the public view abilities for any resource.
0070: * </p>
0071: */
0072: public abstract class BaseAuthzGroupService implements
0073: AuthzGroupService, StorageUser {
0074: /** Our logger. */
0075: private static Log M_log = LogFactory
0076: .getLog(BaseAuthzGroupService.class);
0077:
0078: /** Storage manager for this service. */
0079: protected Storage m_storage = null;
0080:
0081: /** The initial portion of a relative access point URL. */
0082: protected String m_relativeAccessPoint = null;
0083:
0084: /** A provider of additional Abilities for a userId. */
0085: protected GroupProvider m_provider = null;
0086:
0087: /**********************************************************************************************************************************************************************************************************************************************************
0088: * Abstractions, etc.
0089: *********************************************************************************************************************************************************************************************************************************************************/
0090:
0091: /**
0092: * Construct storage for this service.
0093: */
0094: protected abstract Storage newStorage();
0095:
0096: /**
0097: * Access the partial URL that forms the root of resource URLs.
0098: *
0099: * @param relative
0100: * if true, form within the access path only (i.e. starting with /content)
0101: * @return the partial URL that forms the root of resource URLs.
0102: */
0103: protected String getAccessPoint(boolean relative) {
0104: return (relative ? "" : serverConfigurationService()
0105: .getAccessUrl())
0106: + m_relativeAccessPoint;
0107: }
0108:
0109: /**
0110: * Access the azGroup id extracted from an AuthzGroup reference.
0111: *
0112: * @param ref
0113: * The azGroup reference string.
0114: * @return The the azGroup id extracted from an AuthzGroup reference.
0115: */
0116: protected String authzGroupId(String ref) {
0117: String start = getAccessPoint(true) + Entity.SEPARATOR;
0118: int i = ref.indexOf(start);
0119: if (i == -1)
0120: return ref;
0121: String id = ref.substring(i + start.length());
0122: return id;
0123: }
0124:
0125: /**
0126: * Check security permission.
0127: *
0128: * @param lock
0129: * The lock id string.
0130: * @param resource
0131: * The resource reference string, or null if no resource is involved.
0132: * @return true if allowd, false if not
0133: */
0134: protected boolean unlockCheck(String lock, String resource) {
0135: if (!securityService().unlock(lock, resource)) {
0136: return false;
0137: }
0138:
0139: return true;
0140: }
0141:
0142: /**
0143: * Check security permission.
0144: *
0145: * @param lock
0146: * The lock id string.
0147: * @param resource
0148: * The resource reference string, or null if no resource is involved.
0149: * @exception PermissionException
0150: * Thrown if the azGroup does not have access
0151: */
0152: protected void unlock(String lock, String resource)
0153: throws AuthzPermissionException {
0154: if (!unlockCheck(lock, resource)) {
0155: throw new AuthzPermissionException(sessionManager()
0156: .getCurrentSessionUserId(), lock, resource);
0157: }
0158: }
0159:
0160: /**
0161: * Create the live properties for the azGroup.
0162: */
0163: protected void addLiveProperties(BaseAuthzGroup azGroup) {
0164: String current = sessionManager().getCurrentSessionUserId();
0165:
0166: azGroup.m_createdUserId = current;
0167: azGroup.m_lastModifiedUserId = current;
0168:
0169: Time now = timeService().newTime();
0170: azGroup.m_createdTime = now;
0171: azGroup.m_lastModifiedTime = (Time) now.clone();
0172: }
0173:
0174: /**
0175: * Update the live properties for an AuthzGroup for when modified.
0176: */
0177: protected void addLiveUpdateProperties(BaseAuthzGroup azGroup) {
0178: String current = sessionManager().getCurrentSessionUserId();
0179:
0180: azGroup.m_lastModifiedUserId = current;
0181: azGroup.m_lastModifiedTime = timeService().newTime();
0182: }
0183:
0184: /**********************************************************************************************************************************************************************************************************************************************************
0185: * Provider configuration
0186: *********************************************************************************************************************************************************************************************************************************************************/
0187:
0188: /**
0189: * Configuration: set the azGroup provider helper service.
0190: *
0191: * @param provider
0192: * the azGroup provider helper service.
0193: */
0194: public void setProvider(GroupProvider provider) {
0195: m_provider = provider;
0196: }
0197:
0198: /**********************************************************************************************************************************************************************************************************************************************************
0199: * Dependencies
0200: *********************************************************************************************************************************************************************************************************************************************************/
0201:
0202: /**
0203: * @return the ServerConfigurationService collaborator.
0204: */
0205: protected abstract ServerConfigurationService serverConfigurationService();
0206:
0207: /**
0208: * @return the EntityManager collaborator.
0209: */
0210: protected abstract EntityManager entityManager();
0211:
0212: /**
0213: * @return the FunctionManager collaborator.
0214: */
0215: protected abstract FunctionManager functionManager();
0216:
0217: /**
0218: * @return the SecurityService collaborator.
0219: */
0220: protected abstract SecurityService securityService();
0221:
0222: /**
0223: * @return the TimeService collaborator.
0224: */
0225: protected abstract TimeService timeService();
0226:
0227: /**
0228: * @return the SessionManager collaborator.
0229: */
0230: protected abstract SessionManager sessionManager();
0231:
0232: /**
0233: * @return the EventTrackingService collaborator.
0234: */
0235: protected abstract EventTrackingService eventTrackingService();
0236:
0237: /**
0238: * @return the ServerConfigurationService collaborator.
0239: */
0240: protected abstract UserDirectoryService userDirectoryService();
0241:
0242: /**********************************************************************************************************************************************************************************************************************************************************
0243: * Init and Destroy
0244: *********************************************************************************************************************************************************************************************************************************************************/
0245:
0246: /**
0247: * Final initialization, once all dependencies are set.
0248: */
0249: public void init() {
0250: try {
0251: m_relativeAccessPoint = REFERENCE_ROOT;
0252:
0253: // construct storage and read
0254: m_storage = newStorage();
0255: m_storage.open();
0256:
0257: // register as an entity producer
0258: entityManager()
0259: .registerEntityProducer(this , REFERENCE_ROOT);
0260:
0261: // register functions
0262: functionManager().registerFunction(SECURE_ADD_AUTHZ_GROUP);
0263: functionManager().registerFunction(
0264: SECURE_REMOVE_AUTHZ_GROUP);
0265: functionManager().registerFunction(
0266: SECURE_UPDATE_AUTHZ_GROUP);
0267: functionManager().registerFunction(
0268: SECURE_UPDATE_OWN_AUTHZ_GROUP);
0269:
0270: // if no provider was set, see if we can find one
0271: if (m_provider == null) {
0272: m_provider = (GroupProvider) ComponentManager
0273: .get(GroupProvider.class.getName());
0274: }
0275:
0276: M_log.info("init(): provider: "
0277: + ((m_provider == null) ? "none" : m_provider
0278: .getClass().getName()));
0279: } catch (Throwable t) {
0280: M_log.warn("init(); ", t);
0281: }
0282: }
0283:
0284: /**
0285: * Returns to uninitialized state.
0286: */
0287: public void destroy() {
0288: m_storage.close();
0289: m_storage = null;
0290:
0291: M_log.info("destroy()");
0292: }
0293:
0294: /**********************************************************************************************************************************************************************************************************************************************************
0295: * AuthzGroupService implementation
0296: *********************************************************************************************************************************************************************************************************************************************************/
0297:
0298: /**
0299: * {@inheritDoc}
0300: */
0301: public List getAuthzGroups(String criteria, PagingPosition page) {
0302: return m_storage.getAuthzGroups(criteria, page);
0303: }
0304:
0305: /**
0306: * {@inheritDoc}
0307: */
0308: public int countAuthzGroups(String criteria) {
0309: return m_storage.countAuthzGroups(criteria);
0310: }
0311:
0312: /**
0313: * {@inheritDoc}
0314: */
0315: public Set getAuthzGroupIds(String providerId) {
0316: return m_storage.getAuthzGroupIds(providerId);
0317: }
0318:
0319: /**
0320: * {@inheritDoc}
0321: */
0322: public Set getProviderIds(String authzGroupId) {
0323: return m_storage.getProviderIds(authzGroupId);
0324: }
0325:
0326: /**
0327: * {@inheritDoc}
0328: */
0329: public AuthzGroup getAuthzGroup(String id)
0330: throws GroupNotDefinedException {
0331: // Note: since this is a "read" operations, we do NOT refresh (i.e. write) the provider info.
0332: if (id == null)
0333: throw new GroupNotDefinedException("<null>");
0334:
0335: AuthzGroup azGroup = m_storage.get(id);
0336:
0337: // if not found
0338: if (azGroup == null) {
0339: throw new GroupNotDefinedException(id);
0340: }
0341:
0342: return azGroup;
0343: }
0344:
0345: /**
0346: * {@inheritDoc}
0347: */
0348: public void joinGroup(String authzGroupId, String roleId)
0349: throws GroupNotDefinedException, AuthzPermissionException {
0350: String user = sessionManager().getCurrentSessionUserId();
0351: if (user == null)
0352: throw new AuthzPermissionException(user,
0353: SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0354:
0355: // check security (throws if not permitted)
0356: unlock(SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0357:
0358: // get the AuthzGroup
0359: AuthzGroup azGroup = m_storage.get(authzGroupId);
0360: if (azGroup == null) {
0361: throw new GroupNotDefinedException(authzGroupId);
0362: }
0363:
0364: // check the role
0365: Role role = azGroup.getRole(roleId);
0366: if (role == null) {
0367: throw new GroupNotDefinedException(roleId);
0368: }
0369:
0370: ((BaseAuthzGroup) azGroup)
0371: .setEvent(SECURE_UPDATE_OWN_AUTHZ_GROUP);
0372:
0373: // see if already joined
0374: BaseMember grant = (BaseMember) azGroup.getMember(user);
0375: if (grant != null) {
0376: // if inactive, make it active
0377: if (!grant.active)
0378: grant.active = true;
0379: }
0380:
0381: // give the user this role
0382: else {
0383: azGroup.addMember(user, roleId, true, false);
0384: }
0385:
0386: // and save
0387: completeSave(azGroup);
0388: }
0389:
0390: /**
0391: * {@inheritDoc}
0392: */
0393: public void unjoinGroup(String authzGroupId)
0394: throws GroupNotDefinedException, AuthzPermissionException {
0395: String user = sessionManager().getCurrentSessionUserId();
0396: if (user == null)
0397: throw new AuthzPermissionException(user,
0398: SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0399:
0400: // check security (throws if not permitted)
0401: unlock(SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0402:
0403: // get the AuthzGroup
0404: AuthzGroup azGroup = m_storage.get(authzGroupId);
0405: if (azGroup == null) {
0406: throw new GroupNotDefinedException(authzGroupId);
0407: }
0408:
0409: // if not joined (no grant), we are done
0410: BaseMember grant = (BaseMember) azGroup.getMember(user);
0411: if (grant == null) {
0412: return;
0413: }
0414:
0415: // if the user currently is the only maintain role user, disallow the unjoin
0416: if (grant.getRole().getId().equals(azGroup.getMaintainRole())) {
0417: Set maintainers = azGroup.getUsersHasRole(azGroup
0418: .getMaintainRole());
0419: if (maintainers.size() <= 1) {
0420: throw new AuthzPermissionException(user,
0421: SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0422: }
0423: }
0424:
0425: ((BaseAuthzGroup) azGroup)
0426: .setEvent(SECURE_UPDATE_OWN_AUTHZ_GROUP);
0427:
0428: // if the grant is provider, make it inactive so it doesn't revert to provider status
0429: if (grant.isProvided()) {
0430: grant.active = false;
0431: } else {
0432: // remove the user completely
0433: ((BaseAuthzGroup) azGroup).removeMember(user);
0434: }
0435:
0436: // and save
0437: completeSave(azGroup);
0438: }
0439:
0440: /**
0441: * {@inheritDoc}
0442: */
0443: public boolean allowJoinGroup(String authzGroupId) {
0444: String user = sessionManager().getCurrentSessionUserId();
0445: if (user == null)
0446: return false;
0447:
0448: // check security (throws if not permitted)
0449: return unlockCheck(SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId);
0450: }
0451:
0452: /**
0453: * {@inheritDoc}
0454: */
0455: public boolean allowUnjoinGroup(String authzGroupId) {
0456: String user = sessionManager().getCurrentSessionUserId();
0457: if (user == null) {
0458: return false;
0459: }
0460:
0461: // check security (throws if not permitted)
0462: if (!unlockCheck(SECURE_UPDATE_OWN_AUTHZ_GROUP, authzGroupId))
0463: return false;
0464:
0465: // get the azGroup
0466: AuthzGroup azGroup = m_storage.get(authzGroupId);
0467: if (azGroup == null) {
0468: return false;
0469: }
0470:
0471: // if not joined (no grant), unable to unjoin
0472: BaseMember grant = (BaseMember) azGroup.getMember(user);
0473: if (grant == null) {
0474: return false;
0475: }
0476:
0477: // if the grant is provider, unable to unjoin
0478: else if (grant.isProvided()) {
0479: return false;
0480: }
0481:
0482: // if the user currently is the only maintain role user, disallow the unjoin
0483: if (grant.getRole().getId().equals(azGroup.getMaintainRole())) {
0484: Set maintainers = azGroup.getUsersHasRole(azGroup
0485: .getMaintainRole());
0486: if (maintainers.size() <= 1) {
0487: return false;
0488: }
0489: }
0490:
0491: return true;
0492: }
0493:
0494: /**
0495: * {@inheritDoc}
0496: */
0497: public boolean allowUpdate(String id) {
0498: return unlockCheck(SECURE_UPDATE_AUTHZ_GROUP,
0499: authzGroupReference(id));
0500: }
0501:
0502: /**
0503: * {@inheritDoc}
0504: */
0505: public void save(AuthzGroup azGroup)
0506: throws GroupNotDefinedException, AuthzPermissionException {
0507: if (azGroup.getId() == null)
0508: throw new GroupNotDefinedException("<null>");
0509:
0510: Reference ref = entityManager().newReference(azGroup.getId());
0511: if (!SiteService.allowUpdateSiteMembership(ref.getId())) {
0512: // check security (throws if not permitted)
0513: unlock(SECURE_UPDATE_AUTHZ_GROUP,
0514: authzGroupReference(azGroup.getId()));
0515: }
0516:
0517: // make sure it's in storage
0518: if (!m_storage.check(azGroup.getId())) {
0519: // if this was new, create it in storage
0520: if (((BaseAuthzGroup) azGroup).m_isNew) {
0521: // reserve an AuthzGroup with this id from the info store - if it's in use, this will return null
0522: AuthzGroup newAzg = m_storage.put(azGroup.getId());
0523: if (newAzg == null) {
0524: M_log
0525: .warn("saveUsingSecurity, storage.put for a new returns null");
0526: }
0527: } else {
0528: throw new GroupNotDefinedException(azGroup.getId());
0529: }
0530: }
0531:
0532: // complete the save
0533: completeSave(azGroup);
0534: }
0535:
0536: /**
0537: * Complete the saving of the group, once id and security checks have been cleared.
0538: *
0539: * @param azGroup
0540: */
0541: protected void completeSave(AuthzGroup azGroup) {
0542: // update the properties
0543: addLiveUpdateProperties((BaseAuthzGroup) azGroup);
0544:
0545: // complete the azGroup
0546: m_storage.save(azGroup);
0547:
0548: // track it
0549: String event = ((BaseAuthzGroup) azGroup).getEvent();
0550: if (event == null)
0551: event = SECURE_UPDATE_AUTHZ_GROUP;
0552: eventTrackingService().post(
0553: eventTrackingService().newEvent(event,
0554: azGroup.getReference(), true));
0555:
0556: // close the azGroup object
0557: ((BaseAuthzGroup) azGroup).closeEdit();
0558:
0559: // update the db with latest provider, and site security with the latest changes, using the updated azGroup
0560: BaseAuthzGroup updatedRealm = (BaseAuthzGroup) m_storage
0561: .get(azGroup.getId());
0562: updateSiteSecurity(updatedRealm);
0563:
0564: // clear the event for next time
0565: ((BaseAuthzGroup) azGroup).setEvent(null);
0566: }
0567:
0568: /**
0569: * {@inheritDoc}
0570: */
0571: public boolean allowAdd(String id) {
0572: return unlockCheck(SECURE_ADD_AUTHZ_GROUP,
0573: authzGroupReference(id));
0574: }
0575:
0576: /**
0577: * {@inheritDoc}
0578: */
0579: public AuthzGroup addAuthzGroup(String id)
0580: throws GroupIdInvalidException,
0581: GroupAlreadyDefinedException, AuthzPermissionException {
0582: // check security (throws if not permitted)
0583: unlock(SECURE_ADD_AUTHZ_GROUP, authzGroupReference(id));
0584:
0585: // reserve an AuthzGroup with this id from the info store - if it's in use, this will return null
0586: AuthzGroup azGroup = m_storage.put(id);
0587: if (azGroup == null) {
0588: throw new GroupAlreadyDefinedException(id);
0589: }
0590:
0591: ((BaseAuthzGroup) azGroup).setEvent(SECURE_ADD_AUTHZ_GROUP);
0592:
0593: // update the properties
0594: addLiveProperties((BaseAuthzGroup) azGroup);
0595:
0596: // save
0597: completeSave(azGroup);
0598:
0599: return azGroup;
0600: }
0601:
0602: /**
0603: * {@inheritDoc}
0604: */
0605: public AuthzGroup addAuthzGroup(String id, AuthzGroup other,
0606: String userId) throws GroupIdInvalidException,
0607: GroupAlreadyDefinedException, AuthzPermissionException {
0608: // make the new AuthzGroup
0609: AuthzGroup azGroup = addAuthzGroup(id);
0610:
0611: // move in the values from the old AuthzGroup (this includes the id, which we restore
0612: ((BaseAuthzGroup) azGroup).set(other);
0613: ((BaseAuthzGroup) azGroup).m_id = id;
0614:
0615: // give the user the "maintain" role
0616: String roleName = azGroup.getMaintainRole();
0617: if ((roleName != null) && (userId != null)) {
0618: azGroup.addMember(userId, roleName, true, false);
0619: }
0620:
0621: // update the properties
0622: addLiveProperties((BaseAuthzGroup) azGroup);
0623:
0624: // save
0625: completeSave(azGroup);
0626:
0627: return azGroup;
0628: }
0629:
0630: /**
0631: * {@inheritDoc}
0632: */
0633: public AuthzGroup newAuthzGroup(String id, AuthzGroup other,
0634: String userId) throws GroupAlreadyDefinedException {
0635: // make the new AuthzGroup
0636: BaseAuthzGroup azGroup = new BaseAuthzGroup(id);
0637: azGroup.m_isNew = true;
0638:
0639: // move in the values from the old AuthzGroup (this includes the id, which we restore)
0640: if (other != null) {
0641: azGroup.set(other);
0642: azGroup.m_id = id;
0643: }
0644:
0645: // give the user the "maintain" role
0646: String roleName = azGroup.getMaintainRole();
0647: if ((roleName != null) && (userId != null)) {
0648: azGroup.addMember(userId, roleName, true, false);
0649: }
0650:
0651: return azGroup;
0652: }
0653:
0654: /**
0655: * {@inheritDoc}
0656: */
0657: public boolean allowRemove(String id) {
0658: return unlockCheck(SECURE_REMOVE_AUTHZ_GROUP,
0659: authzGroupReference(id));
0660: }
0661:
0662: /**
0663: * {@inheritDoc}
0664: */
0665: public void removeAuthzGroup(AuthzGroup azGroup)
0666: throws AuthzPermissionException {
0667: // check security (throws if not permitted)
0668: unlock(SECURE_REMOVE_AUTHZ_GROUP, azGroup.getReference());
0669:
0670: // complete the azGroup
0671: m_storage.remove(azGroup);
0672:
0673: // track it
0674: eventTrackingService().post(
0675: eventTrackingService().newEvent(
0676: SECURE_REMOVE_AUTHZ_GROUP,
0677: azGroup.getReference(), true));
0678:
0679: // close the azGroup object
0680: ((BaseAuthzGroup) azGroup).closeEdit();
0681:
0682: // clear any site security based on this (if a site) azGroup
0683: removeSiteSecurity(azGroup);
0684: }
0685:
0686: /**
0687: * {@inheritDoc}
0688: */
0689: public void removeAuthzGroup(String azGroupId)
0690: throws AuthzPermissionException {
0691: if (azGroupId == null)
0692: return;
0693:
0694: // check for existance
0695: AuthzGroup azGroup = m_storage.get(azGroupId);
0696: if (azGroup == null) {
0697: return;
0698: }
0699:
0700: // check security (throws if not permitted)
0701: unlock(SECURE_REMOVE_AUTHZ_GROUP,
0702: authzGroupReference(azGroupId));
0703:
0704: // complete the azGroup
0705: m_storage.remove(azGroup);
0706:
0707: // track it
0708: eventTrackingService().post(
0709: eventTrackingService().newEvent(
0710: SECURE_REMOVE_AUTHZ_GROUP,
0711: azGroup.getReference(), true));
0712:
0713: // close the azGroup object
0714: ((BaseAuthzGroup) azGroup).closeEdit();
0715:
0716: // clear any site security based on this (if a site) azGroup
0717: removeSiteSecurity(azGroup);
0718: }
0719:
0720: /**
0721: * {@inheritDoc}
0722: */
0723: public String authzGroupReference(String id) {
0724: return getAccessPoint(true) + Entity.SEPARATOR + id;
0725: }
0726:
0727: /**
0728: * {@inheritDoc}
0729: */
0730: public boolean isAllowed(String user, String function,
0731: String azGroupId) {
0732: return m_storage.isAllowed(user, function, azGroupId);
0733: }
0734:
0735: /**
0736: * {@inheritDoc}
0737: */
0738: public boolean isAllowed(String user, String function,
0739: Collection azGroups) {
0740: return m_storage.isAllowed(user, function, azGroups);
0741: }
0742:
0743: /**
0744: * {@inheritDoc}
0745: */
0746: public Set getUsersIsAllowed(String function, Collection azGroups) {
0747: return m_storage.getUsersIsAllowed(function, azGroups);
0748: }
0749:
0750: /**
0751: * {@inheritDoc}
0752: */
0753: public Set getAllowedFunctions(String role, Collection azGroups) {
0754: return m_storage.getAllowedFunctions(role, azGroups);
0755: }
0756:
0757: /**
0758: * {@inheritDoc}
0759: */
0760: public Set getAuthzGroupsIsAllowed(String userId, String function,
0761: Collection azGroups) {
0762: return m_storage.getAuthzGroupsIsAllowed(userId, function,
0763: azGroups);
0764: }
0765:
0766: /**
0767: * {@inheritDoc}
0768: */
0769: public String getUserRole(String userId, String azGroupId) {
0770: return m_storage.getUserRole(userId, azGroupId);
0771: }
0772:
0773: /**
0774: * {@inheritDoc}
0775: */
0776: public Map getUsersRole(Collection userIds, String azGroupId) {
0777: return m_storage.getUsersRole(userIds, azGroupId);
0778: }
0779:
0780: /**
0781: * {@inheritDoc}
0782: */
0783: public void refreshUser(String userId) {
0784: if ((m_provider == null) || (userId == null))
0785: return;
0786:
0787: try {
0788: String eid = userDirectoryService().getUserEid(userId);
0789:
0790: // wrap the provided map in our special map that will deal with compound provider ids
0791: Map providerGrants = new ProviderMap(m_provider, m_provider
0792: .getGroupRolesForUser(eid));
0793:
0794: m_storage.refreshUser(userId, providerGrants);
0795:
0796: // update site security for this user - get the user's realms for the three site locks
0797: Set updAuthzGroups = getAuthzGroupsIsAllowed(userId,
0798: SiteService.SECURE_UPDATE_SITE, null);
0799: Set unpAuthzGroups = getAuthzGroupsIsAllowed(userId,
0800: SiteService.SITE_VISIT_UNPUBLISHED, null);
0801: Set visitAuthzGroups = getAuthzGroupsIsAllowed(userId,
0802: SiteService.SITE_VISIT, null);
0803:
0804: // convert from azGroup ids (potential site references) to site ids for those that are site,
0805: // skipping special and user sites other than our user's
0806: Set updSites = new HashSet();
0807: for (Iterator i = updAuthzGroups.iterator(); i.hasNext();) {
0808: String azGroupId = (String) i.next();
0809: Reference ref = entityManager().newReference(azGroupId);
0810: if ((SiteService.APPLICATION_ID.equals(ref.getType()))
0811: && SiteService.SITE_SUBTYPE.equals(ref
0812: .getSubType())
0813: && !SiteService.isSpecialSite(ref.getId())
0814: && (!SiteService.isUserSite(ref.getId()) || userId
0815: .equals(SiteService.getSiteUserId(ref
0816: .getId())))) {
0817: updSites.add(ref.getId());
0818: }
0819: }
0820:
0821: Set unpSites = new HashSet();
0822: for (Iterator i = unpAuthzGroups.iterator(); i.hasNext();) {
0823: String azGroupId = (String) i.next();
0824: Reference ref = entityManager().newReference(azGroupId);
0825: if ((SiteService.APPLICATION_ID.equals(ref.getType()))
0826: && SiteService.SITE_SUBTYPE.equals(ref
0827: .getSubType())
0828: && !SiteService.isSpecialSite(ref.getId())
0829: && (!SiteService.isUserSite(ref.getId()) || userId
0830: .equals(SiteService.getSiteUserId(ref
0831: .getId())))) {
0832: unpSites.add(ref.getId());
0833: }
0834: }
0835:
0836: Set visitSites = new HashSet();
0837: for (Iterator i = visitAuthzGroups.iterator(); i.hasNext();) {
0838: String azGroupId = (String) i.next();
0839: Reference ref = entityManager().newReference(azGroupId);
0840: if ((SiteService.APPLICATION_ID.equals(ref.getType()))
0841: && SiteService.SITE_SUBTYPE.equals(ref
0842: .getSubType())
0843: && !SiteService.isSpecialSite(ref.getId())
0844: && (!SiteService.isUserSite(ref.getId()) || userId
0845: .equals(SiteService.getSiteUserId(ref
0846: .getId())))) {
0847: visitSites.add(ref.getId());
0848: }
0849: }
0850:
0851: SiteService.setUserSecurity(userId, updSites, unpSites,
0852: visitSites);
0853: } catch (UserNotDefinedException e) {
0854: M_log.warn("refreshUser: cannot find eid for user: "
0855: + userId);
0856: }
0857: }
0858:
0859: /**
0860: * Update the site security based on the values in the AuthzGroup, if it is a site AuthzGroup.
0861: *
0862: * @param azGroup
0863: * The AuthzGroup.
0864: */
0865: protected void updateSiteSecurity(AuthzGroup azGroup) {
0866: // Special code for the site service
0867: Reference ref = entityManager().newReference(azGroup.getId());
0868: if (SiteService.APPLICATION_ID.equals(ref.getType())
0869: && SiteService.SITE_SUBTYPE.equals(ref.getSubType())) {
0870: // collect the users
0871: Set updUsers = azGroup
0872: .getUsersIsAllowed(SiteService.SECURE_UPDATE_SITE);
0873: Set unpUsers = azGroup
0874: .getUsersIsAllowed(SiteService.SITE_VISIT_UNPUBLISHED);
0875: Set visitUsers = azGroup
0876: .getUsersIsAllowed(SiteService.SITE_VISIT);
0877:
0878: SiteService.setSiteSecurity(ref.getId(), updUsers,
0879: unpUsers, visitUsers);
0880: }
0881: }
0882:
0883: /**
0884: * Update the site security when an AuthzGroup is deleted, if it is a site AuthzGroup.
0885: *
0886: * @param azGroup
0887: * The AuthzGroup.
0888: */
0889: protected void removeSiteSecurity(AuthzGroup azGroup) {
0890: // Special code for the site service
0891: Reference ref = entityManager().newReference(azGroup.getId());
0892: if (SiteService.APPLICATION_ID.equals(ref.getType())
0893: && SiteService.SITE_SUBTYPE.equals(ref.getSubType())) {
0894: // no azGroup, no users
0895: Set empty = new HashSet();
0896:
0897: SiteService.setSiteSecurity(ref.getId(), empty, empty,
0898: empty);
0899: }
0900: }
0901:
0902: /**********************************************************************************************************************************************************************************************************************************************************
0903: * EntityProducer implementation
0904: *********************************************************************************************************************************************************************************************************************************************************/
0905:
0906: /**
0907: * {@inheritDoc}
0908: */
0909: public String getLabel() {
0910: return "authzGroup";
0911: }
0912:
0913: /**
0914: * {@inheritDoc}
0915: */
0916: public boolean willArchiveMerge() {
0917: return false;
0918: }
0919:
0920: /**
0921: * {@inheritDoc}
0922: */
0923: public HttpAccess getHttpAccess() {
0924: return null;
0925: }
0926:
0927: /**
0928: * {@inheritDoc}
0929: */
0930: public boolean parseEntityReference(String reference, Reference ref) {
0931: // for azGroup access
0932: if (reference.startsWith(REFERENCE_ROOT)) {
0933: // the azGroup id may have separators - we use everything after "/realm/"
0934: String id = reference.substring(
0935: REFERENCE_ROOT.length() + 1, reference.length());
0936:
0937: ref.set(APPLICATION_ID, null, id, null, null);
0938:
0939: return true;
0940: }
0941:
0942: return false;
0943: }
0944:
0945: /**
0946: * {@inheritDoc}
0947: */
0948: public String getEntityDescription(Reference ref) {
0949: return null;
0950: }
0951:
0952: /**
0953: * {@inheritDoc}
0954: */
0955: public ResourceProperties getEntityResourceProperties(Reference ref) {
0956: return null;
0957: }
0958:
0959: /**
0960: * {@inheritDoc}
0961: */
0962: public Entity getEntity(Reference ref) {
0963: return null;
0964: }
0965:
0966: /**
0967: * {@inheritDoc}
0968: */
0969: public Collection getEntityAuthzGroups(Reference ref, String userId) {
0970: // double check that it's mine
0971: if (APPLICATION_ID != ref.getType())
0972: return null;
0973:
0974: Collection rv = new Vector();
0975:
0976: // if the reference is an AuthzGroup, and not a special one
0977: // get the list of realms for the azGroup-referenced resource
0978: if ((ref.getId() != null) && (ref.getId().length() > 0)
0979: && (!ref.getId().startsWith("!"))) {
0980: // add the current user's azGroup (for what azGroup stuff everyone can do, i.e. add)
0981: ref.addUserAuthzGroup(rv, sessionManager()
0982: .getCurrentSessionUserId());
0983:
0984: // make a new reference on the azGroup's id
0985: Reference refnew = entityManager()
0986: .newReference(ref.getId());
0987: rv.addAll(refnew.getAuthzGroups(userId));
0988: }
0989:
0990: return rv;
0991: }
0992:
0993: /**
0994: * {@inheritDoc}
0995: */
0996: public String getEntityUrl(Reference ref) {
0997: return null;
0998: }
0999:
1000: /**
1001: * {@inheritDoc}
1002: */
1003: public String archive(String siteId, Document doc, Stack stack,
1004: String archivePath, List attachments) {
1005: return "";
1006: }
1007:
1008: /**
1009: * {@inheritDoc}
1010: */
1011: public String merge(String siteId, Element root,
1012: String archivePath, String fromSiteId, Map attachmentNames,
1013: Map userIdTrans, Set userListAllowImport) {
1014: return "";
1015: }
1016:
1017: /**********************************************************************************************************************************************************************************************************************************************************
1018: * Storage
1019: *********************************************************************************************************************************************************************************************************************************************************/
1020:
1021: protected interface Storage {
1022: /**
1023: * Open.
1024: */
1025: void open();
1026:
1027: /**
1028: * Close.
1029: */
1030: void close();
1031:
1032: /**
1033: * Check if an AuthzGroup by this id exists.
1034: *
1035: * @param id
1036: * The AuthzGroup id.
1037: * @return true if an AuthzGroup by this id exists, false if not.
1038: */
1039: boolean check(String id);
1040:
1041: /**
1042: * Get the AuthzGroup with this id, or null if not found.
1043: *
1044: * @param id
1045: * The AuthzGroup id.
1046: * @return The AuthzGroup with this id, or null if not found.
1047: */
1048: AuthzGroup get(String id);
1049:
1050: /**
1051: * Add a new AuthzGroup with this id.
1052: *
1053: * @param id
1054: * The AuthzGroup id.
1055: * @return The new AuthzGroup, or null if the id is in use.
1056: */
1057: AuthzGroup put(String id);
1058:
1059: /**
1060: * Save the changes to the AuthzGroup
1061: *
1062: * @param azGroup
1063: * The AuthzGroup to save.
1064: */
1065: void save(AuthzGroup azGroup);
1066:
1067: /**
1068: * Remove this AuthzGroup.
1069: *
1070: * @param azGroup
1071: * The azGroup to remove.
1072: */
1073: void remove(AuthzGroup azGroup);
1074:
1075: /**
1076: * Access a list of AuthzGroups that meet specified criteria, naturally sorted.
1077: *
1078: * @param criteria
1079: * Selection criteria: AuthzGroups returned will match this string somewhere in their id, or provider group id.
1080: * @param page
1081: * The PagePosition subset of items to return.
1082: * @return The List (AuthzGroup) of AuthzGroups that meet specified criteria.
1083: */
1084: List getAuthzGroups(String criteria, PagingPosition page);
1085:
1086: /**
1087: * Count the AuthzGroup objets that meet specified criteria.
1088: *
1089: * @param criteria
1090: * Selection criteria: realms returned will match this string somewhere in their id, or provider group id.
1091: * @return The count of AuthzGroups that meet specified criteria.
1092: */
1093: int countAuthzGroups(String criteria);
1094:
1095: /**
1096: * Get the provider IDs for an AuthzGroup
1097: *
1098: * @param authzGroupId The ID of the AuthzGroup
1099: * @return The Set (String) of provider IDs
1100: */
1101: public Set getProviderIds(String authzGroupId);
1102:
1103: /**
1104: * Get the AuthzGroup IDs associated with a provider ID.
1105: *
1106: * @param providerId The provider id
1107: * @return The Set (String) of AuthzGroup IDs
1108: */
1109: public Set getAuthzGroupIds(String providerId);
1110:
1111: /**
1112: * Complete the read process once the basic AuthzGroup info has been read.
1113: *
1114: * @param azGroup
1115: * The AuthzGroup to complete.
1116: */
1117: void completeGet(BaseAuthzGroup azGroup);
1118:
1119: /**
1120: * Test if this user is allowed to perform the function in the named AuthzGroup.
1121: *
1122: * @param userId
1123: * The user id.
1124: * @param function
1125: * The function to open.
1126: * @param azGroupId
1127: * The AuthzGroup id to consult, if it exists.
1128: * @return true if this user is allowed to perform the function in the named AuthzGroup, false if not.
1129: */
1130: boolean isAllowed(String userId, String function,
1131: String azGroupId);
1132:
1133: /**
1134: * Test if this user is allowed to perform the function in the named AuthzGroups.
1135: *
1136: * @param userId
1137: * The user id.
1138: * @param function
1139: * The function to open.
1140: * @param azGroups
1141: * A collection of AuthzGroup ids to consult.
1142: * @return true if this user is allowed to perform the function in the named AuthzGroups, false if not.
1143: */
1144: boolean isAllowed(String userId, String function,
1145: Collection realms);
1146:
1147: /**
1148: * Get the set of user ids of users who are allowed to perform the function in the named AuthzGroups.
1149: *
1150: * @param function
1151: * The function to check.
1152: * @param azGroups
1153: * A collection of the ids of AuthzGroups to consult.
1154: * @return the Set (String) of user ids of users who are allowed to perform the function in the named AuthzGroups.
1155: */
1156: Set getUsersIsAllowed(String function, Collection azGroups);
1157:
1158: /**
1159: * Get the set of functions that users with this role in these AuthzGroups are allowed to perform.
1160: *
1161: * @param role
1162: * The role name.
1163: * @param azGroups
1164: * A collection of AuthzGroup ids to consult.
1165: * @return the Set (String) of functions that users with this role in these AuthzGroups are allowed to perform
1166: */
1167: Set getAllowedFunctions(String role, Collection azGroups);
1168:
1169: /**
1170: * Get the set of AuthzGroup ids in which this user is allowed to perform this function.
1171: *
1172: * @param userId
1173: * The user id.
1174: * @param function
1175: * The function to check.
1176: * @param azGroups
1177: * The Collection of AuthzGroup ids to search; if null, search them all.
1178: * @return the Set (String) of AuthzGroup ids in which this user is allowed to perform this function.
1179: */
1180: Set getAuthzGroupsIsAllowed(String userId, String function,
1181: Collection azGroups);
1182:
1183: /**
1184: * Get the role name for this user in this AuthzGroup.
1185: *
1186: * @param userId
1187: * The user id.
1188: * @param function
1189: * The function to open.
1190: * @param azGroupId
1191: * The AuthzGroup id to consult, if it exists.
1192: * @return the role name for this user in this AuthzGroup, if the user has active membership, or null if not.
1193: */
1194: String getUserRole(String userId, String azGroupId);
1195:
1196: /**
1197: * Get the role name for each user in the userIds Collection in this AuthzGroup.
1198: *
1199: * @param userId
1200: * The user id.
1201: * @param function
1202: * The function to open.
1203: * @param azGroupId
1204: * The AuthzGroup id to consult, if it exists.
1205: * @return A Map (userId -> role name) of role names for each user who have active membership; if the user does not, it will not be in the Map.
1206: */
1207: Map getUsersRole(Collection userIds, String azGroupId);
1208:
1209: /**
1210: * Refresh this user's roles in any AuthzGroup that has an entry in the map; the user's new role is in the map.
1211: *
1212: * @param userId
1213: * The user id
1214: * @param providerMembership
1215: * The Map of external group id -> role id.
1216: */
1217: void refreshUser(String userId, Map providerMembership);
1218:
1219: /**
1220: * Refresh the external user - role membership for this AuthzGroup
1221: *
1222: * @param azGroup
1223: * The azGroup to refresh.
1224: */
1225: void refreshAuthzGroup(BaseAuthzGroup azGroup);
1226: }
1227:
1228: /**********************************************************************************************************************************************************************************************************************************************************
1229: * StorageUser implementation (no container)
1230: *********************************************************************************************************************************************************************************************************************************************************/
1231:
1232: /**
1233: * Construct a new continer given just an id.
1234: *
1235: * @param id
1236: * The id for the new object.
1237: * @return The new containe Resource.
1238: */
1239: public Entity newContainer(String ref) {
1240: return null;
1241: }
1242:
1243: /**
1244: * Construct a new container resource, from an XML element.
1245: *
1246: * @param element
1247: * The XML.
1248: * @return The new container resource.
1249: */
1250: public Entity newContainer(Element element) {
1251: return null;
1252: }
1253:
1254: /**
1255: * Construct a new container resource, as a copy of another
1256: *
1257: * @param other
1258: * The other contianer to copy.
1259: * @return The new container resource.
1260: */
1261: public Entity newContainer(Entity other) {
1262: return null;
1263: }
1264:
1265: /**
1266: * Construct a new rsource given just an id.
1267: *
1268: * @param container
1269: * The Resource that is the container for the new resource (may be null).
1270: * @param id
1271: * The id for the new object.
1272: * @param others
1273: * (options) array of objects to load into the Resource's fields.
1274: * @return The new resource.
1275: */
1276: public Entity newResource(Entity container, String id,
1277: Object[] others) {
1278: return new BaseAuthzGroup(id);
1279: }
1280:
1281: /**
1282: * Construct a new resource, from an XML element.
1283: *
1284: * @param container
1285: * The Resource that is the container for the new resource (may be null).
1286: * @param element
1287: * The XML.
1288: * @return The new resource from the XML.
1289: */
1290: public Entity newResource(Entity container, Element element) {
1291: return new BaseAuthzGroup(element);
1292: }
1293:
1294: /**
1295: * Construct a new resource from another resource of the same type.
1296: *
1297: * @param container
1298: * The Resource that is the container for the new resource (may be null).
1299: * @param other
1300: * The other resource.
1301: * @return The new resource as a copy of the other.
1302: */
1303: public Entity newResource(Entity container, Entity other) {
1304: return new BaseAuthzGroup((AuthzGroup) other);
1305: }
1306:
1307: /**
1308: * Construct a new continer given just an id.
1309: *
1310: * @param id
1311: * The id for the new object.
1312: * @return The new containe Resource.
1313: */
1314: public Edit newContainerEdit(String ref) {
1315: return null;
1316: }
1317:
1318: /**
1319: * Construct a new container resource, from an XML element.
1320: *
1321: * @param element
1322: * The XML.
1323: * @return The new container resource.
1324: */
1325: public Edit newContainerEdit(Element element) {
1326: return null;
1327: }
1328:
1329: /**
1330: * Construct a new container resource, as a copy of another
1331: *
1332: * @param other
1333: * The other contianer to copy.
1334: * @return The new container resource.
1335: */
1336: public Edit newContainerEdit(Entity other) {
1337: return null;
1338: }
1339:
1340: /**
1341: * Construct a new rsource given just an id.
1342: *
1343: * @param container
1344: * The Resource that is the container for the new resource (may be null).
1345: * @param id
1346: * The id for the new object.
1347: * @param others
1348: * (options) array of objects to load into the Resource's fields.
1349: * @return The new resource.
1350: */
1351: public Edit newResourceEdit(Entity container, String id,
1352: Object[] others) {
1353: BaseAuthzGroup e = new BaseAuthzGroup(id);
1354: e.activate();
1355: return e;
1356: }
1357:
1358: /**
1359: * Construct a new resource, from an XML element.
1360: *
1361: * @param container
1362: * The Resource that is the container for the new resource (may be null).
1363: * @param element
1364: * The XML.
1365: * @return The new resource from the XML.
1366: */
1367: public Edit newResourceEdit(Entity container, Element element) {
1368: BaseAuthzGroup e = new BaseAuthzGroup(element);
1369: e.activate();
1370: return e;
1371: }
1372:
1373: /**
1374: * Construct a new resource from another resource of the same type.
1375: *
1376: * @param container
1377: * The Resource that is the container for the new resource (may be null).
1378: * @param other
1379: * The other resource.
1380: * @return The new resource as a copy of the other.
1381: */
1382: public Edit newResourceEdit(Entity container, Entity other) {
1383: BaseAuthzGroup e = new BaseAuthzGroup((AuthzGroup) other);
1384: e.activate();
1385: return e;
1386: }
1387:
1388: /**
1389: * Collect the fields that need to be stored outside the XML (for the resource).
1390: *
1391: * @return An array of field values to store in the record outside the XML (for the resource).
1392: */
1393: public Object[] storageFields(Entity r) {
1394: return null;
1395: }
1396:
1397: /**
1398: * Check if this resource is in draft mode.
1399: *
1400: * @param r
1401: * The resource.
1402: * @return true if the resource is in draft mode, false if not.
1403: */
1404: public boolean isDraft(Entity r) {
1405: return false;
1406: }
1407:
1408: /**
1409: * Access the resource owner user id.
1410: *
1411: * @param r
1412: * The resource.
1413: * @return The resource owner user id.
1414: */
1415: public String getOwnerId(Entity r) {
1416: return null;
1417: }
1418:
1419: /**
1420: * Access the resource date.
1421: *
1422: * @param r
1423: * The resource.
1424: * @return The resource date.
1425: */
1426: public Time getDate(Entity r) {
1427: return null;
1428: }
1429:
1430: public class ProviderMap implements Map {
1431: protected Map m_wrapper = null;
1432: protected GroupProvider m_provider = null;
1433:
1434: public ProviderMap(GroupProvider provider, Map wrapper) {
1435: m_provider = provider;
1436: m_wrapper = wrapper;
1437: }
1438:
1439: public void clear() {
1440: m_wrapper.clear();
1441: }
1442:
1443: public boolean containsKey(Object key) {
1444: return m_wrapper.containsKey(key);
1445: }
1446:
1447: public boolean containsValue(Object value) {
1448: return m_wrapper.containsValue(value);
1449: }
1450:
1451: public Set entrySet() {
1452: return m_wrapper.entrySet();
1453: }
1454:
1455: public Object get(Object key) {
1456: // if we have this key exactly, use it
1457: Object value = m_wrapper.get(key);
1458: if (value != null)
1459: return value;
1460:
1461: // otherwise break up key as a compound id and find what values we have for these
1462: // the values are roles, and we prefer "maintain" to "access"
1463: String rv = null;
1464: String[] ids = m_provider.unpackId((String) key);
1465: for (int i = 0; i < ids.length; i++) {
1466: // try this one
1467: value = m_wrapper.get(ids[i]);
1468:
1469: // if we found one already, ask the provider which to keep
1470: if (value != null) {
1471: rv = m_provider.preferredRole((String) value, rv);
1472: }
1473: }
1474:
1475: return rv;
1476: }
1477:
1478: public boolean isEmpty() {
1479: return m_wrapper.isEmpty();
1480: }
1481:
1482: public Set keySet() {
1483: return m_wrapper.keySet();
1484: }
1485:
1486: public Object put(Object key, Object value) {
1487: return m_wrapper.put(key, value);
1488: }
1489:
1490: public void putAll(Map t) {
1491: m_wrapper.putAll(t);
1492: }
1493:
1494: public Object remove(Object key) {
1495: return m_wrapper.remove(key);
1496: }
1497:
1498: public int size() {
1499: return m_wrapper.size();
1500: }
1501:
1502: public Collection values() {
1503: return m_wrapper.values();
1504: }
1505: }
1506: }
|