001/*
002 * (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *     Thibaud Arguillere (Nuxeo)
017 *
018 * $Id$
019 */
020
021package org.nuxeo.ecm.platform.importer.factories;
022
023import java.io.IOException;
024import java.io.Serializable;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029
030import org.apache.commons.lang.StringUtils;
031import org.nuxeo.ecm.core.api.CoreSession;
032import org.nuxeo.ecm.core.api.DocumentModel;
033import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
034import org.nuxeo.ecm.platform.importer.source.SourceNode;
035
036/**
037 * Default implementation for DocumentModel factory The default empty constructor create Folder for folderish file and
038 * File for other. But you can specify them using the other constructor. Also, if you are using .properties files to
039 * setup metada, you can use the ecm:primaryType xpath to specify the type of document to create. This will override the
040 * default ones, and works for files and folders. If no .properties file is provided of it the current node has a
041 * .properties file but no ecm:primaryType, the default types are created. This works for leafType but also for
042 * folderish type.
043 *
044 * @author Thierry Delprat
045 * @author Daniel Tellez
046 * @author Thibaud Arguillere
047 */
048public class DefaultDocumentModelFactory extends AbstractDocumentModelFactory {
049
050    public static final String DOCTYPE_KEY_NAME = "ecm:primaryType";
051
052    public static final String FACETS_KEY_NAME = "ecm:mixinTypes";
053
054    protected String folderishType;
055
056    protected String leafType;
057
058    /**
059     * Instantiate a DefaultDocumentModelFactory that creates Folder and File
060     */
061    public DefaultDocumentModelFactory() {
062        this("Folder", "File");
063    }
064
065    /**
066     * Instantiate a DefaultDocumentModelFactory that creates specified types doc
067     *
068     * @param folderishType the folderish type
069     * @param leafType the other type
070     */
071    public DefaultDocumentModelFactory(String folderishType, String leafType) {
072        this.folderishType = folderishType;
073        this.leafType = leafType;
074    }
075
076    /*
077     * (non-Javadoc)
078     * @seeorg.nuxeo.ecm.platform.importer.base.ImporterDocumentModelFactory#
079     * createFolderishNode(org.nuxeo.ecm.core.api.CoreSession, org.nuxeo.ecm.core.api.DocumentModel,
080     * org.nuxeo.ecm.platform.importer.base.SourceNode)
081     */
082    @Override
083    public DocumentModel createFolderishNode(CoreSession session, DocumentModel parent, SourceNode node)
084            throws IOException {
085
086        String name = getValidNameFromFileName(node.getName());
087
088        BlobHolder bh = node.getBlobHolder();
089        String folderishTypeToUse = getDocTypeToUse(bh);
090        if (folderishTypeToUse == null) {
091            folderishTypeToUse = folderishType;
092        }
093        List<String> facets = getFacetsToUse(bh);
094
095        DocumentModel doc = session.createDocumentModel(parent.getPathAsString(), name, folderishTypeToUse);
096        for (String facet : facets) {
097            doc.addFacet(facet);
098        }
099        doc.setProperty("dublincore", "title", node.getName());
100        doc = session.createDocument(doc);
101
102        if (bh != null) {
103            doc = setDocumentProperties(session, bh.getProperties(), doc);
104        }
105
106        return doc;
107    }
108
109    /*
110     * (non-Javadoc)
111     * @seeorg.nuxeo.ecm.platform.importer.base.ImporterDocumentModelFactory#
112     * createLeafNode(org.nuxeo.ecm.core.api.CoreSession, org.nuxeo.ecm.core.api.DocumentModel,
113     * org.nuxeo.ecm.platform.importer.base.SourceNode)
114     */
115    @Override
116    public DocumentModel createLeafNode(CoreSession session, DocumentModel parent, SourceNode node) throws IOException {
117        return defaultCreateLeafNode(session, parent, node);
118    }
119
120    protected DocumentModel defaultCreateLeafNode(CoreSession session, DocumentModel parent, SourceNode node)
121            throws IOException {
122
123        BlobHolder bh = node.getBlobHolder();
124        String leafTypeToUse = getDocTypeToUse(bh);
125        if (leafTypeToUse == null) {
126            leafTypeToUse = leafType;
127        }
128        List<String> facets = getFacetsToUse(bh);
129
130        String mimeType = bh.getBlob().getMimeType();
131        if (mimeType == null) {
132            mimeType = getMimeType(node.getName());
133        }
134
135        String name = getValidNameFromFileName(node.getName());
136        String fileName = node.getName();
137
138        DocumentModel doc = session.createDocumentModel(parent.getPathAsString(), name, leafTypeToUse);
139        for (String facet : facets) {
140            doc.addFacet(facet);
141        }
142        doc.setProperty("dublincore", "title", node.getName());
143        doc.setProperty("file", "filename", fileName);
144        doc.setProperty("file", "content", bh.getBlob());
145
146        doc = session.createDocument(doc);
147
148        if (bh != null) {
149            doc = setDocumentProperties(session, bh.getProperties(), doc);
150        }
151
152        return doc;
153    }
154
155    /*
156     * Return null if DOCTYPE_KEY_NAME is not in the properties or has been set to nothing.
157     */
158    protected String getDocTypeToUse(BlobHolder inBH) {
159        String type = null;
160
161        if (inBH != null) {
162            Map<String, Serializable> props = inBH.getProperties();
163            if (props != null) {
164                type = (String) props.get(DOCTYPE_KEY_NAME);
165                if (type != null && type.isEmpty()) {
166                    type = null;
167                }
168            }
169        }
170
171        return type;
172    }
173
174    protected List<String> getFacetsToUse(BlobHolder inBH) {
175        if (inBH != null) {
176            Map<String, Serializable> props = inBH.getProperties();
177            if (props != null) {
178                Serializable ob = props.get(FACETS_KEY_NAME);
179                if (ob instanceof String) {
180                    String facet = (String) ob;
181                    if (StringUtils.isNotBlank(facet)) {
182                        return Collections.singletonList(facet);
183                    }
184                } else if (ob != null) {
185                    return (List<String>) ob;
186                }
187            }
188        }
189        return Collections.emptyList();
190    }
191
192    /** Modify this to get right mime types depending on the file input */
193    protected String getMimeType(String name) {
194        // Dummy MimeType detection : plug nuxeo Real MimeType service to
195        // have better results
196
197        if (name == null) {
198            return "application/octet-stream";
199            /* OpenOffice.org 2.x document types */
200        } else if (name.endsWith(".odp")) {
201            return "application/vnd.oasis.opendocument.presentation";
202        } else if (name.endsWith(".otp")) {
203            return "application/vnd.oasis.opendocument.presentation-template";
204        } else if (name.endsWith(".otg")) {
205            return "application/vnd.oasis.opendocument.graphics-template";
206        } else if (name.endsWith(".odg")) {
207            return "application/vnd.oasis.opendocument.graphics";
208        } else if (name.endsWith(".odt")) {
209            return "application/vnd.oasis.opendocument.text";
210        } else if (name.endsWith(".ott")) {
211            return "application/vnd.oasis.opendocument.text-template";
212        } else if (name.endsWith(".ods")) {
213            return "application/vnd.oasis.opendocument.spreadsheet";
214        } else if (name.endsWith(".ots")) {
215            return "application/vnd.oasis.opendocument.spreadsheet-template";
216            /* Microsoft Office document */
217        } else if (name.endsWith(".doc")) {
218            return "application/msword";
219        } else if (name.endsWith(".xls")) {
220            return "application/vnd.ms-excel";
221        } else if (name.endsWith(".ppt")) {
222            return "application/vnd.ms-powerpoint";
223            /* Ms Office 2007 */
224        } else if (name.endsWith(".xlsx")) {
225            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
226        } else if (name.endsWith(".pptx")) {
227            return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
228        } else if (name.endsWith(".docx")) {
229            return "application/vnd.openxmlformats-officedocument.wordprocessingml.template";
230            /* Other */
231        } else if (name.endsWith(".tar")) {
232            return "application/x-gtar";
233        } else if (name.endsWith(".gz")) {
234            return "application/x-gtar";
235        } else if (name.endsWith(".csv")) {
236            return "text/csv";
237        } else if (name.endsWith(".pdf")) {
238            return "application/pdf";
239        } else if (name.endsWith(".txt")) {
240            return "text/plain";
241        } else if (name.endsWith(".html")) {
242            return "text/html";
243        } else if (name.endsWith(".xml")) {
244            return "text/xml";
245        } else if (name.endsWith(".png")) {
246            return "image/png";
247        } else if (name.endsWith(".jpg")) {
248            return "image/jpg";
249        } else if (name.endsWith(".jpeg")) {
250            return "image/jpeg";
251        } else if (name.endsWith(".gif")) {
252            return "image/gif";
253        } else if (name.endsWith(".zip")) {
254            return "application/zip";
255        } else {
256            return "application/octet-stream";
257        }
258    }
259
260    public void setFolderishType(String folderishType) {
261        this.folderishType = folderishType;
262    }
263
264    public void setLeafType(String leafType) {
265        this.leafType = leafType;
266    }
267
268}