org.sakaiproject.archive.impl.BasicArchiveService.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.archive.impl.BasicArchiveService.java

Source

/**********************************************************************************
 * $URL: https://source.sakaiproject.org/svn/common/trunk/archive-impl/impl/src/java/org/sakaiproject/archive/impl/BasicArchiveService.java $
 * $Id: BasicArchiveService.java 105077 2012-02-24 22:54:29Z ottenhoff@longsight.com $
 ***********************************************************************************
 *
 * 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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
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.AuthzPermissionException;
import org.sakaiproject.authz.api.GroupNotDefinedException;
import org.sakaiproject.authz.api.Role;
import org.sakaiproject.authz.cover.AuthzGroupService;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
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.cover.SiteService;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.cover.TimeService;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserAlreadyDefinedException;
import org.sakaiproject.user.api.UserEdit;
import org.sakaiproject.user.api.UserIdInvalidException;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.api.UserPermissionException;
import org.sakaiproject.user.cover.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;

/**
* <p>...</p>
*/
public class BasicArchiveService implements ArchiveService {
    /** Our logger. */
    private static Log M_log = LogFactory.getLog(BasicArchiveService.class);

    /** A full path and file name to the storage file. */
    protected String m_storagePath = "/";

    protected final static HashMap userIdTrans = new HashMap();

    protected HashSet usersListAllowImport = new HashSet();

    // only the resources created by the followinng roles will be imported
    // role sets are different to different system
    public String[] SAKAI_roles = { "Affiliate", "Assistant", "Instructor", "Maintain", "Organizer", "Owner" };
    public String[] CT_roles = { "Affiliate", "Assistant", "Instructor", "Maintain", "Organizer", "Owner" };
    public String[] WT_roles = {};

    // 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" };

    // only these Sakai tools will be imported
    public String[] sakaiServicesToImport = { "AnnouncementService", "AssignmentService", "ContentHostingService",
            "CalendarService", "DiscussionService", "MailArchiveService", "SyllabusService", "RWikiObjectService",
            "DiscussionForumService", "WebService" };

    public String[] CT_tools_toImport = {};
    public String[] WT_tools_toImport = {};

    //TODO: the draft flag settings for WT and CT

    public HashMap tool_draft_flag = new HashMap();

    /*******************************************************************************
    * Dependencies and their setter methods
    *******************************************************************************/

    /** Dependency: ServerConfigurationService. */
    protected ServerConfigurationService m_serverConfigurationService = null;

    /**
     * Dependency: ServerConfigurationService.
     * @param service The ServerConfigurationService.
     */
    public void setServerConfigurationService(ServerConfigurationService service) {
        m_serverConfigurationService = service;
    }

    /**
     * Configuration: Set the Storage Path.
     * @param path The storage path.
     */
    public void setStoragePath(String path) {
        m_storagePath = path;
    }

    /** Dependency: EntityManager. */
    protected EntityManager m_entityManager = null;

    private ContentHostingService contentHostingService;

    /**
     * Dependency: EntityManager.
     * 
     * @param service
     *        The EntityManager.
     */
    public void setEntityManager(EntityManager service) {
        m_entityManager = service;
    }

    /*******************************************************************************
    * Init and Destroy
    *******************************************************************************/

    /**
     * Final initialization, once all dependencies are set.
     */
    public void init() {
        contentHostingService = (ContentHostingService) ComponentManager.get(ContentHostingService.class.getName());
        if ((m_storagePath != null) && (!m_storagePath.endsWith("/"))) {
            m_storagePath = m_storagePath + "/";
        }

        M_log.info("init(): storage path: " + m_storagePath);
    }

    /**
     * Final cleanup.
     */
    public void destroy() {
        M_log.info("destroy()");
    }

    /*******************************************************************************
    * ArchiveService implementation
    *******************************************************************************/

    /**
    * Create an archive for the resources of a site.
    * @param siteId The id of the site to archive.
    * @return A log of messages from the archive.
    */
    public String archive(String siteId) {
        StringBuilder results = new StringBuilder();

        if (M_log.isDebugEnabled())
            M_log.debug("archive(): site: " + siteId);

        Site theSite = null;
        try {
            theSite = SiteService.getSite(siteId);
        } catch (IdUnusedException e) {
            results.append("Site: " + siteId + " not found.\n");
            M_log.warn("archive(): site not found: " + siteId);
            return results.toString();
        }

        // collect all the attachments we need
        List attachments = m_entityManager.newReferenceList();

        Time now = TimeService.newTime();

        // this is the folder we are writing files to
        String storagePath = m_storagePath + siteId + "-archive/";

        // create the directory for the archive
        File dir = new File(m_storagePath + siteId + "-archive/");
        dir.mkdirs();

        // for each registered ResourceService, give it a chance to archve
        List services = m_entityManager.getEntityProducers();
        for (Iterator iServices = services.iterator(); iServices.hasNext();) {
            EntityProducer service = (EntityProducer) iServices.next();
            if (service == null)
                continue;
            if (!service.willArchiveMerge())
                continue;

            Document doc = Xml.createDocument();
            Stack stack = new Stack();
            Element root = doc.createElement("archive");
            doc.appendChild(root);
            root.setAttribute("source", siteId);
            root.setAttribute("server", m_serverConfigurationService.getServerId());
            root.setAttribute("date", now.toString());
            root.setAttribute("system", FROM_SAKAI_2_8);

            stack.push(root);

            try {
                String msg = service.archive(siteId, doc, stack, storagePath, attachments);
                results.append(msg);
            } catch (Throwable t) {
                results.append(t.toString() + "\n");
            }

            stack.pop();

            String fileName = storagePath + service.getLabel() + ".xml";
            Xml.writeDocument(doc, fileName);
        }

        // archive the collected attachments
        if (attachments.size() > 0) {
            Document doc = Xml.createDocument();
            Stack stack = new Stack();
            Element root = doc.createElement("archive");
            doc.appendChild(root);
            root.setAttribute("source", siteId);
            root.setAttribute("server", m_serverConfigurationService.getServerId());
            root.setAttribute("date", now.toString());
            root.setAttribute("system", FROM_SAKAI_2_8);

            stack.push(root);

            String msg = contentHostingService.archiveResources(attachments, doc, stack, storagePath);
            results.append(msg);

            stack.pop();

            String fileName = storagePath + "attachment.xml";
            Xml.writeDocument(doc, fileName);
        }

        // *** Site

        Document doc = Xml.createDocument();
        Stack stack = new Stack();
        Element root = doc.createElement("archive");
        doc.appendChild(root);
        root.setAttribute("site", siteId);
        root.setAttribute("date", now.toString());
        root.setAttribute("system", FROM_SAKAI_2_8);

        stack.push(root);

        String msg = archiveSite(theSite, doc, stack);
        results.append(msg);

        stack.pop();
        Xml.writeDocument(doc, m_storagePath + siteId + "-archive/site.xml");

        // *** Users
        doc = Xml.createDocument();
        stack = new Stack();
        root = doc.createElement("archive");
        doc.appendChild(root);
        root.setAttribute("site", siteId);
        root.setAttribute("date", now.toString());
        root.setAttribute("system", FROM_SAKAI_2_8);

        stack.push(root);

        msg = archiveUsers(theSite, doc, stack);
        results.append(msg);

        stack.pop();
        Xml.writeDocument(doc, m_storagePath + siteId + "-archive/user.xml");

        return results.toString();

    } // archive

    /**
    * Archive the site definition.
    * @param site the site.
    * @param doc The document to contain the xml.
    * @param stack The stack of elements, the top of which will be the containing
    * element of the "site" element.
    */

    protected static String archiveSite(Site site, Document doc, Stack stack) {
        Element element = doc.createElement(SiteService.APPLICATION_ID);
        ((Element) stack.peek()).appendChild(element);
        stack.push(element);

        Element siteNode = site.toXml(doc, stack);
        stack.push(siteNode);

        // to add the realm node with user list into site
        List roles = new Vector();
        String realmId = "/site/" + site.getId();
        try {
            Role role = null;
            AuthzGroup realm = AuthzGroupService.getAuthzGroup(realmId);

            Element realmNode = doc.createElement("roles");
            ((Element) stack.peek()).appendChild(realmNode);
            stack.push(realmNode);

            roles.addAll(realm.getRoles());

            for (int i = 0; i < roles.size(); i++) {
                role = (Role) roles.get(i);
                String roleId = role.getId();
                Element node = doc.createElement(roleId);
                realmNode.appendChild(node);

                List users = new Vector();
                users.addAll(realm.getUsersHasRole(role.getId()));
                for (int j = 0; j < users.size(); j++) {
                    Element abilityNode = doc.createElement("ability");
                    abilityNode.setAttribute("roleId", roleId);
                    abilityNode.setAttribute("userId", ((String) users.get(j)));
                    node.appendChild(abilityNode);
                }
            }
        } catch (Exception any) {
            // M_log.warn("archve: exception archiving site: "+ site.getId() + ": ", any);
        }

        stack.pop();

        return "archiving Site: " + site.getId() + "\n";

    } // archiveSite

    /**
    * Archive the users defined in this site (internal users only).
    * @param site the site.
    * @param doc The document to contain the xml.
    * @param stack The stack of elements, the top of which will be the containing
    * element of the "site" element.
    */
    protected static String archiveUsers(Site site, Document doc, Stack stack) {
        Element element = doc.createElement(UserDirectoryService.APPLICATION_ID);
        ((Element) stack.peek()).appendChild(element);
        stack.push(element);

        try {
            // get the site's user list
            List users = new Vector();
            String realmId = "/site/" + site.getId();
            try {
                AuthzGroup realm = AuthzGroupService.getAuthzGroup(realmId);
                users.addAll(UserDirectoryService.getUsers(realm.getUsers()));
                Collections.sort(users);
                for (int i = 0; i < users.size(); i++) {
                    User user = (User) users.get(i);
                    user.toXml(doc, stack);
                }
            } catch (GroupNotDefinedException e) {
                //Log.warn("chef", "SiteAction.updateParticipantList  IdUnusedException " + realmId);
            } catch (Exception any) {
            }

        } catch (Exception any) {
            //.M_log.warn("archve: exception archiving users: "
            //   + site.getId() + ": ", any);
        }

        stack.pop();

        return "archiving the users for Site: " + site.getId() + "\n";

    } // archiveUsers

    /**
    * 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.
    */
    public String merge(String fileName, String siteId, String creatorId) {
        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: " + file.getPath() + " not found.\n");
            M_log.warn("merge(): file not found: " + 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);
                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);
                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);
                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);
        }

        return results.toString();

    } // merge

    /**
     * When Sakai is importing an item archived by Sakai, check the creator's role first.
     * The item is imported when the role is in the acceptance list,
     * @param siteId
     * @param userId
     * @return boolean value - true: the role is accepted for importing; otherwise, not;
     */
    public boolean checkSakaiRole(String siteId, String userId) {
        // Check - In sakai, if this tool accept this role during importing
        // currently, all the tools allowed to be imported, are using the same role set
        try {
            AuthzGroup realm = AuthzGroupService.getAuthzGroup(siteId);

            // get the role of the user as this realm
            Role role = realm.getRole(userId);

            for (int i = 0; i < SAKAI_roles.length; i++) {
                if (!SAKAI_roles[i].equalsIgnoreCase(role.getId()))
                    continue;
                return true;
            }
        } catch (GroupNotDefinedException e) {
        }

        return false;

    }//checkSakaiRole

    /**
     * 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) {
        if (system.equalsIgnoreCase(FROM_CT)) {
            // Check - if CT classic accepts the resource made by this role during importing
            for (int i = 0; i < CT_roles.length; i++) {
                if (!CT_roles[i].equalsIgnoreCase(roleId))
                    continue;
                return true;
            }
        } else if (system.equalsIgnoreCase(FROM_SAKAI) || system.equalsIgnoreCase(FROM_SAKAI_2_8)) {
            // Check - if CTools accepts the resource made by this role during importing
            for (int i = 0; i < SAKAI_roles.length; i++) {
                if (!SAKAI_roles[i].equalsIgnoreCase(roleId))
                    continue;
                return true;
            }
        }

        return false;

    }//checkSystemRole

    /*
     * 
     */
    protected boolean checkSakaiService(String serviceName) {
        for (int i = 0; i < sakaiServicesToImport.length; i++) {
            if (serviceName.endsWith(sakaiServicesToImport[i])) {
                return true;
            }
        }
        return false;
    }

    /**
     * When importing an item, check if it needs to be set as a draft
     * @param system The system by which this file was archived
     * @param toolService The service name of the tool calling this function
     * @return boolean value - true: draft requested; false: as it is.
     */
    /*
    public boolean checkToolDraftFlag(String system, String toolService)
    {
       if (system.equalsIgnoreCase(FROM_SAKAI))
       {
     if (toolService.equalsIgnoreCase(AnnouncementService.SERVICE_NAME))
     {
        return SAKAI_annc_draft_import;
     }
     else if (toolService.equalsIgnoreCase(AssignmentService.SERVICE_NAME))
     {
        return SAKAI_assign_draft_import;
     }
     else if (toolService.equalsIgnoreCase(ContentHostingService.SERVICE_NAME))
     {
        return SAKAI_rsc_draft_import;
     }
     else if (toolService.equalsIgnoreCase(CalendarService.SERVICE_NAME))
     {
        return SAKAI_schedule_draft_import;
     }
     else if (toolService.equalsIgnoreCase(DiscussionService.SERVICE_NAME))
     {
        return SAKAI_disc_draft_import;
     }
     else
        return false;
       }
       else
       {
     // TODO: WT or CT may use different rules
     return false;
       }
           
    } //checkToolDraftFlag
    */

    /**
    * 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) {
        // correct for windows backslashes
        fileName = fileName.replace('\\', '/');

        if (M_log.isDebugEnabled())
            M_log.debug("merge(): processing file: " + fileName);

        Site theSite = null;
        try {
            theSite = SiteService.getSite(siteId);
        } catch (IdUnusedException ignore) {
        }

        // 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(FROM_WT))
                    mergeSite(siteId, fromSite, element, userIdTrans, creatorId);
                else
                    mergeSite(siteId, fromSite, element, new HashMap()/*empty userIdMap */, creatorId);
            } else if (element.getTagName().equals(UserDirectoryService.APPLICATION_ID)) {
                try {
                    // merge the users in only when they are from WorkTools
                    if (system.equalsIgnoreCase(FROM_WT)) {
                        String msg = mergeUsers(element, userIdTrans);
                        results.append(msg);
                    }
                } catch (Exception any) {
                }
            }

            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);

                    try {
                        String msg = "";
                        // if the xml file is from WT site, merge it with user id translation
                        if (system.equalsIgnoreCase(FROM_WT))
                            msg = service.merge(siteId, element, fileName, fromSite, attachmentNames, userIdTrans,
                                    new HashSet());
                        else if ((system.equalsIgnoreCase(FROM_SAKAI) || system.equalsIgnoreCase(FROM_SAKAI_2_8))
                                && (checkSakaiService(serviceName)))
                            msg = service.merge(siteId, element, fileName, fromSite, attachmentNames,
                                    new HashMap() /* empty userIdTran map */, usersListAllowImport);
                        else if (system.equalsIgnoreCase(FROM_CT))
                            msg = service.merge(siteId, element, fileName, fromSite, attachmentNames,
                                    new HashMap() /* empty userIdTran map */, usersListAllowImport);

                        results.append(msg);
                    } catch (Throwable t) {
                        results.append("Error merging: " + serviceName + " in file: " + fileName + " : "
                                + t.toString() + "\n");
                    }
                } catch (Throwable t) {
                    results.append("Did not recognize the resource service: " + serviceName + " in file: "
                            + fileName + "\n");
                }
            }
        }

    } // processMerge

    /**
    * 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 (!SecurityService.unlock(lock, reference)) {
            // needs to bring back: where is sessionService
            // throw new PermissionException(UsageSessionService.getSessionUserId(), lock, reference);
        }
    } // unlock

    /**
    * 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, SiteService.siteReference(siteId));

        Site edit = 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 < decoded.length; i++) {
                byte b = decoded[i];
                if (b == (byte) -109 || b == (byte) -108) {
                    // smart quotes, open/close double quote
                    filteredDecoded[i] = (byte) 34;
                } else if (b == (byte) -111 || b == (byte) -110) {
                    // smart quotes, open/close double quote
                    filteredDecoded[i] = (byte) 39;
                } else if (b == (byte) -106) {
                    // dash
                    filteredDecoded[i] = (byte) 45;
                }
            }
            desc = new String(decoded, "UTF-8");
        } catch (Exception any) {
            M_log.warn("mergeSiteInfo(): exception caught");
        }
        //edit.setTitle(title);
        edit.setDescription(desc);

        SiteService.save(edit);

        return;

    } // mergeSiteInfo

    /**
    * Merge the the permission-roles settings into the site
    * @param element The XML DOM tree of messages to merge.
    * @param siteId The id of the site getting imported into.
    */
    protected void mergeSiteRoles(Element el, String siteId, HashMap useIdTrans) throws PermissionException {
        // heck security (throws if not permitted)
        unlock(SiteService.SECURE_UPDATE_SITE, SiteService.siteReference(siteId));

        String source = "";

        // el: <roles> node         
        Node parent0 = el.getParentNode(); // parent0: <site> node
        Node parent1 = parent0.getParentNode(); // parent1: <service> node
        Node parent = parent1.getParentNode(); // parent: <archive> node containing "system"

        if (parent.getNodeType() == Node.ELEMENT_NODE) {
            Element parentEl = (Element) parent;
            source = parentEl.getAttribute("system");
        }

        List roles = new Vector();
        // to add this user with this role inito this realm
        String realmId = "/site/" + siteId;
        try {
            //AuthzGroup realmEdit = AuthzGroupService.getRealm(realmId);
            AuthzGroup realm = AuthzGroupService.getAuthzGroup(realmId);

            //roles.addAll(realmEdit.getRoles());
            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;

                if (source.equalsIgnoreCase(FROM_WT)) {
                    // from WT, merge the users with roles into the new site

                    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");

                        // under 2 conditions the userIdTrans would be empty
                        // 1st is, even from WT, no user id has been processed
                        // 2nd is, this user is not from WT. userIdTrans is always empty
                        if (!userIdTrans.isEmpty()) {
                            // user the new id if the old one from WT has been replaced
                            String newId = (String) useIdTrans.get(userId);
                            if (newId != null)
                                userId = newId;
                        }
                        try {
                            User user = UserDirectoryService.getUser(userId);
                            String roleId = element3.getAttribute("roleId");
                            //Role role = realmEdit.getRole(roleId);
                            Role role = realm.getRole(roleId);
                            if (role != null) {
                                AuthzGroup realmEdit = AuthzGroupService.getAuthzGroup(realmId);
                                realmEdit.addMember(user.getId(), role.getId(), true, false);
                                AuthzGroupService.save(realmEdit);
                            }
                        } catch (UserNotDefinedException e) {
                            M_log.warn("UserNotDefined in mergeSiteRoles: " + userId);
                        } catch (AuthzPermissionException e) {
                            M_log.warn("AuthzPermissionException in mergeSiteRoles", e);
                        }
                    }
                } else {
                    // for both CT classic and Sakai CTools

                    // check is this roleId is a qualified one
                    if (!checkSystemRole(source, element2.getTagName()))
                        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);
                    }
                } // if - elseif - elseif
            } // for
        } catch (GroupNotDefinedException err) {
            M_log.warn("()mergeSiteRoles realm edit exception caught GroupNotDefinedException " + realmId);
        }
        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.
    */

    protected String mergeUsers(Element element, HashMap useIdTrans)
            throws IdInvalidException, IdUsedException, PermissionException {
        String msg = "";
        int count = 0;

        // The flag showing from WT
        boolean fromWT = false;
        boolean fromCTclassic = false;
        boolean fromCTools = false;
        String source = "";

        Node parent = element.getParentNode();
        if (parent.getNodeType() == Node.ELEMENT_NODE) {
            Element parentEl = (Element) parent;
            source = parentEl.getAttribute("system");
        }

        if (source != null) {
            if (source.equalsIgnoreCase(FROM_CT))
                fromCTclassic = true;
            else if (source.equalsIgnoreCase(FROM_WT))
                fromWT = true;
            else
                fromCTools = true;
        } else
            fromCTools = true;

        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("user"))
                continue;

            //for WorkTools
            if (fromWT) {
                // Worktools use email address as Id
                String wtId = element2.getAttribute("id");
                // check if this is an umich address
                if (wtId.endsWith("umich.edu")) {
                    // if this id is a UM unique name
                    // trim the first part of the email as the id
                    String userId = wtId.substring(0, wtId.indexOf("@"));
                    // change the id to be the first part of wtId
                    element2.setAttribute("id", userId);

                    // add the entry (wtEmail <-> userId) into map
                    useIdTrans.put(wtId, userId);

                    try {
                        User user = UserDirectoryService.getUser(userId);
                        // if this user id exists, do nothing.
                    } catch (UserNotDefinedException e) {
                        // this umich id does not exit, merging will create a new user with this id
                        try {
                            UserEdit userEdit = UserDirectoryService.mergeUser(element2);
                            UserDirectoryService.commitEdit(userEdit);
                            count++;
                            // because it is an UM id, report it in the merge log.
                            msg = msg.concat("The user id " + userId + "(" + wtId
                                    + ") doesn't exist, and was just created. \n");
                        } catch (UserIdInvalidException error) {
                            msg = msg.concat("This user with id -" + wtId
                                    + ", can't be merged because of the invalid email address.\n");
                        } catch (UserAlreadyDefinedException error) {
                        } catch (UserPermissionException error) {
                        }
                    }

                } else {
                    // for non-UM email, process as a friend account id
                    try {
                        // test if it is a friend account id
                        User user = UserDirectoryService.getUser(wtId);
                        // if the user exists, do nothing.
                    } catch (UserNotDefinedException e) {
                        try {
                            // if this isn't such a friend email address,
                            // create a new friend account for it
                            UserEdit userEdit = UserDirectoryService.mergeUser(element2);
                            UserDirectoryService.commitEdit(userEdit);
                            count++;
                        } catch (UserIdInvalidException error) {
                            msg = msg.concat("This user with id -" + wtId
                                    + ", can't be merged because of the invalid email address.\n");
                        } catch (UserAlreadyDefinedException error) {
                        } catch (UserPermissionException error) {
                        }
                    }

                }
            }
            // not allowing merging users form CT classic or CTools.
            /*
            else if (fromCTclassic)
            {
               String ctId = element2.getAttribute("id");
                
               try
               {
                  User user = UserDirectoryService.getUser(ctId);
               }
               catch(IdUnusedException e)
               {
                  // if this umich id does not exit, report it in importing log.
                  msg.concat("The user id " + ctId + " doesn't exist, and was just created. \n");
               }
                      
               try
               {
                  // override the old one or create a new user with this id
                  UserEdit userEdit = UserDirectoryService.mergeUser(element2);
                  UserDirectoryService.commitEdit(userEdit);
                  count++;
               }
               catch(IdInvalidException error)
               {
                  msg.concat("This user with id -" + ctId + ", can't be merged because of the invalid email address.\n");
               }
               catch(IdUsedException error)
               {
               }
               catch(PermissionException error)
               {
               }
                        
            }
            else if (fromCTools)
            {
               try
               {
                  UserEdit userEdit = UserDirectoryService.mergeUser(element2);
                  UserDirectoryService.commitEdit(userEdit);
                  count++;
               }
               catch(IdInvalidException error)
               {
                  msg.concat("This user with id -" + element2.getAttribute("id") + ", can't be merged because of the invalid email address.\n");
               }
               catch(IdUsedException error)
               {
               }
               catch(PermissionException error)
               {
               }
            }
            */
        }

        msg = msg + "merging user" + "(" + count + ") users\n";
        return msg;

    } // mergeUsers

    /**
    * 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) {
        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 {
                SiteService.merge(siteId, element2, creatorId);
                mergeSiteInfo(element2, siteId);
            } catch (Exception any) {
            }

            Site site = null;
            try {
                site = SiteService.getSite(siteId);
            } catch (IdUnusedException e) {
                M_log.warn(this + "The site with id " + siteId + " doesn't exit");
                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;

                    // only merge roles when from Worktools
                    //if (source.equalsIgnoreCase(FROM_WT))
                    //{
                    // merge the permission-roles

                    // mergeSiteRoles will merge users from WT into the new site
                    // it also creates a set for the users from CT or CTools having a certain role
                    try {
                        mergeSiteRoles(element3, siteId, useIdTrans);
                    } catch (PermissionException e1) {
                        //}
                    }
                }
            }
        }
    } // mergeSite

    /**
    * Merge the content attachment resources from the attachments part of the
    * archive file into the content hosting service.
    * Map the attachment folder to something new based on the mergeId.
    * @param mergeId The value pre-pended to the numeric attachment folder id from the archive.
    * to make it unique here.
    * @param root The XML DOM tree of content to merge.
    */
    /*
       protected void mergeAttachments(String mergeId, Element root)
       {
          try
          {
     ContentHostingService service = (ContentHostingService)TurbineServices.getInstance()
                       .getService(ContentHostingService.SERVICE_NAME);
        
     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)
        {
           Element element = (Element)child;
        
           // for "resource" kids
           if (element.getTagName().equals("resource"))
           {
              // map the attachment area folder name
              String oldId = element.getAttribute("id");
              if (oldId.startsWith("/attachment/"))
              {
                 String newId = "/attachment/"
                    + mergeId + "-"
                    + oldId.substring(12);
                 element.setAttribute("id", newId);
              }
        
              //    resource: add if missing
              service.mergeResource(element);
           }
        }
     }
          }
          catch (Exception any)
          {
     M_log.warn("mergeAttachments(): exception: ", any);
          }
       }   // mergeAttachments
    */

    /**
     * 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;
    }

} // BasicArchiveService