fr.dutra.confluence2wordpress.core.metadata.DefaultMetadataManager.java Source code

Java tutorial

Introduction

Here is the source code for fr.dutra.confluence2wordpress.core.metadata.DefaultMetadataManager.java

Source

/**
 * Copyright 2011-2012 Alexandre Dutra
 *
 *    Licensed under the Apache 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.apache.org/licenses/LICENSE-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 fr.dutra.confluence2wordpress.core.metadata;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

import com.atlassian.confluence.content.render.xhtml.XhtmlException;
import com.atlassian.confluence.content.render.xhtml.definition.PlainTextMacroBody;
import com.atlassian.confluence.core.ContentEntityObject;
import com.atlassian.confluence.xhtml.api.MacroDefinition;
import com.atlassian.confluence.xhtml.api.MacroDefinitionHandler;
import com.atlassian.confluence.xhtml.api.MacroDefinitionUpdater;
import com.atlassian.confluence.xhtml.api.XhtmlContent;

import fr.dutra.confluence2wordpress.util.CodecUtils;
import fr.dutra.confluence2wordpress.wp.WordpressCategory;
import fr.dutra.confluence2wordpress.wp.WordpressUser;

/**
 * @author Alexandre Dutra
 *
 */
public class DefaultMetadataManager implements MetadataManager {

    //see com.atlassian.confluence.content.render.xhtml.XhtmlConstants
    //see com.atlassian.confluence.content.render.xhtml.storage.macro.StorageMacroConstants

    private static final String WORDPRESS_SYNC_INFO_TAG = "<ac:macro ac:name=\"" + WORDPRESS_SYNC_INFO_MACRO_NAME
            + "\" />";

    private static final String WORDPRESS_META_TAG_START = "<ac:macro ac:name=\"" + WORDPRESS_METADATA_MACRO_NAME
            + "\">";

    private static final String WORDPRESS_META_TAG_END = "</ac:macro>";

    private static final String BODY_TAG_START = "<ac:plain-text-body><![CDATA[";

    private static final String BODY_TAG_END = "]]></ac:plain-text-body>";

    private static final Pattern DRAFT_PREFIX_PATTERN = Pattern.compile("(DRAFT\\s*-\\s*).+");

    private static final String RDP_CATEGORY_NAME = "Revue de presse";

    private static final String RDP_PAGE_TITLE = "Revue de Presse Xebia";

    private static final String RDP_POST_SLUG_FORMAT = "revue-de-presse-xebia-%1$tY-%2$02d";

    private static final String XEBIA_FRANCE_LOGIN = "XebiaFrance";

    private final XhtmlContent xhtmlUtils;

    private final ObjectMapper mapper;

    public DefaultMetadataManager(XhtmlContent xhtmlUtils) {
        super();
        this.xhtmlUtils = xhtmlUtils;
        this.mapper = new ObjectMapper();
    }

    public Metadata extractMetadata(ContentEntityObject page) throws MetadataException {
        //https://developer.atlassian.com/display/CONFDEV/Creating+a+new+Confluence+4.0+Macro
        MacroDefinition metadataMacro = extractMacroDefinition(page, WORDPRESS_METADATA_MACRO_NAME);
        if (metadataMacro == null) {
            return null;
        }
        String macroBody = metadataMacro.getBodyText();
        if (StringUtils.isEmpty(macroBody)) {
            return null;
        }
        return unmarshalMetadata(macroBody);
    }

    public void storeMetadata(ContentEntityObject page, Metadata metadata) throws MetadataException {
        String macroBody = marshalMetadata(metadata);
        if (!updateMacroDefinition(page, WORDPRESS_METADATA_MACRO_NAME, macroBody)) {
            StringBuilder newContent = new StringBuilder();
            newContent.append(page.getBodyAsString());
            newContent.append(buildMetadataMacroTag(macroBody));
            page.setBodyAsString(newContent.toString());
        }
        MacroDefinition syncInfoMacro = extractMacroDefinition(page, WORDPRESS_SYNC_INFO_MACRO_NAME);
        if (syncInfoMacro == null) {
            StringBuilder newContent = new StringBuilder();
            newContent.append(WORDPRESS_SYNC_INFO_TAG);
            newContent.append(page.getBodyAsString());
            page.setBodyAsString(newContent.toString());
        }
    }

    public Metadata createMetadata(ContentEntityObject page, Set<WordpressUser> users,
            Set<WordpressCategory> categories) {
        Metadata metadata = new Metadata();
        String pageTitle = page.getTitle();
        Matcher matcher = DRAFT_PREFIX_PATTERN.matcher(pageTitle);
        if (matcher.matches()) {
            String prefix = matcher.group(1);
            metadata.setPageTitle(StringUtils.substringAfter(pageTitle, prefix));
        } else {
            metadata.setPageTitle(pageTitle);
        }
        if (StringUtils.containsIgnoreCase(metadata.getPageTitle(), RDP_CATEGORY_NAME)) {
            metadata.setPageTitle(RDP_PAGE_TITLE); // to normalize the title
            if (categories != null) {
                for (WordpressCategory category : categories) {
                    if (StringUtils.containsIgnoreCase(category.getCategoryName(), RDP_CATEGORY_NAME)) {
                        metadata.setCategoryNames(Collections.singletonList(category.getCategoryName()));
                        break;
                    }
                }
            }
            Calendar now = Calendar.getInstance();
            metadata.setPostSlug(
                    String.format(RDP_POST_SLUG_FORMAT, now.getTime(), now.get(Calendar.WEEK_OF_YEAR)));
            if (users != null) {
                for (WordpressUser user : users) {
                    if (XEBIA_FRANCE_LOGIN.equals(user.getLogin())) {
                        metadata.setAuthorId(user.getId());
                        break;
                    }
                }
            }
        } else {
            String creatorName = page.getCreatorName();
            if (creatorName != null && users != null) {
                for (WordpressUser wordpressUser : users) {
                    if (creatorName.equals(wordpressUser.getLogin())) {
                        metadata.setAuthorId(wordpressUser.getId());
                        break;
                    }
                }
            }
        }
        return metadata;
    }

    public Metadata unmarshalMetadata(String macroBody) throws MetadataException {
        try {
            String expanded = CodecUtils.decodeAndExpand(macroBody);
            return mapper.readValue(expanded, Metadata.class);
        } catch (JsonParseException e) {
            throw new MetadataException("Cannot unmarshal macro body: " + macroBody, e);
        } catch (JsonMappingException e) {
            throw new MetadataException("Cannot unmarshal macro body: " + macroBody, e);
        } catch (IOException e) {
            throw new MetadataException("Cannot unmarshal macro body: " + macroBody, e);
        }
    }

    public String marshalMetadata(Metadata metadata) throws MetadataException {
        try {
            String json = mapper.writeValueAsString(metadata);
            return CodecUtils.compressAndEncode(json);
        } catch (JsonParseException e) {
            throw new MetadataException("Cannot marshal metadata: " + metadata, e);
        } catch (JsonMappingException e) {
            throw new MetadataException("Cannot marshal metadata: " + metadata, e);
        } catch (IOException e) {
            throw new MetadataException("Cannot marshal metadata: " + metadata, e);
        }
    }

    private StringBuilder buildMetadataMacroTag(String macroBody) throws MetadataException {
        StringBuilder macro = new StringBuilder();
        macro.append(WORDPRESS_META_TAG_START);
        macro.append(BODY_TAG_START);
        macro.append(macroBody);
        macro.append(BODY_TAG_END);
        macro.append(WORDPRESS_META_TAG_END);
        return macro;
    }

    private MacroDefinition extractMacroDefinition(ContentEntityObject page, final String macroName)
            throws MetadataException {
        final List<MacroDefinition> definitions = new ArrayList<MacroDefinition>();
        try {
            xhtmlUtils.handleMacroDefinitions(page.getBodyAsString(), null, new MacroDefinitionHandler() {
                @Override
                public void handle(MacroDefinition macroDefinition) {
                    if (macroDefinition.getName().equals(macroName)) {
                        definitions.add(macroDefinition);
                    }
                }
            });
        } catch (XhtmlException e) {
            throw new MetadataException("Could not parse page: " + page.getTitle(), e);
        }
        if (definitions.isEmpty()) {
            return null;
        }
        MacroDefinition definition = definitions.get(0);
        return definition;
    }

    private boolean updateMacroDefinition(ContentEntityObject page, final String macroName, final String macroBody)
            throws MetadataException {
        final List<MacroDefinition> definitions = new ArrayList<MacroDefinition>();
        String body;
        try {
            body = xhtmlUtils.updateMacroDefinitions(page.getBodyAsString(), null, new MacroDefinitionUpdater() {
                @Override
                public MacroDefinition update(MacroDefinition macroDefinition) {
                    if (macroName.equals(macroDefinition.getName())) {
                        macroDefinition.setBody(new PlainTextMacroBody(macroBody));
                        definitions.add(macroDefinition);
                    }
                    return macroDefinition;
                }
            });

        } catch (XhtmlException e) {
            throw new MetadataException("Could not parse page: " + page.getTitle(), e);
        }
        if (definitions.isEmpty()) {
            return false;
        }
        page.setBodyAsString(body);
        return true;
    }
}