com.celements.web.plugin.CelementsWebPlugin.java Source code

Java tutorial

Introduction

Here is the source code for com.celements.web.plugin.CelementsWebPlugin.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.celements.web.plugin;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;

import com.celements.navigation.cmd.GetMappedMenuItemsForParentCommand;
import com.celements.pagetype.IPageType;
import com.celements.rendering.RenderCommand;
import com.celements.web.plugin.api.CelementsWebPluginApi;
import com.celements.web.plugin.cmd.AddTranslationCommand;
import com.celements.web.plugin.cmd.CelSendMail;
import com.celements.web.plugin.cmd.CheckClassesCommand;
import com.celements.web.plugin.cmd.PasswordRecoveryAndEmailValidationCommand;
import com.celements.web.plugin.cmd.TokenBasedUploadCommand;
import com.celements.web.plugin.cmd.UserNameForUserDataCommand;
import com.celements.web.service.IPrepareVelocityContext;
import com.celements.web.service.IWebUtilsService;
import com.celements.web.token.NewCelementsTokenForUserCommand;
import com.celements.web.utils.IWebUtils;
import com.celements.web.utils.WebUtils;
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Api;
import com.xpn.xwiki.api.Attachment;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.doc.XWikiAttachment;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.classes.PasswordClass;
import com.xpn.xwiki.plugin.XWikiDefaultPlugin;
import com.xpn.xwiki.plugin.XWikiPluginInterface;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiResponse;

public class CelementsWebPlugin extends XWikiDefaultPlugin {

    private static Log LOGGER = LogFactory.getFactory().getInstance(CelementsWebPlugin.class);

    private final static IWebUtils util = WebUtils.getInstance();

    final String PARAM_XPAGE = "xpage";
    final String PARAM_CONF = "conf";
    final String PARAM_AJAX_MODE = "ajax_mode";
    final String PARAM_SKIN = "skin";
    final String PARAM_LANGUAGE = "language";
    final String PARAM_XREDIRECT = "xredirect";

    private List<String> supportedAdminLangList;

    private CelSendMail injectedCelSendMail;

    public CelementsWebPlugin(String name, String className, XWikiContext context) {
        super(name, className, context);
    }

    public Api getPluginApi(XWikiPluginInterface plugin, XWikiContext context) {
        return new CelementsWebPluginApi((CelementsWebPlugin) plugin, context);
    }

    public String getName() {
        return getPrepareVelocityContextService().getVelocityName();
    }

    public void flushCache() {
        //TODO: check if flushCache is called for changing a page MenuItem.
        LOGGER.debug("Entered method flushCache");
    }

    public void flushCache(XWikiContext context) {
        util.flushMenuItemCache(context);
    }

    public void init(XWikiContext context) {
        LOGGER.trace("init called database [" + context.getDatabase() + "]");
        new CheckClassesCommand().checkClasses(context);
        super.init(context);
    }

    public void virtualInit(XWikiContext context) {
        LOGGER.trace("virtualInit called database [" + context.getDatabase() + "]");
        new CheckClassesCommand().checkClasses(context);
        super.virtualInit(context);
    }

    public int queryCount() {
        return util.queryCount();
    }

    /**
     * getSubMenuItemsForParent
     * get all submenu items of given parent document (by fullname).
     * 
     * @param parent
     * @param menuSpace (default: $doc.space)
     * @param menuPart 
     * @return (array of menuitems)
     */
    public List<com.xpn.xwiki.api.Object> getSubMenuItemsForParent(String parent, String menuSpace, String menuPart,
            XWikiContext context) {
        return util.getSubMenuItemsForParent(parent, menuSpace, menuPart, context);
    }

    public String getVersionMode(XWikiContext context) {
        String versionMode = context.getWiki().getSpacePreference("celements_version", context);
        if ("---".equals(versionMode)) {
            versionMode = context.getWiki().getXWikiPreference("celements_version", "celements2", context);
            if ("---".equals(versionMode)) {
                versionMode = "celements2";
            }
        }
        return versionMode;
    }

    /**
     * getUsernameForUserData
     * 
     * @param login
     * @param possibleLogins
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.14.0 use UserNameForUserDataCommand instead
     */
    @Deprecated
    public String getUsernameForUserData(String login, String possibleLogins, XWikiContext context)
            throws XWikiException {
        return new UserNameForUserDataCommand().getUsernameForUserData(login, possibleLogins, context);
    }

    /**
     * 
     * @param userToken
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.14.0 use TokenLDAPAuthServiceImpl instead
     */
    @Deprecated
    public String getUsernameForToken(String userToken, XWikiContext context) throws XWikiException {

        String hashedCode = encryptString("hash:SHA-512:", userToken);
        String userDoc = "";

        if ((userToken != null) && (userToken.trim().length() > 0)) {

            String hql = ", BaseObject as obj, Classes.TokenClass as token where ";
            hql += "doc.space='XWiki' ";
            hql += "and obj.name=doc.fullName ";
            hql += "and token.tokenvalue=? ";
            hql += "and token.validuntil>=? ";
            hql += "and obj.id=token.id ";

            List<Object> parameterList = new Vector<Object>();
            parameterList.add(hashedCode);
            parameterList.add(new Date());

            XWikiStoreInterface storage = context.getWiki().getStore();
            List<String> users = storage.searchDocumentsNames(hql, 0, 0, parameterList, context);
            LOGGER.info("searching token and found " + users.size() + " with parameters "
                    + Arrays.deepToString(parameterList.toArray()));
            if (users == null || users.size() == 0) {
                String db = context.getDatabase();
                context.setDatabase("xwiki");
                users = storage.searchDocumentsNames(hql, 0, 0, parameterList, context);
                if (users != null && users.size() == 1) {
                    users.add("xwiki:" + users.remove(0));
                }
                context.setDatabase(db);
            }
            int usersFound = 0;
            for (String tmpUserDoc : users) {
                if (!tmpUserDoc.trim().equals("")) {
                    usersFound++;
                    userDoc = tmpUserDoc;
                }
            }
            if (usersFound > 1) {
                LOGGER.warn("Found more than one user for token '" + userToken + "'");
                return null;
            }
        } else {
            LOGGER.warn("No valid token given");
        }
        return userDoc;
    }

    /**
     * @deprecated since 2.22.0
     * instead use NewCelementsTokenForUserCommand.getNewCelementsTokenForUserWithAutentication
     */
    @Deprecated
    public String getNewCelementsTokenForUser(String accountName, Boolean guestPlus, XWikiContext context)
            throws XWikiException {
        return new NewCelementsTokenForUserCommand().getNewCelementsTokenForUserWithAuthentication(accountName,
                guestPlus, context);
    }

    public String encryptString(String encoding, String str) {
        return new PasswordClass().getEquivalentPassword(encoding, str);
    }

    public Map<String, String> activateAccount(String activationCode, XWikiContext context) throws XWikiException {
        Map<String, String> userAccount = new HashMap<String, String>();
        String hashedCode = encryptString("hash:SHA-512:", activationCode);
        String username = new UserNameForUserDataCommand().getUsernameForUserData(hashedCode, "validkey", context);

        if ((username != null) && !username.equals("")) {
            String password = context.getWiki().generateRandomString(24);
            XWikiDocument doc = context.getWiki().getDocument(username, context);
            BaseObject obj = doc.getObject("XWiki.XWikiUsers");

            //      obj.set("validkey", "", context);
            obj.set("active", "1", context);
            obj.set("force_pwd_change", "1", context);
            obj.set("password", password, context);

            context.getWiki().saveDocument(doc, context);

            userAccount.put("username", username);
            userAccount.put("password", password);
        }

        return userAccount;
    }

    public String getEmailAdressForUser(String username, XWikiContext context) {
        if (context.getWiki().exists(username, context)) {
            try {
                XWikiDocument doc = context.getWiki().getDocument(username, context);
                BaseObject obj = doc.getObject("XWiki.XWikiUsers");
                return obj.getStringValue("email");
            } catch (XWikiException e) {
                LOGGER.error(e);
            }
        }
        return null;
    }

    //TODO Delegation can be removed as soon as latin1 flag can be removed
    /**
     * @deprecated since 2.19.0 instead use CelSendMail class directly.
     */
    @Deprecated
    public int sendMail(String from, String replyTo, String to, String cc, String bcc, String subject,
            String htmlContent, String textContent, List<Attachment> attachments, Map<String, String> others,
            XWikiContext context) {
        return sendMail(from, replyTo, to, cc, bcc, subject, htmlContent, textContent, attachments, others, false,
                context);
    }

    /**
     * @deprecated since 2.19.0 instead use CelSendMail class directly.
     */
    @Deprecated
    public int sendMail(String from, String replyTo, String to, String cc, String bcc, String subject,
            String htmlContent, String textContent, List<Attachment> attachments, Map<String, String> others,
            boolean isLatin1, XWikiContext context) {
        CelSendMail sender = getCelSendMail(context);
        sender.setFrom(from);
        sender.setReplyTo(replyTo);
        sender.setTo(to);
        sender.setCc(cc);
        sender.setBcc(bcc);
        sender.setSubject(subject);
        sender.setHtmlContent(htmlContent, isLatin1);
        sender.setTextContent(textContent);
        sender.setAttachments(attachments);
        sender.setOthers(others);
        return sender.sendMail();
    }

    void injectCelSendMail(CelSendMail celSendMail) {
        this.injectedCelSendMail = celSendMail;
    }

    CelSendMail getCelSendMail(XWikiContext context) {
        if (injectedCelSendMail != null) {
            return injectedCelSendMail;
        }
        return new CelSendMail(context);
    }

    public List<Attachment> getAttachmentsForDocs(List<String> docsFN, XWikiContext context) {
        List<Attachment> attachments = new ArrayList<Attachment>();
        for (String docFN : docsFN) {
            try {
                LOGGER.info("getAttachmentsForDocs: processing doc " + docFN);
                for (XWikiAttachment xwikiAttachment : context.getWiki().getDocument(docFN, context)
                        .getAttachmentList()) {
                    LOGGER.info("getAttachmentsForDocs: adding attachment " + xwikiAttachment.getFilename()
                            + " to list.");
                    attachments
                            .add(new Attachment(context.getWiki().getDocument(docFN, context).newDocument(context),
                                    xwikiAttachment, context));
                }
            } catch (XWikiException e) {
                LOGGER.error(e);
            }
        }
        return attachments;
    }

    /**
     * @deprecated since 2.11.7 instead use renderCelementsDocument
     *             on celementsweb scriptService
     */
    @Deprecated
    public String renderCelementsPageType(XWikiDocument doc, IPageType pageType, XWikiContext context)
            throws XWikiException {
        XWikiDocument viewTemplate = context.getWiki().getDocument(pageType.getRenderTemplate("view"), context);
        return context.getWiki().getRenderingEngine().renderDocument(viewTemplate, doc, context);
    }

    public BaseObject getSkinConfigObj(XWikiContext context) {
        XWikiDocument doc = context.getDoc();
        try {
            XWiki xwiki = context.getWiki();
            XWikiDocument skinDoc = xwiki.getDocument(xwiki.getSpacePreference("skin", context), context);
            String className = skinDoc.getObject("XWiki.XWikiSkins").getStringValue("skin_config_class_name");
            BaseObject configObj = util.getConfigDocByInheritance(doc, className, context).getObject(className);
            return configObj;
        } catch (XWikiException e) {
            LOGGER.error(e);
        }
        return null;
    }

    @Override
    public void beginRendering(XWikiContext context) {
        LOGGER.debug("start beginRendering: language [" + context.getLanguage() + "].");
        try {
            getPrepareVelocityContextService().prepareVelocityContext(context);
        } catch (RuntimeException exp) {
            LOGGER.error("beginRendering", exp);
            throw exp;
        }
        LOGGER.debug("end beginRendering: language [" + context.getLanguage() + "].");
    }

    @Override
    public void beginParsing(XWikiContext context) {
        LOGGER.debug("start beginParsing: language [" + context.getLanguage() + "].");
        try {
            getPrepareVelocityContextService().prepareVelocityContext(context);
        } catch (RuntimeException exp) {
            LOGGER.error("beginParsing", exp);
            throw exp;
        }
        LOGGER.debug("end beginParsing: language [" + context.getLanguage() + "].");
    }

    IPrepareVelocityContext getPrepareVelocityContextService() {
        return Utils.getComponent(IPrepareVelocityContext.class);
    }

    @SuppressWarnings("unchecked")
    public Map<String, String> getUniqueNameValueRequestMap(XWikiContext context) {
        Map<String, String[]> params = context.getRequest().getParameterMap();
        Map<String, String> resultMap = new HashMap<String, String>();
        for (String key : params.keySet()) {
            if ((params.get(key) != null) && (params.get(key).length > 0)) {
                resultMap.put(key, params.get(key)[0]);
            } else {
                resultMap.put(key, "");
            }
        }
        return resultMap;
    }

    public int createUser(boolean validate, XWikiContext context) throws XWikiException {
        String possibleLogins = getPossibleLogins(context);
        return createUser(getUniqueNameValueRequestMap(context), possibleLogins, validate, context);
    }

    public String getPossibleLogins(XWikiContext context) {
        String possibleLogins = context.getWiki().getXWikiPreference("cellogin", context);
        if ((possibleLogins == null) || "".equals(possibleLogins.trim())) {
            String db = context.getDatabase();
            context.setDatabase("celements2web");
            possibleLogins = context.getWiki().getXWikiPreference("cellogin", context);
            context.setDatabase(db);
            if ((possibleLogins == null) || "".equals(possibleLogins)) {
                possibleLogins = "loginname";
            }
        }
        return possibleLogins;
    }

    @SuppressWarnings("deprecation")
    public synchronized int createUser(Map<String, String> userData, String possibleLogins, boolean validate,
            XWikiContext context) throws XWikiException {
        String accountName = "";
        if (userData.containsKey("xwikiname")) {
            accountName = userData.get("xwikiname");
            userData.remove("xwikiname");
        } else {
            while (accountName.equals("") || context.getWiki().exists("XWiki." + accountName, context)) {
                accountName = context.getWiki().generateRandomString(12);
            }
        }
        String validkey = "";
        int success = -1;
        if (areIdentifiersUnique(userData, possibleLogins, context)) {
            if (!userData.containsKey("password")) {
                String password = context.getWiki().generateRandomString(8);
                userData.put("password", password);
            }
            if (!userData.containsKey("validkey")) {
                validkey = getUniqueValidationKey(context);
                userData.put("validkey", validkey);
            } else {
                validkey = userData.get("validkey");
            }
            if (!userData.containsKey("active")) {
                userData.put("active", "0");
            }
            String content = "#includeForm(\"XWiki.XWikiUserSheet\")";

            //TODO as soon as all installations are on xwiki 1.8+ change to new method (using
            //     XWikiDocument.XWIKI10_SYNTAXID as additional parameter
            success = context.getWiki().createUser(accountName, userData, "XWiki.XWikiUsers", content, "edit",
                    context);
        }

        if (success == 1) {
            // Set rights on user doc
            XWikiDocument doc = context.getWiki().getDocument("XWiki." + accountName, context);
            List<BaseObject> rightsObjs = doc.getObjects("XWiki.XWikiRights");
            for (BaseObject rightObj : rightsObjs) {
                if (rightObj.getStringValue("groups").equals("")) {
                    rightObj.set("users", doc.getFullName(), context);
                    rightObj.set("allow", "1", context);
                    rightObj.set("levels", "view,edit,delete", context);
                    rightObj.set("groups", "", context);
                } else {
                    rightObj.set("users", "", context);
                    rightObj.set("allow", "1", context);
                    rightObj.set("levels", "view,edit,delete", context);
                    rightObj.set("groups", "XWiki.XWikiAdminGroup", context);
                }
            }
            context.getWiki().saveDocument(doc, context);

            if (validate) {
                LOGGER.info("send account validation mail with data: accountname='" + accountName + "', email='"
                        + userData.get("email") + "', validkey='" + validkey + "'");
                try {
                    new PasswordRecoveryAndEmailValidationCommand().sendValidationMessage(userData.get("email"),
                            validkey, "Tools.AccountActivationMail", context);
                } catch (XWikiException e) {
                    LOGGER.error("Exception while sending validation mail to '" + userData.get("email") + "'", e);
                }
            }
        }
        return success;
    }

    private boolean areIdentifiersUnique(Map<String, String> userData, String possibleLogins, XWikiContext context)
            throws XWikiException {
        boolean isUnique = true;
        for (String key : userData.keySet()) {
            if (!"".equals(key.trim()) && (("," + possibleLogins + ",").indexOf("," + key + ",") >= 0)) {
                String user = getUsernameForUserData(userData.get(key), possibleLogins, context);
                if ((user == null) || (user.length() > 0)) { //user == "" means there is no such user
                    isUnique = false;
                }
            }
        }
        return isUnique;
    }

    /**
     * getUniqueValidationKey
     * 
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.14.0 use NewCelementsTokenForUserCommand instead
     */
    @Deprecated
    public String getUniqueValidationKey(XWikiContext context) throws XWikiException {
        return new NewCelementsTokenForUserCommand().getUniqueValidationKey(context);
    }

    /**
     * 
     * @param attachToDoc
     * @param fieldName
     * @param userToken
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.28.0 use TokenBasedUploadCommand instead
     */
    @Deprecated
    public int tokenBasedUpload(Document attachToDoc, String fieldName, String userToken, XWikiContext context)
            throws XWikiException {
        return new TokenBasedUploadCommand().tokenBasedUpload(attachToDoc, fieldName, userToken, context);
    }

    /**
     * 
     * @param attachToDocFN
     * @param fieldName
     * @param userToken
     * @param createIfNotExists
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.28.0 use TokenBasedUploadCommand instead
     */
    @Deprecated
    public int tokenBasedUpload(String attachToDocFN, String fieldName, String userToken, Boolean createIfNotExists,
            XWikiContext context) throws XWikiException {
        return new TokenBasedUploadCommand().tokenBasedUpload(attachToDocFN, fieldName, userToken,
                createIfNotExists, context);
    }

    /**
     * 
     * @param userToken
     * @param context
     * @return
     * @throws XWikiException
     * 
     * @deprecated since 2.14.0 use TokenLDAPAuthServiceImpl instead
     */
    @Deprecated
    public XWikiUser checkAuthByToken(String userToken, XWikiContext context) throws XWikiException {
        String username = getUsernameForToken(userToken, context);
        if ((username != null) && !username.equals("")) {
            LOGGER.info("checkAuthByToken: user " + username + " identified by userToken.");
            context.setUser(username);
            return context.getXWikiUser();
        } else {
            LOGGER.warn("checkAuthByToken: username could not be identified by token");
        }
        return null;
    }

    public XWikiUser checkAuth(String logincredential, String password, String rememberme, String possibleLogins,
            XWikiContext context) throws XWikiException {
        String loginname = getUsernameForUserData(logincredential, possibleLogins, context);
        if ("".equals(loginname) && possibleLogins.matches("(.*,)?loginname(,.*)?")) {
            loginname = logincredential;
        }
        return context.getWiki().getAuthService().checkAuth(loginname, password, rememberme, context);
    }

    public void enableMappedMenuItems(XWikiContext context) {
        GetMappedMenuItemsForParentCommand cmd = new GetMappedMenuItemsForParentCommand();
        cmd.set_isActive(true);
        context.put(GetMappedMenuItemsForParentCommand.CELEMENTS_MAPPED_MENU_ITEMS_KEY, cmd);
    }

    public boolean executeAction(Document actionDoc, Map<String, String[]> request, XWikiDocument includingDoc,
            XWikiContext context) {
        LOGGER.info("Executing action on doc '" + actionDoc.getFullName() + "'");
        VelocityContext vcontext = ((VelocityContext) context.get("vcontext"));
        vcontext.put("theDoc", actionDoc);
        Boolean debug = (Boolean) vcontext.get("debug");
        vcontext.put("debug", true);
        Boolean hasedit = (Boolean) vcontext.get("hasedit");
        vcontext.put("hasedit", true);
        Object req = vcontext.get("request");
        vcontext.put("request", getApiUsableMap(request));
        XWikiDocument execAct = null;
        try {
            execAct = context.getWiki().getDocument("celements2web:Macros.executeActions", context);
        } catch (XWikiException e) {
            LOGGER.error("Could not get action Macro", e);
        }
        String actionContent = "";
        if (execAct != null) {
            String execContent = execAct.getContent();
            execContent = execContent.replaceAll("\\{(/?)pre\\}", "");
            actionContent = context.getWiki().getRenderingEngine().interpretText(execContent, includingDoc,
                    context);
        }
        Object successfulObj = vcontext.get("successful");
        boolean successful = (successfulObj != null) && "true".equals(successfulObj.toString());
        if (!successful) {
            LOGGER.error("Error executing action. Output:" + vcontext.get("actionScriptOutput"));
            LOGGER.error("Rendered Action Script: " + actionContent);
        }
        vcontext.put("debug", debug);
        vcontext.put("hasedit", hasedit);
        vcontext.put("request", req);
        return successful;
    }

    //FIXME Hack to get mail execution to work. The script is not expecting arrays in the
    //      map, since it expects a request. Multiple values with the same name get lost 
    //      in this "quick and dirty" fix
    private Object getApiUsableMap(Map<String, String[]> request) {
        Map<String, String> apiConform = new HashMap<String, String>();
        for (String key : request.keySet()) {
            if ((request.get(key) != null) && (request.get(key).length > 0)) {
                apiConform.put(key, request.get(key)[0]);
            } else {
                apiConform.put(key, null);
            }
        }
        return apiConform;
    }

    public List<String> getSupportedAdminLanguages() {
        if (supportedAdminLangList == null) {
            setSupportedAdminLanguages(Arrays.asList(new String[] { "de", "fr", "en", "it" }));
        }
        return supportedAdminLangList;
    }

    public void setSupportedAdminLanguages(List<String> newSupportedAdminLangList) {
        supportedAdminLangList = newSupportedAdminLangList;
    }

    public boolean writeUTF8Response(String filename, String renderDocFullName, XWikiContext context) {
        boolean success = false;
        if (context.getWiki().exists(renderDocFullName, context)) {
            XWikiDocument renderDoc;
            try {
                renderDoc = context.getWiki().getDocument(renderDocFullName, context);
                adjustResponseHeader(filename, context.getResponse(), context);
                setResponseContent(renderDoc, context.getResponse(), context);
            } catch (XWikiException e) {
                LOGGER.error(e);
            }
            context.setFinished(true);
        }
        return success;
    }

    void adjustResponseHeader(String filename, XWikiResponse response, XWikiContext context) {
        response.setContentType("text/plain");
        String ofilename = Util.encodeURI(filename, context).replaceAll("\\+", " ");
        response.addHeader("Content-disposition", "attachment; filename=\"" + ofilename + "\"; charset='UTF-8'");
    }

    void setResponseContent(XWikiDocument renderDoc, XWikiResponse response, XWikiContext context)
            throws XWikiException {
        String renderedContent = new RenderCommand().renderDocument(renderDoc);
        byte[] data = {};
        try {
            data = renderedContent.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        response.setContentLength(data.length + 3);
        try {
            response.getOutputStream().write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF });
            response.getOutputStream().write(data);
        } catch (IOException e) {
            throw new XWikiException(XWikiException.MODULE_XWIKI_APP,
                    XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, "Exception while sending response", e);
        }
    }

    public boolean isFormFilled(Map<String, String[]> parameterMap, Set<String> additionalFields) {
        boolean isFilled = false;
        if (parameterMap.size() > getIsFilledModifier(parameterMap, additionalFields)) {
            isFilled = true;
        }
        return isFilled;
    }

    short getIsFilledModifier(Map<String, String[]> parameterMap, Set<String> additionalFields) {
        List<String> standardParams = new ArrayList<String>();
        standardParams.add(PARAM_XPAGE);
        standardParams.add(PARAM_CONF);
        standardParams.add(PARAM_AJAX_MODE);
        standardParams.add(PARAM_SKIN);
        standardParams.add(PARAM_LANGUAGE);
        standardParams.add(PARAM_XREDIRECT);
        short modifier = 0;
        if (parameterMap.containsKey(PARAM_XPAGE) && parameterMap.containsKey(PARAM_CONF)
                && arrayContains(parameterMap.get(PARAM_XPAGE), "overlay")) {
            modifier += 1;
        }
        if (parameterMap.containsKey(PARAM_XPAGE) && parameterMap.containsKey(PARAM_AJAX_MODE)
                && arrayContains(parameterMap.get(PARAM_XPAGE), "celements_ajax")) {
            modifier += 1;
            if (parameterMap.containsKey(PARAM_SKIN)) {
                modifier += 1;
            }
        }
        if (parameterMap.containsKey(PARAM_XPAGE)) {
            modifier += 1;
        }
        if (parameterMap.containsKey(PARAM_XREDIRECT)) {
            modifier += 1;
        }
        if (parameterMap.containsKey(PARAM_LANGUAGE)) {
            modifier += 1;
        }
        if ((additionalFields != null) && additionalFields.size() > 0) {
            for (String param : additionalFields) {
                if (!standardParams.contains(param) && parameterMap.containsKey(param)) {
                    modifier += 1;
                }
            }
        }
        return modifier;
    }

    boolean arrayContains(String[] array, String value) {
        Arrays.sort(array);
        return (Arrays.binarySearch(array, value) >= 0);
    }

    /**
     * @deprecated since 2.14.0 use IWebUtilsService instead
     */
    @Deprecated
    public String getDefaultLanguage(XWikiContext context) {
        return getWebService().getDefaultLanguage();
    }

    private IWebUtilsService getWebService() {
        return Utils.getComponent(IWebUtilsService.class);
    }

    /**
     * addTranslation
     * @param fullName
     * @param language
     * @param context
     * @return
     * 
     * @deprecated since 2.14.0 please use the AddTranslationCommand directly
     */
    @Deprecated
    public boolean addTranslation(String fullName, String language, XWikiContext context) {
        return new AddTranslationCommand().addTranslation(fullName, language, context);
    }

}