Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 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.archive.impl;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.archive.api.ArchiveService;
import org.sakaiproject.authz.api.AuthzGroup;
import org.sakaiproject.authz.api.AuthzGroupService;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.content.api.ContentHostingService;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.EntityProducer;
import org.sakaiproject.exception.IdInvalidException;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.IdUsedException;
import org.sakaiproject.exception.InUseException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.util.Xml;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class SiteMerger {
private static Log M_log = LogFactory.getLog(SiteMerger.class);
protected static HashMap userIdTrans = new HashMap();
/**********************************************/
/* Injected Dependencies */
/**********************************************/
protected AuthzGroupService m_authzGroupService = null;
public void setAuthzGroupService(AuthzGroupService service) {
m_authzGroupService = service;
}
protected UserDirectoryService m_userDirectoryService = null;
public void setUserDirectoryService(UserDirectoryService service) {
m_userDirectoryService = service;
}
protected SiteService m_siteService = null;
public void setSiteService(SiteService service) {
m_siteService = service;
}
protected SecurityService m_securityService = null;
public void setSecurityService(SecurityService service) {
m_securityService = service;
}
protected EntityManager m_entityManager = null;
public void setEntityManager(EntityManager m_entityManager) {
this.m_entityManager = m_entityManager;
}
// only the resources created by the followinng roles will be imported
// role sets are different to different system
//public String[] SAKAI_roles = m_filteredSakaiRoles; //= {"Affiliate", "Assistant", "Instructor", "Maintain", "Organizer", "Owner"};
// tool id updates
private String old_toolId_prefix = "chef.";
private String new_toolId_prefix = "sakai.";
private String[] old_toolIds = {"sakai.noti.prefs", "sakai.presence", "sakai.siteinfogeneric", "sakai.sitesetupgeneric", "sakai.threadeddiscussion"};
private String[] new_toolIds = {"sakai.preferences", "sakai.online", "sakai.siteinfo", "sakai.sitesetup", "sakai.discussion"};
//SWG TODO I have a feeling this is a bug
protected HashSet usersListAllowImport = new HashSet();
/**
* Process a merge for the file, or if it's a directory, for all contained files (one level deep).
* @param fileName The site name (for the archive file) to read from.
* @param mergeId The id string to use to make ids in the merge consistent and unique.
* @param creatorId The creator id
* If null or blank, the date/time string of the merge is used.
*/
//TODO Javadoc this
public String merge(String fileName, String siteId, String creatorId, String m_storagePath,
boolean filterSakaiServices, String[] filteredSakaiServices, boolean filterSakaiRoles, String[] filteredSakaiRoles)
{
StringBuilder results = new StringBuilder();
File[] files = null;
// see if the name is a directory
File file = new File(m_storagePath + fileName);
if ((file == null) || (!file.exists()))
{
results.append("file: " + fileName + " not found.\n");
M_log.warn("merge(): file not found: " + file.getPath());
return results.toString();
} else {
try {
// Path outside archive location, discard !
File baseLocation = new File(m_storagePath);
if (!file.getCanonicalPath().startsWith(baseLocation.getCanonicalPath())) {
throw new Exception();
}
} catch (Exception ex) {
results.append("file: " + fileName + " not permitted.\n");
M_log.warn("merge(): file not permitted: " + file.getPath());
return results.toString();
}
}
if (file.isDirectory())
{
files = file.listFiles();
}
else
{
files = new File[1];
files[0] = file;
}
// track old to new attachment names
Map attachmentNames = new HashMap();
// firstly, merge the users
for (int i = 0; i < files.length; i++)
{
if ((files[i] != null) && (files[i].getPath().indexOf("user.xml") != -1))
{
processMerge(files[i].getPath(), siteId, results, attachmentNames, null, filterSakaiServices, filteredSakaiServices, filterSakaiRoles, filteredSakaiRoles);
files[i] = null;
break;
}
}
// see if there's a site definition
for (int i = 0; i < files.length; i++)
{
if ((files[i] != null) && (files[i].getPath().indexOf("site.xml") != -1))
{
processMerge(files[i].getPath(), siteId, results, attachmentNames, creatorId, filterSakaiServices, filteredSakaiServices, filterSakaiRoles, filteredSakaiRoles);
files[i] = null;
break;
}
}
// see if there's an attachments definition
for (int i = 0; i < files.length; i++)
{
if ((files[i] != null) && (files[i].getPath().indexOf("attachment.xml") != -1))
{
processMerge(files[i].getPath(), siteId, results, attachmentNames, null, filterSakaiServices, filteredSakaiServices, filterSakaiRoles, filteredSakaiRoles);
files[i] = null;
break;
}
}
// process each remaining file that is an .xml file
for (int i = 0; i < files.length; i++)
{
if (files[i] != null)
if (files[i].getPath().endsWith(".xml"))
processMerge(files[i].getPath(), siteId, results, attachmentNames, null, filterSakaiServices, filteredSakaiServices, filterSakaiRoles, filteredSakaiRoles);
}
return results.toString();
} // merge
/**
* Read in an archive file and merge the entries into the specified site.
* @param fileName The site name (for the archive file) to read from.
* @param siteId The id of the site to merge the content into.
* @param results A buffer to accumulate result messages.
* @param attachmentNames A map of old to new attachment names.
* @param useIdTrans A map of old WorkTools id to new Ctools id
* @param creatorId The creator id
*/
protected void processMerge(String fileName, String siteId, StringBuilder results, Map attachmentNames, String creatorId, boolean filterSakaiService, String[] filteredSakaiService, boolean filterSakaiRoles, String[] filteredSakaiRoles)
{
// correct for windows backslashes
fileName = fileName.replace('\\', '/');
if (M_log.isDebugEnabled())
M_log.debug("merge(): processing file: " + fileName);
Site theSite = null;
try
{
theSite = m_siteService.getSite(siteId);
}
catch (IdUnusedException ignore) {
M_log.info("Site not found for id:"+siteId+". New site will be created.");
}
// read the whole file into a DOM
Document doc = Xml.readDocument(fileName);
if (doc == null)
{
results.append("Error reading xml from: " + fileName + "\n");
return;
}
// verify the root element
Element root = doc.getDocumentElement();
if (!root.getTagName().equals("archive"))
{
results.append("File: " + fileName + " does not contain archive xml. Found this root tag: " + root.getTagName() + "\n");
return;
}
// get the from site id
String fromSite = root.getAttribute("source");
String system = root.getAttribute("system");
// the children
NodeList children = root.getChildNodes();
final int length = children.getLength();
for(int i = 0; i < length; i++)
{
Node child = children.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE) continue;
Element element = (Element)child;
// look for site stuff
if (element.getTagName().equals(SiteService.APPLICATION_ID))
{
//if the xml file is from WT site, merge it with the translated user ids
//if (system.equalsIgnoreCase(ArchiveService.FROM_WT))
// mergeSite(siteId, fromSite, element, userIdTrans, creatorId);
//else
mergeSite(siteId, fromSite, element, new HashMap()/*empty userIdMap */, creatorId, filterSakaiRoles, filteredSakaiRoles);
}
else if (element.getTagName().equals(UserDirectoryService.APPLICATION_ID))
{ ;
// Apparently, users have only been merged in they are from WorkTools...
// Is this every going to be wanted in Sakai?
// String msg = mergeUsers(element, userIdTrans);
// results.append(msg);
}
else
{
// we need a site now
if (theSite == null)
{
results.append("Site: " + siteId + " not found.\n");
return;
}
// get the service name
String serviceName = translateServiceName(element.getTagName());
// get the service
try
{
EntityProducer service = (EntityProducer) ComponentManager.get(serviceName);
if (service == null) {
// find the service using the EntityManager
List entityProducers = m_entityManager.getEntityProducers();
for (EntityProducer entityProducer : entityProducers) {
if (serviceName.equals(entityProducer.getClass().getName())
|| serviceName.equals(entityProducer.getLabel())
) {
service = entityProducer;
break;
}
}
}
try
{
String msg = "";
if (service != null) {
if ((system.equalsIgnoreCase(ArchiveService.FROM_SAKAI) || system.equalsIgnoreCase(ArchiveService.FROM_SAKAI_2_8))) {
if (checkSakaiService(filterSakaiService, filteredSakaiService, serviceName)) {
// checks passed so now we attempt to do the merge
if (M_log.isDebugEnabled()) M_log.debug("Merging archive data for "+serviceName+" ("+fileName+") to site "+siteId);
msg = service.merge(siteId, element, fileName, fromSite, attachmentNames, new HashMap() /* empty userIdTran map */, usersListAllowImport);
} else {
M_log.warn("Skipping merge archive data for "+serviceName+" ("+fileName+") to site "+siteId+", checked filter failed (filtersOn="+filterSakaiService+", filters="+Arrays.toString(filteredSakaiService)+")");
}
} else {
M_log.warn("Skipping archive data for for "+serviceName+" ("+fileName+") to site "+siteId+", this does not appear to be a sakai archive");
}
} else {
M_log.warn("Skipping archive data for for "+serviceName+" ("+fileName+") to site "+siteId+", no service (EntityProducer) could be found to deal with this data");
}
results.append(msg);
}
catch (Throwable t)
{
results.append("Error merging: " + serviceName + " in file: " + fileName + " : " + t.toString() + "\n");
M_log.warn("Error merging: " + serviceName + " in file: " + fileName + " : " + t.toString(),t);
}
}
catch (Throwable t)
{
results.append("Did not recognize the resource service: " + serviceName + " in file: " + fileName + "\n");
M_log.warn("Did not recognize the resource service: " + serviceName + " in file: " + fileName, t);
}
}
}
} // processMerge
/**
* Merge the site definition from the site part of the archive file into the site service.
* Translate the id to the siteId.
* @param siteId The id of the site getting imported into.
* @param fromSiteId The id of the site the archive was made from.
* @param element The XML DOM tree of messages to merge.
* @param creatorId The creator id
*/
protected void mergeSite(String siteId, String fromSiteId, Element element, HashMap useIdTrans, String creatorId, boolean filterSakaiRoles, String[] filteredSakaiRoles)
{
String source = "";
Node parent = element.getParentNode();
if (parent.getNodeType() == Node.ELEMENT_NODE)
{
Element parentEl = (Element)parent;
source = parentEl.getAttribute("system");
}
NodeList children = element.getChildNodes();
final int length = children.getLength();
for(int i = 0; i < length; i++)
{
Node child = children.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE) continue;
Element element2 = (Element)child;
if (!element2.getTagName().equals("site")) continue;
NodeList toolChildren = element2.getElementsByTagName("tool");
final int tLength = toolChildren.getLength();
for(int i2 = 0; i2 < tLength; i2++)
{
Element element3 = (Element) toolChildren.item(i2);
String toolId = element3.getAttribute("toolId");
if (toolId != null)
{
toolId = toolId.replaceAll(old_toolId_prefix, new_toolId_prefix);
for (int j = 0; j < old_toolIds.length; j++)
{
toolId = toolId.replaceAll(old_toolIds[i], new_toolIds[i]);
}
}
element3.setAttribute("toolId", toolId);
}
// merge the site info first
try
{
m_siteService.merge(siteId, element2, creatorId);
mergeSiteInfo(element2, siteId);
}
catch(Exception any)
{
M_log.warn(any,any);
}
Site site = null;
try
{
site = m_siteService.getSite(siteId);
}
catch (IdUnusedException e)
{
M_log.warn(this + "The site with id " + siteId + " doesn't exit", e);
return;
}
if (site != null)
{
NodeList children2 = element2.getChildNodes();
final int length2 = children2.getLength();
for(int i2 = 0; i2 < length2; i2++)
{
Node child2 = children2.item(i2);
if (child2.getNodeType() != Node.ELEMENT_NODE) continue;
Element element3 = (Element)child2;
if (!element3.getTagName().equals("roles")) continue;
try {
mergeSiteRoles(element3, siteId, useIdTrans, filterSakaiRoles, filteredSakaiRoles);
}
catch (PermissionException e1) {
M_log.warn(e1,e1);
}
}
}
}
} // mergeSite
/**
* Merge the site info like description from the site part of the archive file into the site service.
* @param element The XML DOM tree of messages to merge.
* @param siteId The id of the site getting imported into.
*/
protected void mergeSiteInfo(Element el, String siteId)
throws IdInvalidException, IdUsedException, PermissionException, IdUnusedException, InUseException
{
// heck security (throws if not permitted)
unlock(SiteService.SECURE_UPDATE_SITE, m_siteService.siteReference(siteId));
Site edit = m_siteService.getSite(siteId);
String desc = el.getAttribute("description-enc");
try
{
byte[] decoded = Base64.decodeBase64(desc.getBytes("UTF-8"));
byte[] filteredDecoded = decoded;
for(int i=0; i node
Node parent0 = el.getParentNode(); // parent0: node
Node parent1 = parent0.getParentNode(); // parent1: node
Node parent = parent1.getParentNode(); // parent: node containing "system"
if (parent.getNodeType() == Node.ELEMENT_NODE)
{
Element parentEl = (Element)parent;
source = parentEl.getAttribute("system");
}
List roles = new Vector();
//List maintainUsers = new Vector();
//List accessUsers = new Vector();
// to add this user with this role inito this realm
String realmId = m_siteService.siteReference(siteId); //SWG "/site/" + siteId;
try
{
AuthzGroup realm = m_authzGroupService.getAuthzGroup(realmId);
roles.addAll(realm.getRoles());
NodeList children = el.getChildNodes();
final int length = children.getLength();
for(int i = 0; i < length; i++)
{
Node child = children.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE) continue;
Element element2 = (Element)child;
String roleId = null;
if (ArchiveService.FROM_SAKAI_2_8.equals(source))
{
if (!"role".equals(element2.getTagName())) continue;
roleId = element2.getAttribute("roleId");
}
else
{
roleId = element2.getTagName();
}
//SWG Getting rid of WT part above, this was previously the else branch labeled "for both CT classic and Sakai CTools"
// check is this roleId is a qualified one
if (!checkSystemRole(source, roleId, filterSakaiRoles, filteredSakaiRoles)) continue;
NodeList children2 = element2.getChildNodes();
final int length2 = children2.getLength();
for(int i2 = 0; i2 < length2; i2++)
{
Node child2 = children2.item(i2);
if (child2.getNodeType() != Node.ELEMENT_NODE) continue;
Element element3 = (Element)child2;
if (!element3.getTagName().equals("ability")) continue;
String userId = element3.getAttribute("userId");
// this user has a qualified role, his/her resource will be imported
usersListAllowImport.add(userId);
}
} // for
}
catch(Exception err)
{
M_log.warn("()mergeSiteRoles realm edit exception caught" + realmId,err);
}
return;
} // mergeSiteRoles
/**
* Merge the user list into the the system.
* Translate the id to the siteId.
* @param element The XML DOM tree of messages to merge.
*/
//SWG This seems to have been abandoned for anything for WorkTools.
// If we need the ability to import users again, see ArchiveServiceImpl.java
// for the implementation of this method.
//protected String mergeUsers(Element element, HashMap useIdTrans)
//throws IdInvalidException, IdUsedException, PermissionException
/**
* Old archives have the old CHEF 1.2 service names...
*/
protected String translateServiceName(String name)
{
if ("org.chefproject.service.GenericContentHostingService".equals(name))
{
return ContentHostingService.class.getName();
}
return name;
}
/*
*
*/
protected boolean checkSakaiService (boolean m_filterSakaiServices, String[] m_filteredSakaiServices, String serviceName)
{
if (m_filterSakaiServices)
{
for (int i = 0; i < m_filteredSakaiServices.length; i ++)
{
if (serviceName.endsWith(m_filteredSakaiServices[i].toString()))
{
return true;
}
}
return false;
}
else
{
return true;
}
}
/**
* Check security permission.
* @param lock The lock id string.
* @param reference The resource's reference string, or null if no resource is involved.
* @exception PermissionException thrown if the user does not have access
*/
protected void unlock(String lock, String reference) throws PermissionException
{
if (!m_securityService.unlock(lock, reference))
{
// needs to bring back: where is sessionService
// throw new PermissionException(UsageSessionService.getSessionUserId(), lock, reference);
}
} // unlock
/**
* When Sakai is importing a role in site.xml, check if it is a qualified role.
* @param roleId
* @return boolean value - true: the role is accepted for importing; otherwise, not;
*/
protected boolean checkSystemRole(String system, String roleId, boolean filterSakaiRoles, String[] filteredSakaiRoles) {
if (system.equalsIgnoreCase(ArchiveService.FROM_SAKAI) || system.equalsIgnoreCase(ArchiveService.FROM_SAKAI_2_8)) {
if (filterSakaiRoles)
{
for (int i = 0; i