com.celements.web.plugin.cmd.DocFormCommand.java Source code

Java tutorial

Introduction

Here is the source code for com.celements.web.plugin.cmd.DocFormCommand.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.cmd;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oro.text.perl.MalformedPerl5PatternException;
import org.xwiki.model.reference.DocumentReference;

import com.celements.web.service.IWebUtilsService;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
import com.xpn.xwiki.objects.classes.BaseClass;
import com.xpn.xwiki.objects.classes.PropertyClass;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiRequest;

/**
 * DocFormCommand handles validation of a request with document/object fields
 * and ensures that they are correctly prepared for save.
 * 
 * IMPORTANT: use exactly ONE instance of this class for each XWikiContext (each request).
 * 
 * @author fabian
 *
 */
public class DocFormCommand {

    private static Log LOGGER = LogFactory.getFactory().getInstance(DocFormCommand.class);
    private final Map<String, BaseObject> changedObjects = new HashMap<String, BaseObject>();
    private final Map<String, XWikiDocument> changedDocs = new HashMap<String, XWikiDocument>();

    public Set<XWikiDocument> updateDocFromMap(String fullname, Map<String, String[]> data, XWikiContext context)
            throws XWikiException {
        String docSpace = fullname.split("\\.")[0];
        String docName = fullname.split("\\.")[1];
        DocumentReference docRef = new DocumentReference(context.getDatabase(), docSpace, docName);
        XWikiDocument doc = context.getWiki().getDocument(docRef, context);
        String template = context.getRequest().getParameter("template");
        if (doc.isNew() && !"".equals(template.trim())) {
            String templSpace = template.split("\\.")[0];
            String templName = template.split("\\.")[1];
            DocumentReference templRef = new DocumentReference(context.getDatabase(), templSpace, templName);
            try {
                doc.readFromTemplate(templRef, context);
            } catch (XWikiException e) {
                if (e.getCode() == XWikiException.ERROR_XWIKI_APP_DOCUMENT_NOT_EMPTY) {
                    context.put("exception", e);
                }
                LOGGER.error("Exception reading doc " + docRef + " from template " + templRef, e);
            }
        }
        for (String key : data.keySet()) {
            if (key != null) {
                String[] parts = getDocFullname(key, docSpace, docName);
                DocumentReference saveDocRef = new DocumentReference(context.getDatabase(), parts[0], parts[1]);
                LOGGER.debug("request key:'" + key + "'=value:" + data.get(key).length);
                if (key.matches("([a-zA-Z0-9]*\\.[a-zA-Z0-9]*_)?content")) {
                    XWikiDocument tdoc = getTranslatedDoc(saveDocRef, context);
                    tdoc.setContent(collapse(data.get(key)));
                } else if (key.matches("([a-zA-Z0-9]*\\.[a-zA-Z0-9]*_)?title")) {
                    XWikiDocument tdoc = getTranslatedDoc(saveDocRef, context);
                    tdoc.setTitle(collapse(data.get(key)));
                } else if (key.matches(getFindObjectFieldInRequestRegex())) {
                    XWikiDocument saveDoc = getUpdateDoc(saveDocRef, context);
                    setObjValue(saveDoc, parts[2], data.get(key), context);
                }
            }
        }
        HashSet<XWikiDocument> docSet = new HashSet<XWikiDocument>();
        docSet.addAll(changedDocs.values());
        return docSet;
    }

    String getFindObjectFieldInRequestRegex() {
        return "([a-zA-Z0-9]*\\.[a-zA-Z0-9]*_){1,2}-?(\\d)*_(.*)";
    }

    String[] getDocFullname(String key, String defaultSpace, String defaultName) {
        String docName = defaultName;
        String docSpace = defaultSpace;
        String fieldName = key;
        if (key.matches("([a-zA-Z0-9]*\\.[a-zA-Z0-9]*_){1}(content|title)")
                || key.matches(getRequestParamIncludesDocNameRegex())) {
            String docFullName = key.split("_")[0];
            docSpace = docFullName.split("\\.")[0];
            docName = docFullName.split("\\.")[1];
            fieldName = key.substring(docFullName.length() + 1);
        }
        return new String[] { docSpace, docName, fieldName };
    }

    String getRequestParamIncludesDocNameRegex() {
        return "([a-zA-Z0-9]*\\.[a-zA-Z0-9]*_){2}-?(\\d)*_(.*)";
    }

    XWikiDocument setObjValue(XWikiDocument doc, String key, String[] value, XWikiContext context)
            throws XWikiException {
        String className = key.substring(0, key.indexOf("_"));
        DocumentReference classRef = getWebUtilsService().resolveDocumentReference(className);
        LOGGER.debug("key complete: " + key);
        key = key.substring(key.indexOf("_") + 1);
        Integer objNr = Integer.parseInt(key.substring(0, key.indexOf("_")));
        LOGGER.debug("key -1 part: " + key);
        key = key.substring(key.indexOf("_") + 1);
        LOGGER.debug("key -2 parts: " + key);
        BaseObject obj = null;
        if (changedObjects.containsKey(getObjCacheMapKey(doc, className, objNr))) {
            obj = changedObjects.get(getObjCacheMapKey(doc, className, objNr));
        } else {
            obj = doc.getXObject(classRef, objNr);
            if ((obj == null) || (objNr < 0)) {
                obj = doc.newXObject(classRef, context);
                LOGGER.debug("newObject for classname [" + className + "] on doc [" + doc + "] <-> ["
                        + obj.getNumber() + "] <-> [" + objNr + "].");
            }
            changedObjects.put(getObjCacheMapKey(doc, className, objNr), obj);
            LOGGER.debug("got object for classname [" + className + "] on doc [" + doc + "] <-> [" + obj.getNumber()
                    + "] <-> [" + objNr + "].");
        }
        obj.set(key, collapse(value), context);
        return doc;
    }

    private String getObjCacheMapKey(XWikiDocument doc, String className, Integer objNr) {
        DocumentReference docRef = doc.getDocumentReference();
        return docRef.getLastSpaceReference().getName() + "." + docRef.getName() + "_" + className + "_" + objNr;
    }

    String collapse(String[] value) {
        List<String> valueList = new ArrayList<String>(Arrays.asList(value));
        valueList.removeAll(Arrays.asList((String) null));
        valueList.removeAll(Arrays.asList(""));
        return StringUtils.join(valueList.toArray(), "|");
    }

    XWikiDocument getUpdateDoc(DocumentReference docRef, XWikiContext context) throws XWikiException {
        XWikiDocument doc = context.getWiki().getDocument(docRef, context);
        if (doc.isNew() && "".equals(doc.getDefaultLanguage())) {
            doc.setDefaultLanguage(context.getLanguage());
        }
        if (!changedDocs.containsKey(getFullNameForRef(docRef) + ";" + doc.getDefaultLanguage())) {
            LOGGER.debug("getUpdateDoc: [" + getFullNameForRef(docRef) + ";" + doc.getDefaultLanguage()
                    + "] with doc language [" + doc.getLanguage() + "].");
            applyCreationDateFix(doc, context);
            changedDocs.put(getFullNameForRef(docRef) + ";" + doc.getDefaultLanguage(), doc);
        } else {
            doc = changedDocs.get(getFullNameForRef(docRef) + ";" + doc.getDefaultLanguage());
        }
        return doc;
    }

    XWikiDocument getTranslatedDoc(DocumentReference docRef, XWikiContext context) throws XWikiException {
        XWikiDocument tdoc;
        if (!changedDocs.containsKey(getFullNameForRef(docRef) + ";" + context.getLanguage())) {
            XWikiDocument doc = getUpdateDoc(docRef, context);
            tdoc = new AddTranslationCommand().getTranslatedDoc(doc, context.getLanguage());
            changedDocs.put(getFullNameForRef(docRef) + ";" + context.getLanguage(), tdoc);
        } else {
            tdoc = changedDocs.get(getFullNameForRef(docRef) + ";" + context.getLanguage());
        }
        return tdoc;
    }

    void applyCreationDateFix(XWikiDocument doc, XWikiContext context) {
        //FIXME Should be done when xwiki saves a new document. Unfortunately it is done
        //      when you first get a document and than cached.
        if (doc.isNew()) {
            doc.setCreationDate(new Date());
            doc.setCreator(context.getUser());
        }
    }

    private String getFullNameForRef(DocumentReference docRef) {
        return docRef.getLastSpaceReference().getName() + "." + docRef.getName();
    }

    /**
     * @deprecated since 2.2.0 instead use FormValidationService
     */
    @Deprecated
    public Map<String, String> validateRequest(XWikiContext context) {
        XWikiRequest request = context.getRequest();
        Map<String, String> result = new HashMap<String, String>();
        for (Object paramObj : request.getParameterMap().keySet()) {
            String param = paramObj.toString();

            String validate = validateParameter(param, request.get(param), context);
            if (validate != null) {
                result.put(param, validate);
            }
        }

        return result;
    }

    /**
     * @deprecated since 2.2.0 instead use FormValidationService
     */
    @Deprecated
    private String validateParameter(String param, String value, XWikiContext context) {
        if (param.matches(getFindObjectFieldInRequestRegex())) {
            int pos = 0;
            if (param.matches(getRequestParamIncludesDocNameRegex())) {
                pos = 1;
            }
            String[] paramSplit = param.split("_");
            String className = paramSplit[pos];
            String fieldName = paramSplit[pos + 2];
            for (int i = pos + 3; i < paramSplit.length; i++) {
                fieldName += "_" + paramSplit[i];
            }
            return validateField(className, fieldName, value, context);
        }
        return null;
    }

    /**
     * @deprecated since 2.2.0 instead use FormValidationService
     */
    @Deprecated
    public String validateField(String className, String fieldName, String value, XWikiContext context) {
        String isValidResult = null;
        BaseClass bclass = getBaseClass(className, context);

        if (bclass != null) {
            PropertyClass propclass = (PropertyClass) bclass.getField(fieldName);

            String regexp = getFieldFromProperty(propclass, "validationRegExp");
            String validationMsg = getFieldFromProperty(propclass, "validationMessage");
            if ((regexp != null) && !regexp.trim().equals("")) {
                try {
                    if (!context.getUtil().match(regexp, value)) {
                        isValidResult = validationMsg;
                    }
                } catch (MalformedPerl5PatternException exp) {
                    LOGGER.error("Failed to execute validation regex for field [" + fieldName + "] in class ["
                            + className + "].", exp);
                    isValidResult = validationMsg;
                }
            }
        }

        return isValidResult;
    }

    /**
     * @deprecated since 2.2.0 instead use FormValidationService
     */
    @Deprecated
    String getFieldFromProperty(PropertyClass propclass, String field) {
        BaseProperty prop = (BaseProperty) propclass.getField(field);
        if ((prop != null) && (prop.getValue() != null)) {
            return prop.getValue().toString();
        }
        return "";
    }

    private BaseClass getBaseClass(String className, XWikiContext context) {
        BaseClass bclass = null;
        DocumentReference bclassDocRef = getWebUtilsService().resolveDocumentReference(className);
        try {
            bclass = context.getWiki().getDocument(bclassDocRef, context).getXClass();
        } catch (XWikiException exp) {
            LOGGER.error("Cannot get document class [" + className + "].", exp);
        }
        return bclass;
    }

    Map<String, BaseObject> getChangedObjects() {
        return changedObjects;
    }

    Map<String, XWikiDocument> getChangedDocs() {
        return changedDocs;
    }

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

}