/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/edu-services/trunk/sections-service/sections-impl/sakai/impl/src/java/org/sakaiproject/component/section/sakai/SectionCmMetadataSynchronizer.java $
* $Id: SectionCmMetadataSynchronizer.java 105077 2012-02-24 22:54:29Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2007, 2008 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.component.section.sakai;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.sakaiproject.authz.api.GroupProvider;
import org.sakaiproject.authz.cover.AuthzGroupService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.coursemanagement.api.CourseManagementService;
import org.sakaiproject.coursemanagement.api.Section;
import org.sakaiproject.coursemanagement.api.exception.IdNotFoundException;
import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.event.cover.UsageSessionService;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.javax.PagingPosition;
import org.sakaiproject.site.api.Group;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.site.api.SiteService.SelectionType;
import org.sakaiproject.site.api.SiteService.SortType;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.cover.SessionManager;
/**
* Updates sakai's section metadata with the latest section information from the CM service.
*
* @author <a href="mailto:jholtzman@berkeley.edu">jholtzman@berkeley.edu</a>
*
*/
public class SectionCmMetadataSynchronizer implements Job {
private static final Log log = LogFactory.getLog(SectionCmMetadataSynchronizer.class);
public static final int PAGE_SIZE = 100;
protected SiteService siteService;
protected CourseManagementService cmService;
protected GroupProvider groupProvider;
public void setCmService(CourseManagementService cmService) {
this.cmService = cmService;
}
public void setSiteService(SiteService siteService) {
this.siteService = siteService;
}
public void init() {
if(log.isInfoEnabled()) log.info("init()");
// A group provider may not exist, so we can't use spring to inject it
groupProvider = (GroupProvider)ComponentManager.get(GroupProvider.class);
}
public void updateSakaiSectionMetadata() {
loginToSakai();
int numCourseSites = siteService.countSites(SelectionType.NON_USER, "course", null, null);
int numPages = (int)Math.ceil((double) numCourseSites / PAGE_SIZE);
if(log.isInfoEnabled()) log.info("Synchronizing " + numCourseSites +
" course sites in " + numPages + " chunks of " + PAGE_SIZE + " sites");
for(int page = 0; page < numPages; page++) {
int pageStart = (page*PAGE_SIZE) + 1;
PagingPosition pager = new PagingPosition(pageStart, PAGE_SIZE);
if(log.isDebugEnabled()) log.debug("Paging from " + pageStart + " with page size = " + PAGE_SIZE);
List<Site> pagedSites = siteService.getSites(SelectionType.NON_USER,
"course", null, null, SortType.NONE, pager);
for(Iterator<Site> siteIter = pagedSites.iterator(); siteIter.hasNext();) {
syncSite(siteIter.next());
}
}
logoutFromSakai();
}
private void syncSite(Site site) {
if(log.isDebugEnabled()) log.debug("synching site " + site.getId());
// Ensure that the site is fully initialized.
site.loadAll();
Collection<Group> groups = site.getGroups();
String complexProviderId = site.getProviderGroupId();
String[] sectionEids = groupProvider.unpackId(complexProviderId);
for(int i=0; i<sectionEids.length; i++) {
// Get the section
String sectionEid = sectionEids[i];
Section section;
try {
section = cmService.getSection(sectionEid);
} catch (IdNotFoundException ide) {
log.error("Section " + sectionEid + " is not defined in CM");
// remove the group? remove the providerId from the group?
continue;
}
// Get the group with a providerId equal to this sectionEid
for(Iterator<Group> groupIter = groups.iterator(); groupIter.hasNext();) {
Group group = groupIter.next();
if(sectionEid.equals(group.getProviderGroupId())) {
// Update the group
if(log.isDebugEnabled()) log.debug("Updating sakai group " + group.getId() + " from section " + section.getEid());
CourseSectionUtil.decorateGroupWithCmSection(group, section);
break;
}
}
}
try {
siteService.save(site);
} catch (IdUnusedException e) {
log.error(e);
} catch (PermissionException e) {
log.error(e);
}
}
protected void loginToSakai() {
Session sakaiSession = SessionManager.getCurrentSession();
sakaiSession.setUserId("admin");
sakaiSession.setUserEid("admin");
// establish the user's session
UsageSessionService.startSession("admin", "127.0.0.1", "CMSync");
// update the user's externally provided realm definitions
AuthzGroupService.refreshUser("admin");
// post the login event
EventTrackingService.post(EventTrackingService.newEvent(UsageSessionService.EVENT_LOGIN, null, true));
}
protected void logoutFromSakai() {
// post the logout event
EventTrackingService.post(EventTrackingService.newEvent(UsageSessionService.EVENT_LOGOUT, null, true));
}
public void execute(JobExecutionContext arg0) throws JobExecutionException {
if(log.isDebugEnabled()) log.debug("Updating sakai section metadata from CM via quartz job");
updateSakaiSectionMetadata();
}
}