org.alfresco.repo.web.scripts.datalist.DataListDownloadWebScript.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.repo.web.scripts.datalist.DataListDownloadWebScript.java

Source

/*
 * #%L
 * Alfresco Share Services AMP
 * %%
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 * %%
 * This file is part of the Alfresco software. 
 * If the software was purchased under a paid Alfresco license, the terms of 
 * the paid license agreement will prevail.  Otherwise, the software is 
 * provided under the following open source license terms:
 * 
 * Alfresco 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 3 of the License, or
 * (at your option) any later version.
 * 
 * Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */
package org.alfresco.repo.web.scripts.datalist;

import java.io.IOException;
import java.io.Serializable;
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 java.util.StringTokenizer;

import org.alfresco.model.ContentModel;
import org.alfresco.model.DataListModel;
import org.alfresco.repo.web.scripts.DeclarativeSpreadsheetWebScript;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.namespace.InvalidQNameException;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;

/**
 * Data List Download
 * 
 * Exports the contents of a Data List as an Excel file
 * 
 * @author Nick Burch
 */
public class DataListDownloadWebScript extends DeclarativeSpreadsheetWebScript implements InitializingBean {
    // Logger
    private static final Log logger = LogFactory.getLog(DataListDownloadWebScript.class);

    private static final QName DATA_LIST_ITEM_TYPE = DataListModel.PROP_DATALIST_ITEM_TYPE;

    private NodeService nodeService;
    private SiteService siteService;
    private NamespaceService namespaceService;
    private Map<QName, List<QName>> modelOrder;
    private Map<String, String> rawModelOrder;

    public DataListDownloadWebScript() {
        this.filenameBase = "DataListExport";
    }

    /**
     * @param nodeService NodeService
     */
    public void setNodeService(NodeService nodeService) {
        this.nodeService = nodeService;
    }

    /**
     * @param siteService SiteService
     */
    public void setSiteService(SiteService siteService) {
        this.siteService = siteService;
    }

    /**
     * @param namespaceService NamespaceService
     */
    public void setNamespaceService(NamespaceService namespaceService) {
        this.namespaceService = namespaceService;
    }

    public void setModelOrder(Map<String, String> rawModelOrder) {
        this.rawModelOrder = rawModelOrder;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        modelOrder = new HashMap<QName, List<QName>>();
        for (String key : rawModelOrder.keySet()) {
            QName model;
            List<QName> order = new ArrayList<QName>();

            try {
                model = QName.createQName(key, namespaceService);
            } catch (InvalidQNameException e) {
                logger.warn("Skipping invalid model type " + key);
                continue;
            }

            StringTokenizer st = new StringTokenizer(rawModelOrder.get(key), ",");
            while (st.hasMoreTokens()) {
                order.add(QName.createQName(st.nextToken(), namespaceService));
            }
            modelOrder.put(model, order);
        }
    }

    /**
     * Identify the datalist
     */
    @Override
    protected Object identifyResource(String format, WebScriptRequest req) {
        // Try to find the datalist they requested
        NodeRef list;
        Map<String, String> args = req.getServiceMatch().getTemplateVars();
        if (args.get("store_type") != null) {
            list = new NodeRef(args.get("store_type"), args.get("store_id"), args.get("id"));
        } else {
            // Get the site
            SiteInfo site = siteService.getSite(args.get("site"));
            if (site == null) {
                throw new WebScriptException(Status.STATUS_NOT_FOUND, "Site not found with supplied name");
            }

            // Now find the data list container with in
            NodeRef container = nodeService.getChildByName(site.getNodeRef(), ContentModel.ASSOC_CONTAINS,
                    args.get("container"));
            if (container == null) {
                throw new WebScriptException(Status.STATUS_NOT_FOUND, "Container not found within site");
            }

            // Now get the data list itself
            list = nodeService.getChildByName(container, ContentModel.ASSOC_CONTAINS, args.get("list"));
        }
        if (list == null || !nodeService.exists(list)) {
            throw new WebScriptException(Status.STATUS_NOT_FOUND, "The Data List could not be found");
        }

        return list;
    }

    /**
     * We don't have a HTML version
     */
    @Override
    protected boolean allowHtmlFallback() {
        return false;
    }

    /**
     * Fetch the properties, in the requested order, from
     *  the data list definition
     */
    @Override
    protected List<Pair<QName, Boolean>> buildPropertiesForHeader(Object resource, String format,
            WebScriptRequest req) {
        NodeRef list = (NodeRef) resource;
        QName type = buildType(list);

        // Has the user given us rules for what to do
        //  with this type?
        List<QName> props;
        if (modelOrder.containsKey(type)) {
            props = modelOrder.get(type);
        } else {
            // We'll have to try to guess it for them
            // For now, just use DataList properties for the type
            TypeDefinition typeDef = dictionaryService.getType(type);
            Map<QName, PropertyDefinition> allProps = typeDef.getProperties();
            props = new ArrayList<QName>();

            for (QName prop : allProps.keySet()) {
                if (NamespaceService.DATALIST_MODEL_1_0_URI.equals(prop.getNamespaceURI())) {
                    props.add(prop);
                }
            }
        }

        // Everything is required
        List<Pair<QName, Boolean>> properties = new ArrayList<Pair<QName, Boolean>>();
        for (QName qname : props) {
            properties.add(new Pair<QName, Boolean>(qname, true));
        }
        return properties;
    }

    private QName buildType(NodeRef list) {
        String typeS = (String) nodeService.getProperty(list, DATA_LIST_ITEM_TYPE);
        if (!typeS.startsWith(NamespaceService.DATALIST_MODEL_PREFIX + ":")) {
            throw new WebScriptException(Status.STATUS_NOT_IMPLEMENTED, "Unexpected list type " + typeS);
        }
        QName type = QName.createQName(NamespaceService.DATALIST_MODEL_1_0_URI,
                typeS.substring(typeS.indexOf(':') + 1));
        return type;
    }

    private List<NodeRef> getItems(NodeRef list) {
        Set<QName> typeSet = new HashSet<QName>(Arrays.asList(new QName[] { buildType(list) }));

        List<NodeRef> items = new ArrayList<NodeRef>();
        for (ChildAssociationRef ca : nodeService.getChildAssocs(list, typeSet)) {
            items.add(ca.getChildRef());
        }
        return items;
    }

    @Override
    protected void populateBody(Object resource, CSVPrinter csv, List<QName> properties) throws IOException {
        throw new WebScriptException(Status.STATUS_BAD_REQUEST, "CSV not currently supported");
    }

    @Override
    protected void populateBody(Object resource, Workbook workbook, Sheet sheet, List<QName> properties)
            throws IOException {
        NodeRef list = (NodeRef) resource;
        List<NodeRef> items = getItems(list);

        // Our various formats
        DataFormat formatter = workbook.createDataFormat();

        CellStyle styleInt = workbook.createCellStyle();
        styleInt.setDataFormat(formatter.getFormat("0"));
        CellStyle styleDate = workbook.createCellStyle();
        styleDate.setDataFormat(formatter.getFormat("yyyy-mm-dd"));
        CellStyle styleDouble = workbook.createCellStyle();
        styleDouble.setDataFormat(formatter.getFormat("General"));
        CellStyle styleNewLines = workbook.createCellStyle();
        styleNewLines.setWrapText(true);

        // Export the items
        int rowNum = 1, colNum = 0;
        for (NodeRef item : items) {
            Row r = sheet.createRow(rowNum);

            colNum = 0;
            for (QName prop : properties) {
                Cell c = r.createCell(colNum);

                Serializable val = nodeService.getProperty(item, prop);
                if (val == null) {
                    // Is it an association, or just missing?
                    List<AssociationRef> assocs = nodeService.getTargetAssocs(item, prop);
                    if (assocs.size() > 0) {
                        StringBuffer text = new StringBuffer();
                        int lines = 1;

                        for (AssociationRef ref : assocs) {
                            NodeRef child = ref.getTargetRef();
                            QName type = nodeService.getType(child);
                            if (ContentModel.TYPE_PERSON.equals(type)) {
                                if (text.length() > 0) {
                                    text.append('\n');
                                    lines++;
                                }
                                text.append(nodeService.getProperty(child, ContentModel.PROP_USERNAME));
                            } else if (ContentModel.TYPE_CONTENT.equals(type)) {
                                // TODO Link to the content
                                if (text.length() > 0) {
                                    text.append('\n');
                                    lines++;
                                }
                                text.append(nodeService.getProperty(child, ContentModel.PROP_TITLE));
                            } else {
                                System.err.println("TODO: handle " + type + " for " + child);
                            }
                        }

                        String v = text.toString();
                        c.setCellValue(v);
                        if (lines > 1) {
                            c.setCellStyle(styleNewLines);
                            r.setHeightInPoints(lines * sheet.getDefaultRowHeightInPoints());
                        }
                    } else {
                        // This property isn't set
                        c.setCellType(Cell.CELL_TYPE_BLANK);
                    }
                } else {
                    // Regular property, set
                    if (val instanceof String) {
                        c.setCellValue((String) val);
                    } else if (val instanceof Date) {
                        c.setCellValue((Date) val);
                        c.setCellStyle(styleDate);
                    } else if (val instanceof Integer || val instanceof Long) {
                        double v = 0.0;
                        if (val instanceof Long)
                            v = (double) (Long) val;
                        if (val instanceof Integer)
                            v = (double) (Integer) val;
                        c.setCellValue(v);
                        c.setCellStyle(styleInt);
                    } else if (val instanceof Float || val instanceof Double) {
                        double v = 0.0;
                        if (val instanceof Float)
                            v = (double) (Float) val;
                        if (val instanceof Double)
                            v = (double) (Double) val;
                        c.setCellValue(v);
                        c.setCellStyle(styleDouble);
                    } else {
                        // TODO
                        System.err.println("TODO: handle " + val.getClass().getName() + " - " + val);
                    }
                }

                colNum++;
            }

            rowNum++;
        }

        // Sensible column widths please!
        colNum = 0;
        for (QName prop : properties) {
            sheet.autoSizeColumn(colNum);
            colNum++;
        }
    }
}