org.infoglue.cms.applications.contenttool.actions.UpdateContentVersionAttributeAction.java Source code

Java tutorial

Introduction

Here is the source code for org.infoglue.cms.applications.contenttool.actions.UpdateContentVersionAttributeAction.java

Source

/* ===============================================================================
 *
 * Part of the InfoGlue Content Management Platform (www.infoglue.org)
 *
 * ===============================================================================
 *
 *  Copyright (C)
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 2, as published by the
 * Free Software Foundation. See the file LICENSE.html for more information.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
 * Place, Suite 330 / Boston, MA 02111-1307 / USA.
 *
 * ===============================================================================
 */

package org.infoglue.cms.applications.contenttool.actions;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.apache.xerces.parsers.DOMParser;
import org.infoglue.cms.controllers.kernel.impl.simple.AccessRightController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentControllerProxy;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentStateController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentTypeDefinitionController;
import org.infoglue.cms.controllers.kernel.impl.simple.ContentVersionController;
import org.infoglue.cms.entities.content.ContentVO;
import org.infoglue.cms.entities.content.ContentVersion;
import org.infoglue.cms.entities.content.ContentVersionVO;
import org.infoglue.cms.entities.management.ContentTypeAttribute;
import org.infoglue.cms.entities.management.ContentTypeDefinitionVO;
import org.infoglue.cms.exception.AccessConstraintException;
import org.infoglue.cms.exception.ConstraintException;
import org.infoglue.cms.util.AccessConstraintExceptionBuffer;
import org.infoglue.cms.util.CmsPropertyHandler;
import org.infoglue.cms.util.ConstraintExceptionBuffer;
import org.infoglue.cms.util.XMLHelper;
import org.infoglue.deliver.controllers.kernel.impl.simple.PageEditorHelper;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
  * This is the action-class for UpdateContentVersionVersion
  * 
  * @author Mattias Bogeblad
  */

public class UpdateContentVersionAttributeAction extends ViewContentVersionAction {
    private final static Logger logger = Logger.getLogger(UpdateContentVersionAttributeAction.class.getName());

    private static final long serialVersionUID = 1L;

    private ContentVersionVO contentVersionVO;
    private Integer contentId;
    private Integer languageId;
    private Integer contentVersionId;
    private String attributeName;
    private String deliverContext = "infoglueDeliverWorking";

    private ConstraintExceptionBuffer ceb;

    public UpdateContentVersionAttributeAction() {
        this(new ContentVersionVO());
    }

    public UpdateContentVersionAttributeAction(ContentVersionVO contentVersionVO) {
        this.contentVersionVO = contentVersionVO;
        this.ceb = new ConstraintExceptionBuffer();
    }

    public String doExecute() throws Exception {
        logger.info("Updating content version attribute....");
        logger.info("contentId:" + contentId);
        logger.info("languageId:" + languageId);
        logger.info("attributeName:" + attributeName);

        super.initialize(this.contentVersionId, this.contentId, this.languageId);

        this.contentVersionVO = this.getContentVersionVO();

        String attributeValue = getRequest().getParameter(this.attributeName);
        logger.info("attributeValue:" + attributeValue);
        if (attributeValue != null) {
            setAttributeValue(this.contentVersionVO, this.attributeName, attributeValue);
            ceb.throwIfNotEmpty();

            this.contentVersionVO.setVersionModifier(this.getInfoGluePrincipal().getName());
            ContentVersionController.getContentVersionController().update(this.contentId, this.languageId,
                    this.contentVersionVO, this.getInfoGluePrincipal());
        }

        return "success";
    }

    private static Boolean active = new Boolean(false);

    /**
     * This command updates a certain attribute in a content version.
     * Lately we added a timeout on the wait for other threads to finish to avoid locks.
     */
    public String doSaveAndReturnValue() {
        /*
        try
        {
           Random rand = new Random();
            int randomNum = rand.nextInt((10 - 1) + 1) + 1;
           System.out.println("Sleep...");
           Thread.sleep(randomNum*1000);
        } 
        catch (Exception e)
        {
        }
        */

        int index = 0;
        while (active && index < 100) {
            logger.info("Waiting for previous thread..");
            try {
                Thread.sleep(50);
            } catch (Exception e) {
            }
            index++;
        }

        synchronized (active) {
            active = new Boolean(true);
        }

        try {
            logger.info("Updating content version attribute through ajax....");
            logger.info("contentId:" + contentId);
            logger.info("languageId:" + languageId);
            logger.info("attributeName:" + attributeName);

            super.initialize(this.contentVersionId, this.contentId, this.languageId);

            this.contentVersionVO = this.getContentVersionVO();
            if (this.contentVersionVO == null) {
                ContentVO contentVO = ContentController.getContentController().getContentVOWithId(contentId);
                ContentTypeDefinitionVO contentTypeDefinitionVO = ContentTypeDefinitionController.getController()
                        .getContentTypeDefinitionVOWithId(contentVO.getContentTypeDefinitionId());

                StringBuffer sb = new StringBuffer();
                sb.append(
                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?><article xmlns=\"x-schema:ArticleSchema.xml\"><attributes>");
                List contentTypeAttributes = ContentTypeDefinitionController.getController()
                        .getContentTypeAttributes(contentTypeDefinitionVO, true);
                Iterator contentTypeAttributesIterator = contentTypeAttributes.iterator();
                while (contentTypeAttributesIterator.hasNext()) {
                    ContentTypeAttribute contentTypeAttribute = (ContentTypeAttribute) contentTypeAttributesIterator
                            .next();
                    String initialValue = contentTypeAttribute.getContentTypeAttribute("initialData")
                            .getContentTypeAttributeParameterValue().getValue("label");
                    if (initialValue == null || initialValue.trim().equals(""))
                        initialValue = "State " + contentTypeAttribute.getName();
                    sb.append("<" + contentTypeAttribute.getName() + "><![CDATA[" + initialValue + "]]></"
                            + contentTypeAttribute.getName() + ">");
                }
                sb.append("</attributes></article>");

                ContentVersionVO contentVersionVO = new ContentVersionVO();
                contentVersionVO.setVersionComment("Autocreated");
                contentVersionVO.setVersionModifier(this.getInfoGluePrincipal().getName());
                contentVersionVO.setVersionValue(sb.toString());
                this.contentVersionVO = ContentVersionController.getContentVersionController().create(contentId,
                        languageId, contentVersionVO, null);
            } else if (!this.contentVersionVO.getStateId().equals(ContentVersionVO.WORKING_STATE)) {
                ContentVersionVO latestContentVersionVO = ContentVersionController.getContentVersionController()
                        .getLatestContentVersionVO(this.contentVersionVO.getContentId(),
                                this.contentVersionVO.getLanguageId());
                if (latestContentVersionVO.getId().intValue() > this.contentVersionVO.getId().intValue()
                        && latestContentVersionVO.getStateId().equals(ContentVersionVO.WORKING_STATE)) {
                    logger.warn("The version is actually not in published state any more: "
                            + latestContentVersionVO.getContentId());
                    this.contentVersionVO = latestContentVersionVO;
                    this.contentVersionId = latestContentVersionVO.getId();
                } else {
                    ContentVersionVO contentVersion = ContentStateController.changeState(
                            this.contentVersionVO.getContentVersionId(), ContentVersionVO.WORKING_STATE,
                            "Edit on sight", false, null, this.getInfoGluePrincipal(),
                            this.contentVersionVO.getContentId(), new ArrayList());
                    logger.info("Changed state on: " + latestContentVersionVO.getContentId());
                    this.contentVersionId = contentVersion.getContentVersionId();
                    this.contentVersionVO = contentVersion;
                }
            }

            String attributeValue = getRequest().getParameter(this.attributeName);
            logger.info("*************************************************");
            logger.info("** SAVING **");
            logger.info("*************************************************");
            logger.info("attributeValue real:" + attributeValue);

            /*
            for(int i=0; i<attributeValue.length(); i++)
               logger.info("c:" + (int)attributeValue.charAt(i) + "-" + Integer.toHexString((int)attributeValue.charAt(i)));
            */

            if (attributeValue != null) {
                boolean enableCustomCharactersParsing = CmsPropertyHandler.getEnableCustomCharactersParsing();
                logger.info("enableCustomCharactersParsing: " + enableCustomCharactersParsing);
                if (enableCustomCharactersParsing) {
                    boolean isUTF8 = false;
                    boolean hasUnicodeChars = false;
                    if (attributeValue.indexOf((char) 65533) > -1)
                        isUTF8 = true;

                    for (int i = 0; i < attributeValue.length(); i++) {
                        int c = (int) attributeValue.charAt(i);
                        //logger.error("c2:" + c + "-" + Integer.toHexString(c));
                        if (c > 255 && c < 65533)
                            hasUnicodeChars = true;
                    }

                    logger.debug("isUTF8:" + isUTF8);
                    logger.debug("hasUnicodeChars:" + hasUnicodeChars);

                    if (!isUTF8 && !hasUnicodeChars) {
                        String fromEncoding = CmsPropertyHandler.getUploadFromEncoding();
                        if (fromEncoding == null)
                            fromEncoding = "iso-8859-1";

                        String toEncoding = CmsPropertyHandler.getUploadToEncoding();
                        if (toEncoding == null)
                            toEncoding = "utf-8";

                        String[] controlChars = CmsPropertyHandler.getCustomCharactersForConversionParsed();
                        if (logger.isInfoEnabled()) {
                            logger.info("controlChars: " + Arrays.toString(controlChars));
                        }

                        boolean convert = true;
                        for (String charToTest : controlChars) {
                            if (logger.isInfoEnabled()) {
                                logger.info("Index for " + charToTest + ":" + attributeValue.indexOf(charToTest));
                            }
                            if (attributeValue.indexOf(charToTest) > -1) {
                                convert = false;
                                break;
                            }
                        }

                        if (convert) {
                            attributeValue = new String(attributeValue.getBytes(fromEncoding), toEncoding);
                        }

                    }
                }

                logger.info("\n\nattributeValue original:" + attributeValue);
                attributeValue = parseInlineAssetReferences(attributeValue);
                logger.info("attributeValue transformed:" + attributeValue + "\n\n");

                setAttributeValue(this.contentVersionVO, this.attributeName, attributeValue);
                ceb.throwIfNotEmpty();

                this.contentVersionVO.setVersionModifier(this.getInfoGluePrincipal().getName());
                ContentVersionController.getContentVersionController().update(this.contentId, this.languageId,
                        this.contentVersionVO, this.getInfoGluePrincipal());
                logger.info("*************************************************");

                attributeValue = PageEditorHelper.parseAttributeForInlineEditing(attributeValue, true,
                        getDeliverContext(), contentId, languageId);
            }

            this.getResponse().setContentType("text/plain; charset=utf-8");
            this.getResponse().setCharacterEncoding("utf-8");
            //this.getResponse().setContentType("text/plain");
            this.getResponse().getWriter().println(attributeValue);
        } catch (ConstraintException ce) {
            logger.info("Error saving attribute - not allowed by validation: " + ce.getMessage());
            this.getResponse().setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
            try {
                final String errorCode = ce.getErrorCode();
                String localizedErrorMessage;
                if (errorCode.length() > 5) {
                    localizedErrorMessage = StringEscapeUtils.unescapeXml(errorCode);
                } else {
                    localizedErrorMessage = getLocalizedErrorMessage(getLocale(), errorCode);
                    String requiredErrorCode = "300";
                    if (requiredErrorCode.equals(errorCode)) {
                        try {
                            String fieldName = ce.getFieldName();
                            fieldName = fieldName.substring(fieldName.lastIndexOf(".") + 1);
                            ContentVO contentVO = ContentController.getContentController()
                                    .getContentVOWithId(this.contentId);
                            String fieldDisplayName = ContentTypeDefinitionController.getController()
                                    .getContentTypeDefinitionAttributeDisplayName(
                                            contentVO.getContentTypeDefinitionId(), fieldName,
                                            getLocale().getLanguage());
                            if (fieldDisplayName == null) {
                                logger.info("Did not find a display name for attribute. " + fieldName);
                            } else {
                                localizedErrorMessage += " (" + fieldDisplayName + ")";
                            }
                        } catch (Exception ex) {
                            logger.warn(
                                    "Failed to get the display name for required field validation error. ContentId: "
                                            + contentId + ". FieldName: " + ce.getFieldName() + ". Message: "
                                            + ex.getMessage());
                            logger.info(
                                    "Failed to get the display name for required field validation error. ContentId: "
                                            + contentId + ". FieldName: " + ce.getFieldName(),
                                    ex);
                        }
                    }
                }
                this.getResponse().setCharacterEncoding("utf-8");
                this.getResponse().getWriter().println(localizedErrorMessage);
            } catch (IOException ex) {
                logger.error("Error when reporting constraint exception for content attribute update. Message: "
                        + ex.getMessage());
            }
            return NONE;
        } catch (Throwable t) {
            logger.error("Error saving attribute: " + t.getMessage(), t);
            this.getResponse().setStatus(this.getResponse().SC_INTERNAL_SERVER_ERROR);
            return ERROR;
        } finally {
            synchronized (active) {
                active = new Boolean(false);
            }
        }

        return NONE;
    }

    public String doGetAttributeValue() throws Exception {
        try {
            super.initialize(this.contentVersionId, this.contentId, this.languageId);
            this.contentVersionVO = this.getContentVersionVO();
            if (this.contentVersionVO == null) {
                ContentVO contentVO = ContentController.getContentController().getContentVOWithId(contentId);
                ContentTypeDefinitionVO contentTypeDefinitionVO = ContentTypeDefinitionController.getController()
                        .getContentTypeDefinitionVOWithId(contentVO.getContentTypeDefinitionId());

                StringBuffer sb = new StringBuffer();
                sb.append(
                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?><article xmlns=\"x-schema:ArticleSchema.xml\"><attributes>");
                List contentTypeAttributes = ContentTypeDefinitionController.getController()
                        .getContentTypeAttributes(contentTypeDefinitionVO, true);
                Iterator contentTypeAttributesIterator = contentTypeAttributes.iterator();
                while (contentTypeAttributesIterator.hasNext()) {
                    ContentTypeAttribute contentTypeAttribute = (ContentTypeAttribute) contentTypeAttributesIterator
                            .next();
                    String initialValue = contentTypeAttribute.getContentTypeAttribute("initialData")
                            .getContentTypeAttributeParameterValue().getValue("label");
                    if (initialValue == null || initialValue.trim().equals(""))
                        initialValue = "State " + contentTypeAttribute.getName();
                    sb.append("<" + contentTypeAttribute.getName() + "><![CDATA[" + initialValue + "]]></"
                            + contentTypeAttribute.getName() + ">");
                }
                sb.append("</attributes></article>");

                ContentVersionVO contentVersionVO = new ContentVersionVO();
                contentVersionVO.setVersionComment("Autocreated");
                contentVersionVO.setVersionModifier(this.getInfoGluePrincipal().getName());
                contentVersionVO.setVersionValue(sb.toString());
                this.contentVersionVO = ContentVersionController.getContentVersionController().create(contentId,
                        languageId, contentVersionVO, null);
            }

            AccessConstraintExceptionBuffer ceb = new AccessConstraintExceptionBuffer();

            Integer protectedContentId = ContentControllerProxy.getController()
                    .getProtectedContentId(this.contentVersionVO.getContentId());
            logger.info("protectedContentId:" + protectedContentId);
            if (protectedContentId != null
                    && !AccessRightController.getController().getIsPrincipalAuthorized(this.getInfoGluePrincipal(),
                            "Content.Write", protectedContentId.toString()))
                ceb.add(new AccessConstraintException("Content.contentId", "1001"));

            ceb.throwIfNotEmpty();

            String attributeValue = "";
            if (this.contentVersionVO != null) {
                attributeValue = ContentVersionController.getContentVersionController()
                        .getAttributeValue(contentVersionVO, attributeName, false);
            }

            logger.info("attributeValue before parse:" + attributeValue);

            attributeValue = PageEditorHelper.parseAttributeForInlineEditing(attributeValue, false,
                    getDeliverContext(), contentId, languageId);
            //logger.info("parseAttributeForInlineEditing done");

            logger.info("attributeValue:" + attributeValue);
            /*
            logger.info("attributeValue:" +attributeValue);
            for(int i=0; i<attributeValue.length(); i++)
               logger.info("c3:" + (int)attributeValue.charAt(i) + "-" + Integer.toHexString((int)attributeValue.charAt(i)));
            */

            this.getResponse().setContentType("text/plain; charset=utf-8");
            this.getResponse().setCharacterEncoding("utf-8");
            //this.getResponse().setContentType("text/plain");
            this.getResponse().getWriter().println(attributeValue);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }

        return NONE;
    }

    private String parseInlineAssetReferences(String attributeValue) throws Exception {
        Map<String, String> replacements = new HashMap<String, String>();

        logger.info("********************\n\n");
        Pattern pattern = Pattern.compile("\"DownloadAsset.action.*?\"");
        Matcher matcher = pattern.matcher(attributeValue);
        while (matcher.find()) {
            String match = matcher.group();
            logger.info("Found a inline asset: " + match);
            String parsedContentId = match.substring(match.indexOf("contentId=") + 10, match.indexOf("&", 10));
            logger.info("parsedContentId: " + parsedContentId);
            int langStartIndex = match.indexOf("languageId=") + 11;
            String parsedLanguageId = match.substring(langStartIndex, match.indexOf("&", langStartIndex));
            logger.info("parsedLanguageId: " + parsedLanguageId);
            int assetStartIndex = match.indexOf("assetKey=") + 9;
            String parsedAssetKey = match.substring(assetStartIndex, match.indexOf("\"", assetStartIndex));
            logger.info("parsedAssetKey: " + parsedAssetKey);

            String url = "$templateLogic.getInlineAssetUrl(" + parsedContentId + ", \"" + parsedAssetKey + "\")";
            logger.info("url:" + url);
            //replacements.put(match.substring(1, match.length() - 1), url);
            replacements.put(match, url);
        }
        logger.info("********************\n\n");

        Iterator<String> replacementsIterator = replacements.keySet().iterator();
        while (replacementsIterator.hasNext()) {
            String patternToReplace = replacementsIterator.next();
            String replacement = replacements.get(patternToReplace);

            logger.info("Replacing " + patternToReplace + " with " + replacement);
            patternToReplace = patternToReplace.replaceAll("\\?", "\\\\?");
            logger.info("patternToReplace " + patternToReplace);

            replacement = replacement.replaceAll("\\$", "\\\\\\$");
            logger.info("replacement " + replacement);
            replacement = replacement.replaceAll("\\.", "\\\\.");
            logger.info("replacement " + replacement);
            replacement = replacement.replaceAll("\\(", "\\\\(");
            logger.info("replacement " + replacement);
            replacement = replacement.replaceAll("\\)", "\\\\)");
            logger.info("replacement " + replacement);

            logger.info("patternToReplace: " + patternToReplace);
            logger.info("replacement: " + replacement);

            logger.info("attributeValue before " + attributeValue);
            String delimeter = "";
            if (patternToReplace.startsWith("\""))
                delimeter = "\"";
            if (patternToReplace.startsWith("\'"))
                delimeter = "\'";

            replacement = delimeter + replacement + delimeter;

            logger.info("replacement: " + replacement);
            attributeValue = attributeValue.replaceAll(patternToReplace, replacement);
            logger.info("attributeValue after " + attributeValue);
        }

        return attributeValue;
    }

    /**
     * This method sets a value to the xml that is the contentVersions Value. 
     */

    private void setAttributeValue(ContentVersionVO contentVersionVO, String attributeName, String attributeValue) {
        String value = "";
        if (this.contentVersionVO != null) {
            try {
                logger.info("VersionValue:" + this.contentVersionVO.getVersionValue());
                InputSource inputSource = new InputSource(
                        new StringReader(this.contentVersionVO.getVersionValue()));

                DOMParser parser = new DOMParser();
                parser.parse(inputSource);
                Document document = parser.getDocument();

                NodeList nl = document.getDocumentElement().getChildNodes();
                Node n = nl.item(0);

                nl = n.getChildNodes();
                for (int i = 0; i < nl.getLength(); i++) {
                    n = nl.item(i);
                    if (n.getNodeName().equalsIgnoreCase(attributeName)) {
                        logger.info("Setting attributeValue: " + attributeValue);
                        if (n.getFirstChild() != null && n.getFirstChild().getNodeValue() != null) {
                            n.getFirstChild().setNodeValue(attributeValue);
                            break;
                        } else {
                            CDATASection cdata = document.createCDATASection(attributeValue);
                            n.appendChild(cdata);
                            break;
                        }
                        /*
                        Node valueNode = n.getFirstChild();
                        n.getFirstChild().setNodeValue(attributeValue);
                        break;
                        */
                    }
                }
                contentVersionVO.setVersionValue(XMLHelper.serializeDom(document, new StringBuffer()).toString());
            } catch (Exception e) {
                logger.error("Problem updating version value:" + attributeName + "=" + attributeValue + " reason:"
                        + e.getMessage(), e);
            }
        }
    }

    public void setContentVersionId(Integer contentVersionId) {
        this.contentVersionVO.setContentVersionId(contentVersionId);
    }

    public java.lang.Integer getContentVersionId() {
        return this.contentVersionVO.getContentVersionId();
    }

    public void setStateId(Integer stateId) {
        this.contentVersionVO.setStateId(stateId);
    }

    public java.lang.Integer getStateId() {
        return this.contentVersionVO.getStateId();
    }

    public void setContentId(Integer contentId) {
        this.contentId = contentId;
    }

    public java.lang.Integer getContentId() {
        return this.contentId;
    }

    public void setLanguageId(Integer languageId) {
        this.languageId = languageId;
    }

    public java.lang.Integer getLanguageId() {
        return this.languageId;
    }

    public java.lang.String getVersionValue() {
        return this.contentVersionVO.getVersionValue();
    }

    public void setVersionValue(java.lang.String versionValue) {
        this.contentVersionVO.setVersionValue(versionValue);
    }

    public String getAttributeName() {
        return attributeName;
    }

    public void setAttributeName(String attributeName) {
        this.attributeName = attributeName;
    }

    public String getDeliverContext() {
        return deliverContext;
    }

    public void setDeliverContext(String deliverContext) {
        this.deliverContext = deliverContext;
    }

}