org.exoplatform.services.cms.impl.Utils.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.services.cms.impl.Utils.java

Source

/*
 * Copyright (C) 2003-2007 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */
package org.exoplatform.services.cms.impl;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
import javax.ws.rs.core.MediaType;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.container.component.ComponentPlugin;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.services.cms.BasePath;
import org.exoplatform.services.cms.documents.TrashService;
import org.exoplatform.services.cms.link.LinkManager;
import org.exoplatform.services.cms.templates.TemplateService;
import org.exoplatform.services.cms.thumbnail.ThumbnailPlugin;
import org.exoplatform.services.cms.thumbnail.ThumbnailService;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
import org.exoplatform.services.jcr.impl.core.NodeImpl;
import org.exoplatform.services.jcr.util.Text;
import org.exoplatform.services.jcr.util.VersionHistoryImporter;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.services.security.Identity;
import org.exoplatform.services.security.IdentityRegistry;
import org.exoplatform.services.security.MembershipEntry;
import org.exoplatform.services.wcm.core.NodetypeConstant;
import org.exoplatform.services.wcm.utils.WCMCoreUtils;

import com.ibm.icu.text.Transliterator;

/**
 * @author benjaminmestrallet
 */
public class Utils {
    private final static Log LOG = ExoLogger.getLogger(Utils.class.getName());

    private static final String ILLEGAL_SEARCH_CHARACTERS = "\\!^()+{}[]:\"-";

    public static final String MAPPING_FILE = "mapping.properties";

    public static final String EXO_SYMLINK = "exo:symlink";

    public static final long KB = 1024L;
    public static final long MB = 1024L * KB;
    public static final long GB = 1024L * MB;

    public static Node makePath(Node rootNode, String path, String nodetype)
            throws PathNotFoundException, RepositoryException {
        return makePath(rootNode, path, nodetype, null);
    }

    @SuppressWarnings("unchecked")
    public static Node makePath(Node rootNode, String path, String nodetype, Map permissions)
            throws PathNotFoundException, RepositoryException {
        String[] tokens = path.split("/");
        Node node = rootNode;
        for (int i = 0; i < tokens.length; i++) {
            String token = tokens[i];
            if (token.length() > 0) {
                if (node.hasNode(token)) {
                    node = node.getNode(token);
                } else {
                    node = node.addNode(token, nodetype);
                    node.getSession().save();
                    node = (Node) node.getSession().getItem(node.getPath());
                    if (node.canAddMixin("exo:privilegeable")) {
                        node.addMixin("exo:privilegeable");
                    }
                    if (permissions != null) {
                        ((ExtendedNode) node).setPermissions(permissions);
                    }
                }
            }
        }
        rootNode.save();
        return node;
    }

    /**
     * this function used to process import version history for a node
     *
     * @param currentNode
     * @param versionHistorySourceStream
     * @param mapHistoryValue
     * @throws Exception
     */
    public static void processImportHistory(Node currentNode, InputStream versionHistorySourceStream,
            Map<String, String> mapHistoryValue) throws Exception {
        //read stream, get the version history data & keep it inside a map
        Map<String, byte[]> mapVersionHistoryData = getVersionHistoryData(versionHistorySourceStream);

        //import one by one
        for (String uuid : mapHistoryValue.keySet()) {
            for (String name : mapVersionHistoryData.keySet()) {
                if (name.equals(uuid + ".xml")) {
                    try {
                        byte[] versionHistoryData = mapVersionHistoryData.get(name);
                        ByteArrayInputStream inputStream = new ByteArrayInputStream(versionHistoryData);
                        String value = mapHistoryValue.get(uuid);
                        Node versionableNode = currentNode.getSession().getNodeByUUID(uuid);
                        importHistory((NodeImpl) versionableNode, inputStream, getBaseVersionUUID(value),
                                getPredecessors(value), getVersionHistory(value));
                        currentNode.getSession().save();
                        break;
                    } catch (ItemNotFoundException item) {
                        currentNode.getSession().refresh(false);
                        if (LOG.isErrorEnabled()) {
                            LOG.error("Can not found versionable node" + item, item);
                        }
                    } catch (Exception e) {
                        currentNode.getSession().refresh(false);
                        if (LOG.isErrorEnabled()) {
                            LOG.error("Import version history failed " + e, e);
                        }
                    }
                }
            }
        }
    }

    /**
     * This function is used to get the version history data which is kept inside the xml files
     * @param versionHistorySourceStream
     * @return a map saving version history data with format: [file name, version history data]
     * @throws IOException
     */
    private static Map<String, byte[]> getVersionHistoryData(InputStream versionHistorySourceStream)
            throws IOException {
        Map<String, byte[]> mapVersionHistoryData = new HashMap<String, byte[]>();
        ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(versionHistorySourceStream));
        byte[] data = new byte[1024];
        ZipEntry entry = zipInputStream.getNextEntry();
        while (entry != null) {
            //get binary data inside the zip entry
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int available = -1;
            while ((available = zipInputStream.read(data, 0, 1024)) > -1) {
                out.write(data, 0, available);
            }

            //save data into map
            mapVersionHistoryData.put(entry.getName(), out.toByteArray());

            //go to next entry
            out.close();
            zipInputStream.closeEntry();
            entry = zipInputStream.getNextEntry();
        }

        zipInputStream.close();
        return mapVersionHistoryData;
    }

    /**
     * do import a version into a node
     *
     * @param versionableNode
     * @param versionHistoryStream
     * @param baseVersionUuid
     * @param predecessors
     * @param versionHistory
     * @throws RepositoryException
     * @throws IOException
     */
    private static void importHistory(NodeImpl versionableNode, InputStream versionHistoryStream,
            String baseVersionUuid, String[] predecessors, String versionHistory)
            throws RepositoryException, IOException {
        VersionHistoryImporter versionHistoryImporter = new VersionHistoryImporter(versionableNode,
                versionHistoryStream, baseVersionUuid, predecessors, versionHistory);
        versionHistoryImporter.doImport();
    }

    /**
     * get data from the version history file
     *
     * @param importHistorySourceStream
     * @return
     * @throws Exception
     */
    public static Map<String, String> getMapImportHistory(InputStream importHistorySourceStream) throws Exception {
        ZipInputStream zipInputStream = new ZipInputStream(importHistorySourceStream);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] data = new byte[1024];
        ZipEntry entry = zipInputStream.getNextEntry();
        Map<String, String> mapHistoryValue = new HashMap<String, String>();
        while (entry != null) {
            int available = -1;
            if (entry.getName().equals(MAPPING_FILE)) {
                while ((available = zipInputStream.read(data, 0, 1024)) > -1) {
                    out.write(data, 0, available);
                }
                InputStream inputStream = new ByteArrayInputStream(out.toByteArray());
                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
                String strLine;
                // Read File Line By Line
                while ((strLine = br.readLine()) != null) {
                    // Put the history information into list
                    if (strLine.indexOf("=") > -1) {
                        mapHistoryValue.put(strLine.split("=")[0], strLine.split("=")[1]);
                    }
                }
                // Close the input stream
                inputStream.close();
                zipInputStream.closeEntry();
                break;
            }
            entry = zipInputStream.getNextEntry();
        }
        out.close();
        zipInputStream.close();
        return mapHistoryValue;
    }

    private static String getBaseVersionUUID(String valueHistory) {
        String[] arrHistoryValue = valueHistory.split(";");
        return arrHistoryValue[1];
    }

    private static String[] getPredecessors(String valueHistory) {
        String[] arrHistoryValue = valueHistory.split(";");
        String strPredecessors = arrHistoryValue[1];
        if (strPredecessors.indexOf(",") > -1) {
            return strPredecessors.split(",");
        }
        return new String[] { strPredecessors };
    }

    private static String getVersionHistory(String valueHistory) {
        String[] arrHistoryValue = valueHistory.split(";");
        return arrHistoryValue[0];
    }

    public static String getPersonalDrivePath(String parameterizedDrivePath, String userId) throws Exception {
        SessionProvider sessionProvider = WCMCoreUtils.getUserSessionProvider();
        NodeHierarchyCreator nodeHierarchyCreator = WCMCoreUtils.getService(NodeHierarchyCreator.class);
        Node userNode = nodeHierarchyCreator.getUserNode(sessionProvider, userId);
        return StringUtils.replaceOnce(parameterizedDrivePath,
                nodeHierarchyCreator.getJcrPath(BasePath.CMS_USERS_PATH) + "/${userId}", userNode.getPath());
    }

    public static List<PropertyDefinition> getProperties(Node node) throws Exception {
        List<PropertyDefinition> properties = new ArrayList<PropertyDefinition>();
        NodeType nodetype = node.getPrimaryNodeType();
        Collection<NodeType> types = new ArrayList<NodeType>();
        types.add(nodetype);
        NodeType[] mixins = node.getMixinNodeTypes();
        if (mixins != null)
            types.addAll(Arrays.asList(mixins));
        for (NodeType nodeType : types) {
            for (PropertyDefinition property : nodeType.getPropertyDefinitions()) {
                String name = property.getName();
                if (!name.equals("exo:internalUse") && !property.isProtected() && !node.hasProperty(name)) {
                    properties.add(property);
                }
            }
        }
        return properties;
    }

    public static boolean isInTrash(Node node) throws RepositoryException {
        TrashService trashService = WCMCoreUtils.getService(TrashService.class);
        return trashService.isInTrash(node);
    }

    /**
     * Gets the title.
     *
     * @param node the node
     * @return the title
     * @throws Exception the exception
     */
    public static String getTitle(Node node) throws Exception {
        String title = null;
        if (node.hasProperty("exo:title")) {
            title = node.getProperty("exo:title").getValue().getString();
        } else if (node.hasNode("jcr:content")) {
            Node content = node.getNode("jcr:content");
            if (content.hasProperty("dc:title")) {
                try {
                    title = content.getProperty("dc:title").getValues()[0].getString();
                } catch (Exception ex) {
                    title = null;
                }
            }
        }
        if (title == null) {
            if (node.isNodeType("nt:frozenNode")) {
                String uuid = node.getProperty("jcr:frozenUuid").getString();
                Node originalNode = node.getSession().getNodeByUUID(uuid);
                title = originalNode.getName();
            } else {
                title = node.getName();
            }

        }
        return StringEscapeUtils.escapeHtml(Text.unescapeIllegalJcrChars(title));
    }

    public static String escapeIllegalCharacterInQuery(String query) {
        String ret = query;
        if (ret != null) {
            for (char c : ILLEGAL_SEARCH_CHARACTERS.toCharArray()) {
                ret = ret.replace(c + "", "\\" + c);
            }
        }
        return ret;
    }

    /**
     * 
     * @param     : node
     * @param     : keepInTrash true if the link will be move to trash, otherwise set by false
     * @throws    : Exception
     * @Objective : Remove all the link of a deleted node
     * @Author    : Nguyen The Vinh from ECM of eXoPlatform
     *              vinh.nguyen@exoplatform.com
     */
    public static void removeDeadSymlinks(Node node, boolean keepInTrash) throws Exception {
        if (isInTrash(node)) {
            return;
        }
        LinkManager linkManager = WCMCoreUtils.getService(LinkManager.class);
        TrashService trashService = WCMCoreUtils.getService(TrashService.class);
        SessionProvider sessionProvider = SessionProvider.createSystemProvider();
        Queue<Node> queue = new LinkedList<Node>();
        queue.add(node);

        try {
            while (!queue.isEmpty()) {
                node = queue.poll();
                if (!node.isNodeType(EXO_SYMLINK)) {
                    try {
                        List<Node> symlinks = linkManager.getAllLinks(node, EXO_SYMLINK);

                        // Before removing symlinks, We order symlinks by name descending, index descending.
                        // Example: symlink[3],symlink[2], symlink[1] to avoid the case that
                        // the index of same name symlink automatically changed to increasing one by one
                        Collections.sort(symlinks, new Comparator<Node>() {
                            @Override
                            public int compare(Node node1, Node node2) {
                                try {
                                    String name1 = node1.getName();
                                    String name2 = node2.getName();
                                    if (name1.equals(name2)) {
                                        int index1 = node1.getIndex();
                                        int index2 = node2.getIndex();
                                        return -1 * ((Integer) index1).compareTo(index2);
                                    }
                                    return -1 * name1.compareTo(name2);
                                } catch (RepositoryException e) {
                                    return 0;
                                }
                            }
                        });

                        for (Node symlink : symlinks) {
                            synchronized (symlink) {
                                if (keepInTrash) {
                                    trashService.moveToTrash(symlink, sessionProvider, 1);
                                } else {
                                    symlink.remove();
                                }
                            }
                        }
                    } catch (Exception e) {
                        if (LOG.isWarnEnabled()) {
                            LOG.warn(e.getMessage());
                        }
                    }
                    for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
                        queue.add(iter.nextNode());
                    }
                }
            }
        } catch (Exception e) {
            if (LOG.isWarnEnabled()) {
                LOG.warn(e.getMessage());
            }
        } finally {
            sessionProvider.close();
        }
    }

    public static void removeDeadSymlinks(Node node) throws Exception {
        removeDeadSymlinks(node, true);
    }

    public static Node getChildOfType(Node node, String childType) throws Exception {
        if (node == null) {
            return null;
        }
        NodeIterator iter = node.getNodes();
        while (iter.hasNext()) {
            Node child = iter.nextNode();
            if (child.isNodeType(childType)) {
                return child;
            }
        }
        return null;
    }

    public static boolean hasChild(Node node, String childType) throws Exception {
        return (getChildOfType(node, childType) != null);
    }

    /**
     * Get Service Log Content Node of specific service.
     *
     * @param serviceName
     * @return
     * @throws Exception
     */
    public static Node getServiceLogContentNode(String serviceName, String logType) throws Exception {
        // Get workspace and session where store service log
        ManageableRepository repository = WCMCoreUtils.getRepository();
        Session session = WCMCoreUtils.getSystemSessionProvider()
                .getSession(repository.getConfiguration().getDefaultWorkspaceName(), repository);
        Node serviceLogContentNode = null;

        if (session.getRootNode().hasNode("exo:services")) {
            // Get service folder
            Node serviceFolder = session.getRootNode().getNode("exo:services");

            // Get service node
            Node serviceNode = serviceFolder.hasNode(serviceName) ? serviceFolder.getNode(serviceName)
                    : serviceFolder.addNode(serviceName, NodetypeConstant.NT_UNSTRUCTURED);

            // Get log node of service
            String serviceLogName = serviceName + "_" + logType;
            Node serviceLogNode = serviceNode.hasNode(serviceLogName) ? serviceNode.getNode(serviceLogName)
                    : serviceNode.addNode(serviceLogName, NodetypeConstant.NT_FILE);

            // Get service log content
            if (serviceLogNode.hasNode(NodetypeConstant.JCR_CONTENT)) {
                serviceLogContentNode = serviceLogNode.getNode(NodetypeConstant.JCR_CONTENT);
            } else {
                serviceLogContentNode = serviceLogNode.addNode(NodetypeConstant.JCR_CONTENT,
                        NodetypeConstant.NT_RESOURCE);
                serviceLogContentNode.setProperty(NodetypeConstant.JCR_ENCODING, "UTF-8");
                serviceLogContentNode.setProperty(NodetypeConstant.JCR_MIME_TYPE, MediaType.TEXT_PLAIN);
                serviceLogContentNode.setProperty(NodetypeConstant.JCR_DATA, StringUtils.EMPTY);
                serviceLogContentNode.setProperty(NodetypeConstant.JCR_LAST_MODIFIED, new Date().getTime());
            }
        }
        session.save();
        return serviceLogContentNode;
    }

    public static String getObjectId(String nodePath) throws UnsupportedEncodingException {
        return URLEncoder.encode(nodePath.replaceAll("'", "\\\\'"), "utf-8");
    }

    /**
     * Clean string.
     *
     * @param str the str
     *
     * @return the string
     */
    public static String cleanString(String str) {
        Transliterator accentsconverter = Transliterator
                .getInstance("Latin; NFD; [:Nonspacing Mark:] Remove; NFC;");
        str = accentsconverter.transliterate(str);
        //the character ? seems to not be changed to d by the transliterate function
        StringBuffer cleanedStr = new StringBuffer(str.trim());
        // delete special character
        for (int i = 0; i < cleanedStr.length(); i++) {
            char c = cleanedStr.charAt(i);
            if (c == ' ') {
                if (i > 0 && cleanedStr.charAt(i - 1) == '-') {
                    cleanedStr.deleteCharAt(i--);
                } else {
                    c = '-';
                    cleanedStr.setCharAt(i, c);
                }
                continue;
            }
            if (i > 0 && !(Character.isLetterOrDigit(c) || c == '-')) {
                cleanedStr.deleteCharAt(i--);
                continue;
            }
            if (i > 0 && c == '-' && cleanedStr.charAt(i - 1) == '-')
                cleanedStr.deleteCharAt(i--);
        }
        while (StringUtils.isNotEmpty(cleanedStr.toString()) && !Character.isLetterOrDigit(cleanedStr.charAt(0))) {
            cleanedStr.deleteCharAt(0);
        }
        String clean = cleanedStr.toString().toLowerCase();
        if (clean.endsWith("-")) {
            clean = clean.substring(0, clean.length() - 1);
        }

        return clean;
    }

    public static List<String> getMemberships() throws Exception {
        String userId = ConversationState.getCurrent().getIdentity().getUserId();
        List<String> userMemberships = new ArrayList<String>();
        userMemberships.add(userId);
        // here we must retrieve memberships of the user using the
        // IdentityRegistry Service instead of Organization Service to
        // allow JAAS based authorization
        Collection<MembershipEntry> memberships = getUserMembershipsFromIdentityRegistry(userId);
        if (memberships != null) {
            for (MembershipEntry membership : memberships) {
                String role = membership.getMembershipType() + ":" + membership.getGroup();
                userMemberships.add(role);
            }
        }
        return userMemberships;
    }

    /**
     * this method retrieves memberships of the user having the given id using the
     * IdentityRegistry service instead of the Organization service to allow JAAS
     * based authorization
     *
     * @param authenticatedUser the authenticated user id
     * @return a collection of MembershipEntry
     */
    private static Collection<MembershipEntry> getUserMembershipsFromIdentityRegistry(String authenticatedUser) {
        IdentityRegistry identityRegistry = WCMCoreUtils.getService(IdentityRegistry.class);
        Identity currentUserIdentity = identityRegistry.getIdentity(authenticatedUser);
        return currentUserIdentity.getMemberships();
    }

    public static String getNodeTypeIcon(Node node, String appended, String mode) throws RepositoryException {
        StringBuilder str = new StringBuilder();
        if (node == null)
            return "";

        // Primary node type
        String nodeType = node.getPrimaryNodeType().getName();

        // Get real node if node is symlink
        if (node.isNodeType(EXO_SYMLINK)) {
            LinkManager linkManager = Util.getUIPortal().getApplicationComponent(LinkManager.class);
            try {
                nodeType = node.getProperty(NodetypeConstant.EXO_PRIMARYTYPE).getString();
                node = linkManager.getTarget(node);
                if (node == null)
                    return "";
            } catch (Exception e) {
                return "";
            }
        }

        if (node.isNodeType(NodetypeConstant.EXO_TRASH_FOLDER)) {
            nodeType = NodetypeConstant.EXO_TRASH_FOLDER;
        } else if (node.isNodeType(NodetypeConstant.EXO_FAVOURITE_FOLDER)) {
            nodeType = NodetypeConstant.EXO_FAVOURITE_FOLDER;
        } else if (nodeType.equals(NodetypeConstant.NT_UNSTRUCTURED)
                || nodeType.equals(NodetypeConstant.NT_FOLDER)) {
            for (String specificFolder : NodetypeConstant.SPECIFIC_FOLDERS) {
                if (node.isNodeType(specificFolder)) {
                    nodeType = specificFolder;
                    break;
                }
            }
        }

        nodeType = nodeType.replace(':', '_');

        // Default css class
        String defaultCssClass;
        if (node.isNodeType(NodetypeConstant.NT_UNSTRUCTURED) || node.isNodeType(NodetypeConstant.NT_FOLDER)) {
            defaultCssClass = "Folder";
        } else if (node.isNodeType(NodetypeConstant.NT_FILE)) {
            defaultCssClass = "File";
        } else {
            defaultCssClass = nodeType;
        }
        defaultCssClass += "Default";

        str.append(appended);
        str.append(defaultCssClass);
        str.append(" ");
        str.append(appended);
        str.append(nodeType);
        if (mode != null && mode.equalsIgnoreCase("Collapse"))
            str.append(' ').append(mode).append(appended).append(nodeType);
        if (node.isNodeType(NodetypeConstant.NT_FILE)) {
            if (node.hasNode(NodetypeConstant.JCR_CONTENT)) {
                Node jcrContentNode = node.getNode(NodetypeConstant.JCR_CONTENT);
                str.append(' ').append(appended).append(jcrContentNode.getProperty(NodetypeConstant.JCR_MIMETYPE)
                        .getString().toLowerCase().replaceAll("/|\\.", ""));
            }
        }
        return str.toString();
    }

    public static String getNodeTypeIcon(Node node, String appended) throws RepositoryException {
        return getNodeTypeIcon(node, appended, null);
    }

    /**
     * Check if a node is document type.
     * @param node
     * @return true: is document; false: not document
     * @throws Exception
     */
    public static boolean isDocument(Node node) throws Exception {
        TemplateService templateService = WCMCoreUtils.getService(TemplateService.class);
        if (templateService == null)
            return false;
        List<String> documentTypeList = templateService.getDocumentTemplates();
        if (documentTypeList == null)
            return false;
        for (String documentType : documentTypeList) {
            if (node.getPrimaryNodeType().isNodeType(documentType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * gets the file size in friendly format
     * @param node the file node
     * @return the file size
     * @throws Exception
     */
    public static String fileSize(Node node) throws Exception {
        if (node == null || !node.isNodeType("nt:file")) {
            return "";
        }
        StringBuffer ret = new StringBuffer();
        ret.append(" - ");
        long size = 0;
        try {
            size = node.getProperty("jcr:content/jcr:data").getLength();
        } catch (Exception e) {
            LOG.error("Can not get file size", e);
        }
        long byteSize = size % KB;
        long kbSize = (size % MB) / KB;
        long mbSize = (size % GB) / MB;
        long gbSize = size / GB;

        if (gbSize >= 1) {
            ret.append(gbSize).append(refine(mbSize)).append(" GB");
        } else if (mbSize >= 1) {
            ret.append(mbSize).append(refine(kbSize)).append(" MB");
        } else if (kbSize > 1) {
            ret.append(kbSize).append(refine(byteSize)).append(" KB");
        } else {
            ret.append("1 KB");
        }
        return ret.toString();
    }

    public static boolean isSupportThumbnailView(String mimeType) {
        List<String> thumbnailMimeTypes = new ArrayList<String>();
        List<ComponentPlugin> componentPlugins = WCMCoreUtils.getService(ThumbnailService.class)
                .getComponentPlugins();
        for (ComponentPlugin plugin : componentPlugins) {
            if (plugin instanceof ThumbnailPlugin) {
                thumbnailMimeTypes.addAll(((ThumbnailPlugin) plugin).getMimeTypes());
            }
        }
        return thumbnailMimeTypes.contains(mimeType);
    }

    /**
     * refines the size up to 3 digits, add '0' in front if necessary.
     * @param size the size
     * @return the size in 3 digit format
     */
    private static String refine(long size) {
        if (size == 0) {
            return "";
        }
        String strSize = String.valueOf(size);
        while (strSize.length() < 3) {
            strSize = "0" + strSize;
        }
        return "," + Math.round(Double.valueOf(Integer.valueOf(strSize) / 100.0));
    }
}