/********************************************************************************** * $URL: $ * $Id: $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.site.tool.helper.managegroupsectionrole.impl; // imports import java.util.Observable; import java.util.Observer; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.lang.StringUtils; import org.sakaiproject.authz.api.AuthzGroup; import org.sakaiproject.authz.api.AuthzGroupService; import org.sakaiproject.authz.api.Member; import org.sakaiproject.authz.api.GroupNotDefinedException; import org.sakaiproject.authz.api.SecurityAdvisor; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.entity.api.Entity; import org.sakaiproject.entity.api.EntityManager; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.event.api.Event; import org.sakaiproject.event.api.EventTrackingService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.site.api.Group; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.util.SiteConstants; import org.sakaiproject.thread_local.api.ThreadLocalManager; /** * <p>RoleGroupEventWatcher is for </p> * * @author University of Michigan, Sakai Software Development Team * @version $Revision$ */ public class RoleGroupEventWatcher implements Observer { private static Log log = LogFactory.getLog(RoleGroupEventWatcher.class); /******************************************************************************* * Dependencies and their setter methods *******************************************************************************/ /** Dependency: event tracking service */ protected EventTrackingService m_eventTrackingService = null; /** * Dependency: event tracking service. * @param service The event tracking service. */ public void setEventTrackingService(EventTrackingService service) { m_eventTrackingService = service; } /** Dependency: site service */ protected SiteService m_siteService = null; /** * Dependency: site service. * @param service The site service. */ public void setSiteService(SiteService service) { m_siteService = service; } /** Dependency: AuthzGroup service */ protected AuthzGroupService m_authzGroupService = null; /** * Dependency: AuthzGroup service. * @param service The AuthzGroup service. */ public void setAuthzGroupService(AuthzGroupService service) { m_authzGroupService = service; } protected EntityManager entityManager; public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } protected SecurityService securityService; public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } protected ThreadLocalManager threadLocalManager; public void setThreadLocalManager(ThreadLocalManager threadLocalManager) { this.threadLocalManager = threadLocalManager; } /******************************************************************************* * Init and Destroy *******************************************************************************/ /** * Final initialization, once all dependencies are set. */ public void init() { try { // start watching the events - only those generated on this server, not those from elsewhere m_eventTrackingService.addLocalObserver(this); log.info(this +".init()"); } catch (Exception t) { log.warn(this +".init(): ", t); } } /** * Returns to uninitialized state. */ public void destroy() { // done with event watching m_eventTrackingService.deleteObserver(this); log.info(this +".destroy()"); } /******************************************************************************* * Observer implementation *******************************************************************************/ /** * This method is called whenever the observed object is changed. An * application calls an <tt>Observable</tt> object's * <code>notifyObservers</code> method to have all the object's * observers notified of the change. * * default implementation is to cause the courier service to deliver to the * interface controlled by my controller. Extensions can override. * * @param o the observable object. * @param arg an argument passed to the <code>notifyObservers</code> * method. */ public void update(Observable o, Object arg) { // arg is Event if (!(arg instanceof Event)) return; Event event = (Event) arg; // check the event function against the functions we have notifications watching for String function = event.getEvent(); if (function.equals(AuthzGroupService.SECURE_UPDATE_AUTHZ_GROUP) || AuthzGroupService.SECURE_JOIN_AUTHZ_GROUP.equals(function) || AuthzGroupService.SECURE_UNJOIN_AUTHZ_GROUP.equals(function)) { Reference ref = entityManager.newReference(event.getResource()); // look for group reference. Need to replace it with parent site reference String refId = ref.getId(); String groupType = Entity.SEPARATOR + SiteService.GROUP_SUBTYPE; if (refId.indexOf(groupType) != -1) { refId = refId.substring(0, refId.indexOf(groupType)); ref = entityManager.newReference(refId); } // this is the current realm reference if (threadLocalManager.get("current.event.resource.ref") == null) { threadLocalManager.set("current.event.resource.ref", ref); // importing from template, bypass the permission checking: // temporarily allow the user to read and write to site, authzgroup, etc. securityService.pushAdvisor(new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }); try { String realmId = ref.getId(); if (realmId.indexOf(SiteService.GROUP_SUBTYPE) == -1 && realmId.startsWith("/" + SiteService.SITE_SUBTYPE + "/")) { // not for group realm update, only for site realm updates String siteId = realmId.replace(SiteService.REFERENCE_ROOT + "/", ""); AuthzGroup r; r = m_authzGroupService.getAuthzGroup(realmId); Site site = m_siteService.getSite(siteId); // whether saving site is needed because some groups need updates boolean needSave = false; for (Object g : site.getGroups()) { ResourceProperties properties = ((Group) g).getProperties(); if (properties.getProperty(((Group) g).GROUP_PROP_WSETUP_CREATED) != null && properties.getProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID) != null) { needSave = true; // this is a role provided group, need to sync with realm user now. String roleString = properties.getProperty(SiteConstants.GROUP_PROP_ROLE_PROVIDERID); if (roleString != null && roleString.length() > 0) { Set<Member> members = ((Group) g).getMembers(); String[] roles = StringUtils.split(roleString, "+"); for (String role : roles) { // remove those provided members by role for(Member m : members) { if (m.getRole().getId().equals(role)) { ((Group) g).removeMember(m.getUserId()); } } // update the group member with current realm users Set roleUserSet = r.getUsersHasRole(role.trim()); if (roleUserSet != null && !roleUserSet.isEmpty()) { for(Object userId:roleUserSet) { ((Group) g).addMember((String) userId, role.trim(), true, false); } } } } } } if (needSave) { // Save only site group membership updates to this site m_siteService.saveGroupMembership(site); } } } catch (GroupNotDefinedException e) { log.warn("update: " + e + ": " + event.getResource()); } catch (IdUnusedException e) { log.warn("update: " + e + ": " + event.getResource()); } catch (PermissionException e) { log.warn("update: " + e + ": " + event.getResource()); } catch (Exception e) { log.warn(this + ".update:" + e + ": " + event.getResource()); e.printStackTrace(); } securityService.popAdvisor(); // reset threadLocalManager.set("current.event.resource.ref", null); } } } // update } // RoleGroupEventWatcher