org.theospi.portfolio.portal.web.XsltPortal.java Source code

Java tutorial

Introduction

Here is the source code for org.theospi.portfolio.portal.web.XsltPortal.java

Source

/**********************************************************************************
* $URL:https://source.sakaiproject.org/svn/osp/trunk/portal/webapp/src/java/org/theospi/portfolio/portal/web/XsltPortal.java $
* $Id:XsltPortal.java 9134 2006-05-08 20:28:42Z chmaurer@iupui.edu $
***********************************************************************************
*
 * Copyright (c) 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.theospi.portfolio.portal.web;

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.OutputKeys;
import org.sakaiproject.authz.api.Role;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.portal.charon.CharonPortal;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SitePage;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.tool.api.*;
import org.sakaiproject.tool.cover.ActiveToolManager;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.user.api.Preferences;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.cover.PreferencesService;
import org.sakaiproject.util.ResourceLoader;
import org.apache.commons.lang.StringUtils;
import org.sakaiproject.util.Web;
import org.theospi.portfolio.portal.intf.PortalManager;
import org.theospi.portfolio.portal.model.SitePageWrapper;
import org.theospi.portfolio.portal.model.SiteType;
import org.theospi.portfolio.portal.model.ToolCategory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;

/**
 * Created by IntelliJ IDEA.
 * User: John Ellis
 * Date: Feb 9, 2006
 * Time: 2:21:33 PM
 * To change this template use File | Settings | File Templates.
 */
public class XsltPortal extends CharonPortal {

    private PortalManager portalManager;
    private DocumentBuilder documentBuilder;
    private Templates templates;
    private Templates toolCategoryTemplates;
    private URIResolver servletResolver;
    private String categoryBasePath;

    /** messages. */
    private static ResourceLoader rb = new ResourceLoader("org/theospi/portfolio/portal/messages");

    /** base messages. */
    private static ResourceLoader rbsitenav = new ResourceLoader("sitenav");

    private static final String TOOL_CATEGORY = "category";
    private static final String TOOL_CATEGORY_HELPER = "category_helper";
    private static final String SITE_TYPE = "site_type";
    private static final String SITE_TYPE_HELPER = "site_type_helper";

    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // get the Sakai session
        Session session = SessionManager.getCurrentSession();

        // recognize what to do from the path
        String option = req.getPathInfo();

        // get the parts (the first will be "")
        String[] parts = option.split("/");

        if (parts.length < 2) {
            super.doPost(req, res);
            return;
        }

        if (parts[1].equals(SITE_TYPE_HELPER)) {
            // Resolve the site_type of the form /portal/site_type_helper/project
            String siteTypeKey = parts[2];
            doSiteTypeHelper(req, res, session, siteTypeKey, parts.length == 4);
        } else {
            super.doPost(req, res);
        }
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        // get the Sakai session
        Session session = SessionManager.getCurrentSession();

        // recognize what to do from the path
        String option = req.getPathInfo();

        // get the parts (the first will be "")
        String[] parts = option.split("/");

        if (parts.length < 2) {
            super.doGet(req, res);
            return;
        }

        if (parts[1].equals(SITE_TYPE)) {
            // Resolve the site_type of the form /portal/site_type/project
            String siteTypeKey = parts[2];
            doSiteType(req, res, session, siteTypeKey);
        } else if (parts[1].equals(SITE_TYPE_HELPER)) {
            // Resolve the site_type of the form /portal/site_type_helper/project
            String siteTypeKey = parts[2];
            doSiteTypeHelper(req, res, session, siteTypeKey, parts.length == 4);
        } else if (parts[1].equals(TOOL_CATEGORY)) {
            // Resolve the site_type of the form /portal/category/<siteId>/<categoryKey>/<optionalToolId>
            String siteId = parts[2];
            String categoryKey = parts[3];
            String pageId = null;
            if (parts.length > 4) {
                pageId = parts[4];
            }
            doCategory(req, res, session, siteId, categoryKey, pageId);
        } else if (parts[1].equals(TOOL_CATEGORY_HELPER)) {
            // Resolve the site_type of the form /portal/category_helper/<siteId>/<categoryKey>
            String siteId = parts[2];
            String categoryKey = parts[3];
            doCategoryHelper(req, res, session, siteId, categoryKey, parts.length > 4);
        } else {
            super.doGet(req, res);
        }
    }

    protected void forwardPortal(ActiveTool tool, HttpServletRequest req, HttpServletResponse res,
            ToolConfiguration p, String skin, String toolContextPath, String toolPathInfo)
            throws ToolException, IOException {

        // if there is a stored request state, and path, extract that from the
        // session and
        // reinstance it

        // generate the forward to the tool page placement
        String portalPlacementUrl = getPortalString() + super.getPortalPageUrl(p);
        res.sendRedirect(portalPlacementUrl);
        return;

    }

    protected String getPortalString() {
        return "/osp-portal";
    }

    protected void doCategoryHelper(HttpServletRequest req, HttpServletResponse res, Session session, String siteId,
            String categoryKey, boolean returning) throws ToolException, IOException {
        if (session.getUserId() == null) {
            doLogin(req, res, session, req.getPathInfo(), false);
            return;
        }

        Site site = getPortalManager().getSite(siteId);
        String siteTypeKey = getPortalManager().decorateSiteType(site);
        SiteType siteType = getPortalManager().getSiteType(siteTypeKey);

        Document doc = getDocumentBuilder().newDocument();
        Element root = doc.createElement("toolCategory");
        ToolCategory category = getPortalManager().getToolCategory(siteType.getKey(), categoryKey);

        Map categoryPageMap = getPortalManager().getPagesByCategory(siteId);
        List categoryPages = (List) categoryPageMap.get(category);
        root.appendChild(createCategoryXml(doc, category, categoryPages, siteId, categoryKey, null));

        Element rolesElement = createRolesXml(doc, siteId);
        root.appendChild(rolesElement);

        doc.appendChild(root);
        outputDocument(req, res, session, doc, getToolCategoryTransformer());

        /*
        ToolSession toolSession = session.getToolSession(Web.escapeJavascript(categoryKey));
            
        if (!returning) {
           toolSession.setAttribute(PortalManager.SITE_TYPE, siteTypeKey);
           toolSession.setAttribute(PortalManager.SITE_ID, siteId);
           toolSession.setAttribute(PortalManager.TOOL_CATEGORY, categoryKey);
           toolSession.setAttribute(PortalManager.CONTEXT, getContext());
        }
            
        // put the session in the request attribute
        req.setAttribute(Tool.TOOL_SESSION, toolSession);
            
        // set as the current tool session
        SessionManager.setCurrentToolSession(toolSession);
            
        // put the placement id in the request attribute
        String placementId = Web.escapeJavascript(categoryKey);
        req.setAttribute(Tool.PLACEMENT_ID, placementId);
            
        ActiveTool helperTool = ActiveToolManager.getActiveTool("osp.tool.category");
        Placement placement = new org.sakaiproject.util.Placement(placementId, helperTool, null, null, null);
            
        String context = req.getPathInfo();
        forwardTool(helperTool, req, res, placement, siteType.getSkin(), getContext() + "/" + context, "/toolCategory");
        */
    }

    protected Element createRolesXml(Document doc, String siteId) {
        Element rolesElement = doc.createElement("roles");
        List roles = getPortalManager().getRoles(siteId);
        for (Iterator i = roles.iterator(); i.hasNext();) {
            Role role = (Role) i.next();
            if (role != null) {
                Element roleElement = doc.createElement("role");
                roleElement.setAttribute("id", role.getId());
                rolesElement.appendChild(roleElement);
            }
        }
        return rolesElement;
    }

    protected void doSiteTypeHelper(HttpServletRequest req, HttpServletResponse res, Session session,
            String siteTypeKey, boolean returning) throws ToolException {
        if (session.getUserId() == null) {
            doLogin(req, res, session, req.getPathInfo(), false);
            return;
        }

        SiteType siteType = getPortalManager().getSiteType(siteTypeKey);

        ToolSession toolSession = session.getToolSession(Web.escapeJavascript(siteTypeKey));

        toolSession.setAttribute(PortalManager.RELOAD_SITES, "true");

        if (!returning) {
            toolSession.setAttribute(PortalManager.SITE_TYPE, siteTypeKey);
        }

        // put the session in the request attribute
        req.setAttribute(Tool.TOOL_SESSION, toolSession);

        // set as the current tool session
        SessionManager.setCurrentToolSession(toolSession);

        // put the placement id in the request attribute
        String placementId = Web.escapeJavascript(siteTypeKey);
        req.setAttribute(Tool.PLACEMENT_ID, placementId);

        ActiveTool helperTool = ActiveToolManager.getActiveTool("osp.site.type");
        Placement placement = new org.sakaiproject.util.Placement(placementId, "osp.site.type", helperTool, null,
                null, null);

        String context = req.getPathInfo();
        forwardTool(helperTool, req, res, placement, siteType.getSkin(), getContext() + "/" + context, "/siteType");
    }

    protected void doCategory(HttpServletRequest req, HttpServletResponse res, Session session, String siteId,
            String categoryKey, String pageId) throws IOException, ToolException {
        siteId = checkVisitSite(siteId, session, req, res);
        if (siteId == null) {
            return;
        }
        Document doc = createPortalDocument(session, null, siteId, categoryKey, pageId, req);
        outputDocument(req, res, session, doc);
    }

    protected void doSiteType(HttpServletRequest req, HttpServletResponse res, Session session, String siteTypeKey)
            throws IOException, ToolException {
        if (session.getUserId() == null) {
            doLogin(req, res, session, req.getPathInfo(), false);
            return;
        }
        Document doc = createPortalDocument(session, siteTypeKey, null, null, null, req);
        outputDocument(req, res, session, doc);
    }

    protected void outputDocument(HttpServletRequest req, HttpServletResponse res, Session session, Document doc)
            throws IOException {
        outputDocument(req, res, session, doc, getTransformer());
    }

    protected void outputDocument(HttpServletRequest req, HttpServletResponse res, Session session, Document doc,
            Transformer transformer) throws IOException {

        res.setContentType("text/html; charset=UTF-8");
        res.addDateHeader("Expires", System.currentTimeMillis() - (1000L * 60L * 60L * 24L * 365L));
        res.addDateHeader("Last-Modified", System.currentTimeMillis());
        res.addHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
        res.addHeader("Pragma", "no-cache");

        PrintWriter out = res.getWriter();

        try {
            StreamResult outputTarget = new StreamResult(out);
            transformer.transform(new DOMSource(doc), outputTarget);
        } catch (TransformerException e) {
            throw new RuntimeException(e);
        }
    }

    protected void doSite(HttpServletRequest req, HttpServletResponse res, Session session, String siteId,
            String pageId, String toolContextPath) throws IOException, ToolException {
        siteId = checkVisitSite(siteId, session, req, res);

        if (siteId == null) {
            return;
        }

        Document doc = createPortalDocument(session, null, siteId, null, pageId, req);
        outputDocument(req, res, session, doc);
    }

    protected void doWorksite(HttpServletRequest req, HttpServletResponse res, Session session, String siteId,
            String pageId, String toolContextPath) throws IOException, ToolException {
        siteId = checkVisitSite(siteId, session, req, res);
        if (siteId == null) {
            return;
        }
        Document doc = createPortalDocument(session, null, siteId, null, pageId, req);
        outputDocument(req, res, session, doc);
    }

    protected void doPage(HttpServletRequest req, HttpServletResponse res, Session session, String pageId,
            String toolContextPath) throws IOException, ToolException {
        SitePage page = getPortalManager().getSitePage(pageId);
        if (page == null) {
            doError(req, res, session, ERROR_WORKSITE);
            return;
        }
        String siteId = page.getSiteId();
        siteId = checkVisitSite(siteId, session, req, res);
        if (siteId == null) {
            return;
        }
        Document doc = createPortalDocument(session, null, siteId,
                getPortalManager().getPageCategory(siteId, pageId), pageId, req);
        outputDocument(req, res, session, doc);
    }

    protected void postLogin(HttpServletRequest req, HttpServletResponse res, Session session, String loginPath)
            throws ToolException {
        if (session.getAttribute(Tool.HELPER_DONE_URL) == null) {
            session.setAttribute(Tool.HELPER_DONE_URL, Web.returnUrl(req, null));
        }

        super.postLogin(req, res, session, loginPath);
    }

    protected Document createPortalDocument(Session session, String siteTypeKey, String siteId,
            String toolCategoryKey, String pageId, HttpServletRequest req) throws IOException, ToolException {
        Document doc = getDocumentBuilder().newDocument();

        Element root = doc.createElement("portal");
        doc.appendChild(root);

        User currentUser = getPortalManager().getCurrentUser();
        boolean loggedIn = false;
        if (currentUser != null && currentUser.getId().length() > 0) {
            root.appendChild(createUserXml(doc, currentUser));
            loggedIn = true;
        }

        root.appendChild(createLoginXml(doc, req));

        Map siteTypesMap = getPortalManager().getSitesByType(siteId);
        Site site = null;
        SitePage page = null;

        if (siteId != null) {
            site = getPortalManager().getSite(siteId);
        }

        if (pageId != null) {
            page = getPortalManager().getSitePage(pageId);
        }

        if (siteTypeKey == null) {
            siteTypeKey = getPortalManager().decorateSiteType(site);
        }

        SiteType siteType = findSiteType(siteTypesMap, siteTypeKey);

        root.appendChild(createTitleXml(doc, site, page));

        List skins = getSkins(siteType, site);
        root.appendChild(createSkinsXml(doc, skins));
        root.appendChild(createConfixXml(doc, skins, site, loggedIn));
        root.appendChild(createSiteTypesXml(doc, siteTypesMap, siteTypeKey, siteId));

        if (siteId != null) {
            Map pageCateogries = getPortalManager().getPagesByCategory(siteId);

            checkToolPermissions(pageCateogries);

            if (pageId == null && toolCategoryKey == null) {
                // need to pick first page or category
                ToolCategory category = findFirstCategory(pageCateogries);
                if (category.getKey().equals(ToolCategory.UNCATEGORIZED_KEY)) {
                    List pages = (List) pageCateogries.get(category);
                    pageId = findFirstPage(pages);
                } else {
                    toolCategoryKey = category.getKey();
                }
            }

            root.appendChild(createPageCategoriesXml(doc, pageCateogries, siteId, toolCategoryKey, pageId));
        }

        if (siteId != null) {
            Element rolesElement = createRolesXml(doc, siteId);
            root.appendChild(rolesElement);
        }

        if (!getPortalManager().isDisplaySiteTypes()) {
            try {
                root.appendChild(createSitesTabArea(session, siteId, doc, req));
            } catch (SAXException e) {
                throw new ToolException(e);
            }
        }

        root.appendChild(createExternalizedXml(doc));

        return doc;
    }

    protected void checkToolPermissions(Map pages) {
        List emptyCategories = new ArrayList();
        for (Iterator<ToolCategory> i = pages.entrySet().iterator(); i.hasNext();) {
            Entry entry = (Entry) i.next();
            ToolCategory category = (ToolCategory) entry.getKey();
            List categoryPages = (List) entry.getValue();
            checkPagesAccess(categoryPages);
            if (categoryPages.isEmpty()) {
                emptyCategories.add(category);
            }
        }

        for (Iterator<ToolCategory> i = emptyCategories.iterator(); i.hasNext();) {
            ToolCategory category = i.next();
            pages.remove(category);
        }
    }

    protected void checkPagesAccess(List categoryPages) {
        for (Iterator<SitePageWrapper> i = categoryPages.iterator(); i.hasNext();) {
            SitePageWrapper page = i.next();
            List pageTools = page.getPage().getTools();
            if (!checkToolsAccess(page.getPage().getContainingSite(), pageTools)) {
                i.remove();
            }
        }
    }

    protected boolean checkToolsAccess(Site site, List pageTools) {
        boolean retVal = false;

        for (Iterator<Placement> i = pageTools.iterator(); i.hasNext();) {
            Placement tool = i.next();
            if (allowTool(site, tool)) {
                retVal = true;
            }
        }

        return retVal;
    }

    protected String findFirstPage(List pages) {
        SitePageWrapper first = null;
        for (Iterator i = pages.iterator(); i.hasNext();) {
            SitePageWrapper wrapper = (SitePageWrapper) i.next();
            if (first == null || first.getOrder() > wrapper.getOrder()) {
                first = wrapper;
            }
        }
        return first.getPage().getId();
    }

    protected ToolCategory findFirstCategory(Map pageCateogries) {
        ToolCategory first = null;

        for (Iterator i = pageCateogries.keySet().iterator(); i.hasNext();) {
            ToolCategory category = (ToolCategory) i.next();
            if (first == null || first.getOrder() > category.getOrder()) {
                first = category;
            }
        }

        return first;
    }

    protected SiteType findSiteType(Map siteTypesMap, String siteTypeKey) {
        for (Iterator i = siteTypesMap.keySet().iterator(); i.hasNext();) {
            SiteType siteType = (SiteType) i.next();
            if (siteType.getKey().equals(siteTypeKey)) {
                return siteType;
            }
        }

        return null;
    }

    private Element createSitesTabArea(Session session, String siteId, Document doc, HttpServletRequest req)
            throws IOException, SAXException {
        Element siteTabs = doc.createElement("siteTabs");
        CharArrayWriter writer = new CharArrayWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        printWriter.write("<div id=\"blank\">");
        includeTabs(printWriter, req, session, siteId, "site", false);
        Document tabs = getDocumentBuilder().parse(new InputSource(new CharArrayReader(writer.toCharArray())));
        siteTabs.appendChild(doc.importNode(tabs.getDocumentElement(), true));
        return siteTabs;
    }

    protected Element createExternalizedXml(Document doc) {
        Element externalized = doc.createElement("externalized");

        for (Iterator i = rb.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            externalized.appendChild(createExternalizedEntryXml(doc, entry.getKey(), entry.getValue()));
        }

        for (Iterator i = rbsitenav.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            externalized.appendChild(createExternalizedEntryXml(doc, entry.getKey(), entry.getValue()));
        }

        return externalized;
    }

    protected Element createExternalizedEntryXml(Document doc, Object key, Object value) {
        Element entry = doc.createElement("entry");
        entry.setAttribute("key", (String) key);

        appendTextElementNode(doc, "value", (String) value, entry);

        return entry;
    }

    protected Element createTitleXml(Document doc, Site site, SitePage page) {
        Element titleElement = doc.createElement("pageTitle");
        String title = ServerConfigurationService.getString("ui.service");

        if (site != null) {
            title += ":" + site.getTitle();
        }

        if (page != null) {
            title += ":" + page.getTitle();
        }
        safeAppendTextNode(doc, titleElement, title, true);

        return titleElement;
    }

    protected Element createConfixXml(Document doc, List skins, Site site, boolean loggedIn) {
        Element config = doc.createElement("config");

        String skinRepo = ServerConfigurationService.getString("skin.repo");
        if (skins.size() > 0) {
            skinRepo += "/" + skins.get(skins.size() - 1);
        } else {
            skinRepo += "/" + ServerConfigurationService.getString("skin.default");
        }

        if (site != null) {
            String presenceUrl = getContext() + "/presence/" + site.getId();
            boolean showPresence = ServerConfigurationService.getBoolean("display.users.present", true);
            Element presence = doc.createElement("presence");
            safeAppendTextNode(doc, presence, presenceUrl, true);
            presence.setAttribute("include", Boolean.valueOf(showPresence && loggedIn).toString());
            config.appendChild(presence);
        }

        Element logo = doc.createElement("logo");
        safeAppendTextNode(doc, logo, skinRepo + "/images/logo_inst.gif", true);
        Element banner = doc.createElement("banner");
        safeAppendTextNode(doc, banner, skinRepo + "/images/banner_inst.gif", true);
        Element logout = doc.createElement("logout");
        safeAppendTextNode(doc, logout, getContext() + "/logout", true);

        String copyright = ServerConfigurationService.getString("bottom.copyrighttext");
        String service = ServerConfigurationService.getString("ui.service", "Sakai");
        String serviceVersion = ServerConfigurationService.getString("version.service", "?");
        String sakaiVersion = ServerConfigurationService.getString("version.sakai", "?");
        String server = ServerConfigurationService.getServerId();
        String helpUrl = ServerConfigurationService.getHelpUrl(null);
        String[] bottomNav = ServerConfigurationService.getStrings("bottomnav");
        String[] poweredByUrl = ServerConfigurationService.getStrings("powered.url");
        String[] poweredByImage = ServerConfigurationService.getStrings("powered.img");
        String[] poweredByAltText = ServerConfigurationService.getStrings("powered.alt");

        config.appendChild(logo);
        config.appendChild(banner);
        config.appendChild(logout);

        appendTextElementNode(doc, "copyright", copyright, config);
        appendTextElementNode(doc, "service", service, config);
        appendTextElementNode(doc, "serviceVersion", serviceVersion, config);
        appendTextElementNode(doc, "sakaiVersion", sakaiVersion, config);
        appendTextElementNode(doc, "server", server, config);
        appendTextElementNode(doc, "helpUrl", helpUrl, config);
        appendTextElementNodes(doc, bottomNav, config, "bottomNavs", "bottomNav");

        if ((poweredByUrl != null) && (poweredByImage != null) && (poweredByAltText != null)
                && (poweredByUrl.length == poweredByImage.length)
                && (poweredByUrl.length == poweredByAltText.length)) {
            for (int i = 0; i < poweredByUrl.length; i++) {
                config.appendChild(
                        createPoweredByXml(doc, poweredByAltText[i], poweredByImage[i], poweredByUrl[i]));
            }
        } else {
            config.appendChild(createPoweredByXml(doc, "Powered by Sakai", "/library/image/sakai_powered.gif",
                    "http://sakaiproject.org"));
        }

        appendTextElementNodes(doc, poweredByUrl, config, "poweredByUrls", "poweredByUrl");
        appendTextElementNodes(doc, poweredByImage, config, "poweredByImages", "poweredByImage");
        appendTextElementNodes(doc, poweredByAltText, config, "poweredByAltTexts", "poweredByAltText");

        return config;
    }

    protected Element createPoweredByXml(Document doc, String text, String image, String url) {
        Element poweredBy = doc.createElement("poweredBy");

        appendTextElementNode(doc, "text", text, poweredBy);
        appendTextElementNode(doc, "image", image, poweredBy);
        appendTextElementNode(doc, "url", url, poweredBy);

        return poweredBy;
    }

    protected void appendTextElementNodes(Document doc, String[] strings, Element parent, String topNodeName,
            String nodeName) {
        Element topNode = doc.createElement(topNodeName);

        if (strings == null) {
            return;
        }

        for (int i = 0; i < strings.length; i++) {
            appendTextElementNode(doc, nodeName, strings[i], topNode);
        }

        parent.appendChild(topNode);
    }

    protected void appendTextElementNode(Document doc, String name, String text, Element parent) {
        Element element = doc.createElement(name);
        safeAppendTextNode(doc, element, text, true);
        parent.appendChild(element);
    }

    protected Element createPageCategoriesXml(Document doc, Map pages, String siteId, String toolCategoryKey,
            String pageId) {
        Element pagesElement = doc.createElement("categories");

        for (Iterator i = pages.entrySet().iterator(); i.hasNext();) {
            Entry entry = (Entry) i.next();
            ToolCategory category = (ToolCategory) entry.getKey();
            List categoryPageList = (List) entry.getValue();
            pagesElement.appendChild(
                    createCategoryXml(doc, category, categoryPageList, siteId, toolCategoryKey, pageId));
        }
        return pagesElement;
    }

    protected Element createCategoryXml(Document doc, ToolCategory category, List categoryPageList, String siteId,
            String categoryKey, String pageId) {
        Element categoryElement = doc.createElement("category");
        boolean selected = category.getKey().equals(categoryKey);
        categoryElement.setAttribute("selected", Boolean.valueOf(selected).toString());
        categoryElement.setAttribute("order", Integer.valueOf(category.getOrder()).toString());
        Element categoryKeyElement = doc.createElement("key");
        safeAppendTextNode(doc, categoryKeyElement, category.getKey(), false);
        Element categoryEscapedKeyElement = doc.createElement("escapedKey");
        safeAppendTextNode(doc, categoryEscapedKeyElement, Web.escapeJavascript(category.getKey()), false);
        Element categoryUrlElement = doc.createElement("url");
        // Resolve the site_type of the form /portal/category/<siteId>/<categoryKey>/<optionalToolId>
        safeAppendTextNode(doc, categoryUrlElement,
                getContext() + "/" + TOOL_CATEGORY + "/" + siteId + "/" + category.getKey(), true);
        Element categoryHelperUrlElement = doc.createElement("helperUrl");
        // Resolve the site_type of the form /portal/category_helper/<siteId>/<categoryKey>/<optionalToolId>
        safeAppendTextNode(doc, categoryHelperUrlElement,
                getContext() + "/" + TOOL_CATEGORY_HELPER + "/" + siteId + "/" + category.getKey(), true);

        categoryElement.appendChild(categoryKeyElement);
        categoryElement.appendChild(categoryEscapedKeyElement);
        categoryElement.appendChild(categoryUrlElement);
        categoryElement.appendChild(categoryHelperUrlElement);

        if (portalManager.isUseDb()) {
            appendTextElementNode(doc, "layoutFile", category.getKey(), categoryElement);
        } else {
            appendTextElementNode(doc, "layoutFile", getCategoryHomePagePath(category.getHomePagePath()),
                    categoryElement);
        }

        Element pagesElement = doc.createElement("pages");

        for (Iterator i = categoryPageList.iterator(); i.hasNext();) {
            SitePageWrapper page = (SitePageWrapper) i.next();
            pagesElement.appendChild(
                    createPageXml(doc, page.getOrder(), siteId, page.getPage(), category.getKey(), pageId));
        }

        categoryElement.appendChild(pagesElement);
        return categoryElement;
    }

    /**
     * concatenates categoryBasePath, locale, and homePagePath.  If can't resolve this path the locale
     * portion is removed.
     * @param homePagePath
     * @return localized path
     */
    protected String getCategoryHomePagePath(String homePagePath) {
        ResourceLoader rl = new ResourceLoader();
        String localeStr = rl.getLocale().toString();
        String localizedPath = categoryBasePath + "_" + localeStr + "/" + homePagePath;
        try {
            URL url = getServletContext().getResource(localizedPath);
            if (url != null) {
                return localizedPath;
            }
            // try without the country part
            localizedPath = categoryBasePath + "_" + localeStr.replaceFirst("_.*", "") + "/" + homePagePath;
            url = getServletContext().getResource(localizedPath);
            if (url != null) {
                return localizedPath;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return categoryBasePath + "/" + homePagePath;
    }

    protected Element createPageXml(Document doc, int index, String siteId, SitePage page, String parentCategoryKey,
            String pageId) {
        Element pageElement = doc.createElement("page");
        pageElement.setAttribute("order", Integer.valueOf(index).toString());
        boolean pageSelected = page.getId().equals(pageId);
        pageElement.setAttribute("selected", Boolean.valueOf(pageSelected).toString());
        pageElement.setAttribute("layout", Integer.valueOf(page.getLayout()).toString());
        pageElement.setAttribute("popUp", Boolean.valueOf(page.isPopUp()).toString());
        pageElement.setAttribute("toolId", getFirstToolId(page));
        Element pageName = doc.createElement("title");
        safeAppendTextNode(doc, pageName, page.getTitle(), true);
        // portal/site/9607661f-f3aa-4938-8005-c3ffaa228c6c/page/0307f10c-225b-4db8-803e-b12f24e38544

        Element pageUrl = doc.createElement("url");
        if (parentCategoryKey != null && !parentCategoryKey.equals(ToolCategory.UNCATEGORIZED_KEY)) {
            safeAppendTextNode(doc, pageUrl,
                    getContext() + "/category/" + siteId + "/" + parentCategoryKey + "/" + page.getId(), true);
        } else {
            safeAppendTextNode(doc, pageUrl, getContext() + "/site/" + siteId + "/page/" + page.getId(), true);
        }

        Element popPageUrl = doc.createElement("popUrl");
        safeAppendTextNode(doc, popPageUrl, getContext() + "/page/" + page.getId(), true);

        Element columns = doc.createElement("columns");

        for (int i = 0; i < 2; i++) {
            Element column = doc.createElement("column");
            column.setAttribute("index", Integer.valueOf(i).toString());
            column.appendChild(createColumnToolsXml(doc, page.getTools(i), page));
            columns.appendChild(column);
        }

        pageElement.appendChild(pageName);
        pageElement.appendChild(pageUrl);
        pageElement.appendChild(popPageUrl);
        pageElement.appendChild(columns);

        return pageElement;
    }

    protected String getFirstToolId(SitePage page) {
        List tools = page.getTools();

        if (tools.size() > 0) {
            Placement placement = (Placement) tools.get(0);
            if (placement.getTool() != null)
                return placement.getTool().getId();
        }

        return "";
    }

    protected Element createColumnToolsXml(Document doc, List tools, SitePage page) {
        Element toolsElement = doc.createElement("tools");

        for (Iterator i = tools.iterator(); i.hasNext();) {
            Placement placement = (Placement) i.next();
            if (placement.getTool() != null)
                toolsElement.appendChild(createToolXml(doc, placement, page));
        }

        return toolsElement;
    }

    protected Element createToolXml(Document doc, Placement placement, SitePage page) {
        Element toolElement = doc.createElement("tool");

        Element title = doc.createElement("title");
        safeAppendTextNode(doc, title, page.getTitle(), true);

        Element escapedId = doc.createElement("escapedId");
        String id = Web.escapeJavascript("i" + placement.getId());

        id = id.substring(1);

        safeAppendTextNode(doc, escapedId, id, true);

        //portal/tool/ad222467-e186-4cca-80e9-d12a9d6db392?panel=Main
        Element toolUrl = doc.createElement("url");
        safeAppendTextNode(doc, toolUrl, getContext() + "/tool/" + placement.getId() + "?panel=Main", true);

        //portal/title/ad222467-e186-4cca-80e9-d12a9d6db392
        Element toolTitleUrl = doc.createElement("titleUrl");
        safeAppendTextNode(doc, toolTitleUrl, getContext() + "/title/" + placement.getId(), true);

        toolElement.appendChild(title);
        toolElement.appendChild(escapedId);
        toolElement.appendChild(toolUrl);
        toolElement.appendChild(toolTitleUrl);

        return toolElement;
    }

    protected Element createSiteTypesXml(Document doc, Map siteTypesMap, String siteTypeKey, String siteId) {
        Element siteTypes = doc.createElement("siteTypes");
        List types = new ArrayList(siteTypesMap.keySet());
        Collections.sort(types);

        for (Iterator i = types.iterator(); i.hasNext();) {
            SiteType type = (SiteType) i.next();
            boolean selected = type.getKey().equals(siteTypeKey);
            siteTypes.appendChild(createSiteTypeXml(doc, type, (List) siteTypesMap.get(type), selected, siteId));
        }

        return siteTypes;
    }

    protected Element createSiteTypeXml(Document doc, SiteType type, List sites, boolean selected, String siteId) {
        Element siteTypeElement = doc.createElement("siteType");
        siteTypeElement.setAttribute("selected", Boolean.valueOf(selected).toString());
        siteTypeElement.setAttribute("order", Integer.valueOf(type.getOrder()).toString());
        siteTypeElement.setAttribute("userSite", Boolean.valueOf(type == SiteType.MY_WORKSPACE).toString());
        Element siteTypeKey = doc.createElement("key");
        safeAppendTextNode(doc, siteTypeKey, type.getKey(), false);
        siteTypeElement.appendChild(siteTypeKey);

        Element siteTypeName = doc.createElement("name");
        safeAppendTextNode(doc, siteTypeName, type.getName(), false);
        siteTypeElement.appendChild(siteTypeName);

        Element siteTypeEscapedKey = doc.createElement("escapedKey");
        safeAppendTextNode(doc, siteTypeEscapedKey, Web.escapeJavascript(type.getKey()), false);
        siteTypeElement.appendChild(siteTypeEscapedKey);

        Element siteTypeUrl = doc.createElement("url");
        // /portal/site_type/<key>

        try {
            Site site = getPortalManager().getSite(type.getKey());
            safeAppendTextNode(doc, siteTypeUrl, getContext() + "/site/" + type.getKey(), true);
        } catch (RuntimeException e) {
            safeAppendTextNode(doc, siteTypeUrl, getContext() + "/" + SITE_TYPE + "/" + type.getKey(), true);
        }
        siteTypeElement.appendChild(siteTypeUrl);

        Element siteTypeHelperUrl = doc.createElement("helperUrl");
        // /portal/site_type_helper/<key>
        safeAppendTextNode(doc, siteTypeHelperUrl, getContext() + "/" + SITE_TYPE_HELPER + "/" + type.getKey(),
                true);
        siteTypeElement.appendChild(siteTypeHelperUrl);

        siteTypeElement.appendChild(createSitesListXml(doc, sites, siteId));
        return siteTypeElement;
    }

    protected void safeAppendTextNode(Document doc, Element element, String text, boolean cdata) {
        if (text != null) {
            element.appendChild(cdata ? doc.createCDATASection(text) : doc.createTextNode(text));
        }
    }

    protected Element createSitesListXml(Document doc, List mySites, String siteId) {
        Session session = SessionManager.getCurrentSession();

        int prefTabs = 4;
        List prefExclude = new Vector();
        List prefOrder = new Vector();
        if (session.getUserId() != null) {
            Preferences prefs = PreferencesService.getPreferences(session.getUserId());
            ResourceProperties props = prefs.getProperties("sakai.portal.sitenav");
            try {
                prefTabs = (int) props.getLongProperty("tabs");
            } catch (Exception any) {
            }

            List l = props.getPropertyList("exclude");
            if (l != null) {
                prefExclude = l;
            }

            l = props.getPropertyList("order");
            if (l != null) {
                prefOrder = l;
            }
        }

        mySites.removeAll(prefExclude);
        // re-order mySites to have order first, the rest later
        List ordered = new Vector();
        for (Iterator i = prefOrder.iterator(); i.hasNext();) {
            String id = (String) i.next();

            // find this site in the mySites list
            int pos = indexOf(id, mySites);
            if (pos != -1) {
                // move it from mySites to order
                Site s = (Site) mySites.get(pos);
                ordered.add(s);
                mySites.remove(pos);
            }
        }

        // pick up the rest of the mySites
        ordered.addAll(mySites);
        mySites = ordered;

        Element sitesElement = doc.createElement("sites");
        int order = 0;
        for (Iterator i = mySites.iterator(); i.hasNext();) {
            Site site = (Site) i.next();
            boolean selected = siteId != null ? site.getId().equals(siteId) : false;
            sitesElement.appendChild(createSiteXml(doc, site, selected, order, false));
            order++;
        }
        return sitesElement;
    }

    protected Element createSiteXml(Document doc, Site site, boolean selected, int order, boolean extra) {
        Element siteElement = doc.createElement("site");
        siteElement.setAttribute("selected", Boolean.valueOf(selected).toString());
        siteElement.setAttribute("extra", Boolean.valueOf(extra).toString());
        siteElement.setAttribute("published", Boolean.valueOf(site.isPublished()).toString());
        siteElement.setAttribute("order", Integer.valueOf(order).toString());

        Element siteUrl = doc.createElement("url");
        // http://localhost:8080/portal/site/bc5b1aa2-c53b-4fd1-0017-f91eef511e65<key>
        safeAppendTextNode(doc, siteUrl, getContext() + "/site/" + site.getId(), true);
        siteElement.appendChild(siteUrl);

        Element siteTitle = doc.createElement("title");
        safeAppendTextNode(doc, siteTitle, site.getTitle(), true);
        siteElement.appendChild(siteTitle);

        Element siteDescription = doc.createElement("description");
        safeAppendTextNode(doc, siteDescription, site.getDescription(), true);
        siteElement.appendChild(siteDescription);

        return siteElement;
    }

    protected Element createSkinsXml(Document doc, List skins) {
        Element skinsElement = doc.createElement("skins");
        int index = 0;

        String skinRepo = ServerConfigurationService.getString("skin.repo");

        Element skin = doc.createElement("skin");
        skin.setAttribute("order", index + "");
        safeAppendTextNode(doc, skin, getContext() + "/library/css/osp-portal.css", true);
        skinsElement.appendChild(skin);
        index++;

        for (Iterator i = skins.iterator(); i.hasNext();) {
            String skinUrl = (String) i.next();
            index = appendSkin(skinRepo, skinUrl, doc, index, skinsElement, "/portal.css");
        }

        if (index == 1) {
            String skinUrl = ServerConfigurationService.getString("skin.default");
            index = appendSkin(skinRepo, skinUrl, doc, index, skinsElement, "/portal.css");
        }

        return skinsElement;
    }

    protected Element createToolSkinsXml(Document doc, List skins) {
        Element skinsElement = doc.createElement("toolSkins");
        int index = 0;

        String skinRepo = ServerConfigurationService.getString("skin.repo");

        Element skin = doc.createElement("skin");
        skin = doc.createElement("skin");
        skin.setAttribute("order", index + "");
        safeAppendTextNode(doc, skin, getContext() + "/library/skin/tool_base.css", true);
        skinsElement.appendChild(skin);
        index++;

        for (Iterator i = skins.iterator(); i.hasNext();) {
            String skinUrl = (String) i.next();
            index = appendSkin(skinRepo, skinUrl, doc, index, skinsElement, "/tool.css");
        }

        if (index == 2) {
            String skinUrl = ServerConfigurationService.getString("skin.default");
            index = appendSkin(skinRepo, skinUrl, doc, index, skinsElement, "/tool.css");
        }

        return skinsElement;
    }

    protected int appendSkin(String skinRepo, String skinUrl, Document doc, int index, Element skinsElement,
            String cssFile) {
        Element skin;
        String skinPortalUrl = skinRepo + "/" + skinUrl + cssFile;
        skin = doc.createElement("skin");
        skin.setAttribute("order", index + "");
        safeAppendTextNode(doc, skin, skinPortalUrl, true);
        skinsElement.appendChild(skin);
        index++;
        return index;
    }

    protected List getSkins(SiteType siteType, Site site) {
        List skins = new ArrayList();

        if (siteType != null && siteType.getSkin() != null) {
            skins.add(siteType.getSkin());
        }

        if (site != null && site.getSkin() != null) {
            skins.add(site.getSkin());
        }

        return skins;
    }

    protected Element createUserXml(Document doc, User current) {
        Element user = doc.createElement("currentUser");

        appendTextElementNode(doc, "id", current.getId(), user);
        appendTextElementNode(doc, "first", current.getFirstName(), user);
        appendTextElementNode(doc, "last", current.getLastName(), user);
        appendTextElementNode(doc, "email", current.getEmail(), user);

        return user;
    }

    protected Element createLoginXml(Document doc, HttpServletRequest req) {
        Element login = doc.createElement("loginInfo");

        String logInOutUrl = Web.serverUrl(req);
        String loginText = null;
        String logoutText = null;
        String image1 = null;

        // for a possible second link
        String logInOutUrl2 = null;
        String loginText2 = null;
        String image2 = null;

        boolean topLogin = ServerConfigurationService.getBoolean("top.login", true);
        boolean containerLogin = ServerConfigurationService.getBoolean("container.login", false);
        if (containerLogin)
            topLogin = false;

        if (!topLogin) {
            logInOutUrl += getPortalString() + "/login";

            // let the login url be overridden by configuration
            String overrideLoginUrl = StringUtils.trimToNull(ServerConfigurationService.getString("login.url"));
            if (overrideLoginUrl != null)
                logInOutUrl = overrideLoginUrl;

            // check for a login text override
            loginText = StringUtils.trimToNull(ServerConfigurationService.getString("login.text"));
            if (loginText == null)
                loginText = rbsitenav.getString("log.login");

            // check for an image for the login
            image1 = StringUtils.trimToNull(ServerConfigurationService.getString("login.icon"));

            //    check for a possible second, xlogin link
            if (Boolean.TRUE.toString().equalsIgnoreCase(ServerConfigurationService.getString("xlogin.enabled"))) {
                // get the text and image as configured
                loginText2 = StringUtils.trimToNull(ServerConfigurationService.getString("xlogin.text"));
                image2 = StringUtils.trimToNull(ServerConfigurationService.getString("xlogin.icon"));
                logInOutUrl2 = ServerConfigurationService.getString("portalPath") + "/xlogin";

                appendTextElementNode(doc, "logInOutUrl2", logInOutUrl2, login);
                appendTextElementNode(doc, "loginText2", loginText2, login);
                appendTextElementNode(doc, "image2", image2, login);
            }
        }

        // check for a logout text override
        logoutText = StringUtils.trimToNull(ServerConfigurationService.getString("logout.text"));
        if (logoutText == null)
            logoutText = rbsitenav.getString("sit_log");

        appendTextElementNode(doc, "topLogin", Boolean.toString(topLogin), login);
        appendTextElementNode(doc, "logInOutUrl", logInOutUrl, login);
        appendTextElementNode(doc, "loginText", loginText, login);
        appendTextElementNode(doc, "logoutText", logoutText, login);
        appendTextElementNode(doc, "image1", image1, login);

        return login;
    }

    protected String checkVisitSite(String siteId, Session session, HttpServletRequest req, HttpServletResponse res)
            throws IOException, ToolException {
        // default site if not set
        if (siteId == null) {
            if (session.getUserId() == null) {
                siteId = ServerConfigurationService.getGatewaySiteId();
            } else {
                siteId = SiteService.getUserSiteId(session.getUserId());
            }
        }

        // find the site, for visiting
        Site site = null;
        try {
            site = getSiteVisit(siteId);
        } catch (IdUnusedException e) {
            doError(req, res, session, ERROR_SITE);
            return null;
        } catch (PermissionException e) {
            // if not logged in, give them a chance
            if (session.getUserId() == null) {
                doLogin(req, res, session, req.getPathInfo(), false);
            } else {
                doError(req, res, session, ERROR_SITE);
            }
            return null;
        }

        return site.getId();
    }

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        setPortalManager((PortalManager) ComponentManager.get(PortalManager.class.getName() + ".tx"));
        try {
            setDocumentBuilder(DocumentBuilderFactory.newInstance().newDocumentBuilder());
            String transformPath = config.getInitParameter("transform");
            Templates templates = createTemplate(config, transformPath);
            setTemplates(templates);

            String transformToolCategoryPath = config.getInitParameter("transformToolCategory");
            Templates templatesToolCategory = createTemplate(config, transformToolCategoryPath);
            setServletResolver(new PortalResourceUriResolver(getPortalManager(), config.getServletContext()));
            setToolCategoryTemplates(templatesToolCategory);

            categoryBasePath = config.getInitParameter("categoryBasePath");
            if (categoryBasePath == null || categoryBasePath.length() == 0) {
                categoryBasePath = "/WEB-INF/category";
            }

            Collection categoriesNeedingLoading = getPortalManager().getCategoriesInNeedOfFiles();

            if (categoriesNeedingLoading != null) {
                for (Iterator<ToolCategory> i = categoriesNeedingLoading.iterator(); i.hasNext();) {
                    processCategoryFiles(i.next(), config.getServletContext());
                }

                getPortalManager().saveToolCategories(categoriesNeedingLoading);
            }
        } catch (ParserConfigurationException e) {
            throw new ServletException(e);
        } catch (TransformerConfigurationException e) {
            throw new ServletException(e);
        } catch (MalformedURLException e) {
            throw new ServletException(e);
        } catch (IOException e) {
            throw new ServletException(e);
        }
    }

    protected void processCategoryFiles(ToolCategory toolCategory, ServletContext context) throws IOException {
        File base = new File(categoryBasePath);
        String parentPath = base.getParent();

        Set paths = context.getResourcePaths(parentPath);

        for (Iterator<String> i = paths.iterator(); i.hasNext();) {
            String path = i.next();
            if (path.startsWith(categoryBasePath)) {
                path += toolCategory.getHomePagePath();
                if (context.getResource(path) != null) {
                    processCategoryFile(toolCategory, path, context.getResourceAsStream(path));
                }
            }
        }
    }

    protected void processCategoryFile(ToolCategory toolCategory, String path, InputStream is) throws IOException {
        String locale = path.substring(categoryBasePath.length());
        locale = locale.substring(0, locale.length() - toolCategory.getHomePagePath().length() - 1);

        if (locale.startsWith("_")) {
            locale = locale.substring(1);
        }

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int c = is.read();
        while (c != -1) {
            bos.write(c);
            c = is.read();
        }
        bos.flush();
        toolCategory.getPages().put(locale, bos.toByteArray());
    }

    private Templates createTemplate(ServletConfig config, String transformPath)
            throws MalformedURLException, TransformerConfigurationException {
        InputStream stream = config.getServletContext().getResourceAsStream(transformPath);
        URL url = config.getServletContext().getResource(transformPath);
        String urlPath = url.toString();
        String systemId = urlPath.substring(0, urlPath.lastIndexOf('/') + 1);
        Templates templates = TransformerFactory.newInstance().newTemplates(new StreamSource(stream, systemId));
        return templates;
    }

    public PortalManager getPortalManager() {
        return portalManager;
    }

    public void setPortalManager(PortalManager portalManager) {
        this.portalManager = portalManager;
    }

    protected String getContext() {
        return "/" + this.getServletContext().getServletContextName();
    }

    public DocumentBuilder getDocumentBuilder() {
        return documentBuilder;
    }

    public void setDocumentBuilder(DocumentBuilder documentBuilder) {
        this.documentBuilder = documentBuilder;
    }

    protected Transformer getToolCategoryTransformer() {
        try {
            Transformer trans = getToolCategoryTemplates().newTransformer();
            trans.setURIResolver(getServletResolver());
            return trans;
        } catch (TransformerConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    public Transformer getTransformer() {
        try {
            Transformer trans = getTemplates().newTransformer();
            trans.setURIResolver(getServletResolver());
            return trans;
        } catch (TransformerConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    public Templates getTemplates() {
        return templates;
    }

    public void setTemplates(Templates templates) {
        this.templates = templates;
    }

    public Templates getToolCategoryTemplates() {
        return toolCategoryTemplates;
    }

    public void setToolCategoryTemplates(Templates toolCategoryTemplates) {
        this.toolCategoryTemplates = toolCategoryTemplates;
    }

    public URIResolver getServletResolver() {
        return servletResolver;
    }

    public void setServletResolver(URIResolver servletResolver) {
        this.servletResolver = servletResolver;
    }

    protected void dumpDocument(Node node) {
        try {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(new DOMSource(node), new StreamResult(System.out));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}