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