001/*
002 * (C) Copyright 2012-2018 Nuxeo (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 *     Thomas Roger
018 */
019
020package org.nuxeo.ecm.csv.core;
021
022import static org.nuxeo.ecm.core.api.CoreSession.IMPORT_LIFECYCLE_STATE;
023import static org.nuxeo.ecm.core.api.LifeCycleConstants.INITIAL_LIFECYCLE_STATE_OPTION_NAME;
024
025import java.io.Serializable;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.Collections;
029import java.util.List;
030import java.util.Map;
031import java.util.UUID;
032
033import org.apache.commons.lang3.StringUtils;
034import org.nuxeo.common.utils.Path;
035import org.nuxeo.ecm.core.api.CoreSession;
036import org.nuxeo.ecm.core.api.DocumentModel;
037import org.nuxeo.ecm.core.api.DocumentRef;
038import org.nuxeo.ecm.core.api.NuxeoException;
039import org.nuxeo.ecm.core.api.PathRef;
040import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
041import org.nuxeo.ecm.core.query.sql.NXQL;
042import org.nuxeo.ecm.csv.core.CSVImporterOptions.ImportMode;
043
044/**
045 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
046 * @since 5.7
047 */
048public class DefaultCSVImporterDocumentFactory implements CSVImporterDocumentFactory {
049
050    private static final long serialVersionUID = 1L;
051
052    public static final String DC_CREATOR = "dc:creator";
053
054    public static final String DC_CONTRIBUTORS = "dc:contributors";
055
056    public static final List<String> IGNORE_FIELDS_ON_UPDATE = Collections.singletonList(NXQL.ECM_LIFECYCLESTATE);
057
058    protected CSVImporterOptions importerOptions = CSVImporterOptions.DEFAULT_OPTIONS;
059
060    @Override
061    public void createDocument(CoreSession session, String parentPath, String name, String type,
062            Map<String, Serializable> values) {
063        values = prepareValues(values);
064        DocumentModel doc = session.createDocumentModel(parentPath, name, type);
065
066        if (importerOptions.importMode.equals(ImportMode.IMPORT)) {
067            setLifeCycleState(values, doc, IMPORT_LIFECYCLE_STATE);
068            if (values.containsKey(NXQL.ECM_UUID)) {
069                ((DocumentModelImpl) doc).setId((String) values.get(NXQL.ECM_UUID));
070                values.remove(NXQL.ECM_UUID);
071            } else {
072                ((DocumentModelImpl) doc).setId(UUID.randomUUID().toString());
073            }
074            for (Map.Entry<String, Serializable> entry : values.entrySet()) {
075                doc.setPropertyValue(entry.getKey(), entry.getValue());
076            }
077            session.importDocuments(Collections.singletonList(doc));
078        } else {
079            setLifeCycleState(values, doc, INITIAL_LIFECYCLE_STATE_OPTION_NAME);
080            if (values.containsKey(NXQL.ECM_UUID)) {
081                throw new NuxeoException("CSV file contains UUID. Import using Import Mode to avoid overwriting.");
082            }
083            for (Map.Entry<String, Serializable> entry : values.entrySet()) {
084                doc.setPropertyValue(entry.getKey(), entry.getValue());
085            }
086            session.createDocument(doc);
087        }
088    }
089
090    protected void setLifeCycleState(Map<String, Serializable> values, DocumentModel doc, String lifeCyclePropertyName) {
091        if (values.containsKey(NXQL.ECM_LIFECYCLESTATE)) {
092            doc.putContextData(lifeCyclePropertyName, values.get(NXQL.ECM_LIFECYCLESTATE));
093            values.remove(NXQL.ECM_LIFECYCLESTATE);
094        }
095    }
096
097    protected Map<String, Serializable> prepareValues(Map<String, Serializable> values) {
098        if (values.containsKey(DC_CREATOR)) {
099            // make sure the creator is part of the contributors
100            String creator = (String) values.get(DC_CREATOR);
101            String[] contributorsArray = (String[]) values.get(DC_CONTRIBUTORS);
102            List<String> contributors = contributorsArray == null ? new ArrayList<>()
103                    : new ArrayList<>(Arrays.asList(contributorsArray));
104            if (StringUtils.isNotBlank(creator) && !contributors.contains(creator)) {
105                contributors.add(creator);
106            }
107            values.put(DC_CONTRIBUTORS, contributors.toArray(new String[contributors.size()]));
108        }
109        return values;
110    }
111
112    @Override
113    public void updateDocument(CoreSession session, DocumentRef docRef, Map<String, Serializable> values) {
114        DocumentModel doc = session.getDocument(docRef);
115        for (Map.Entry<String, Serializable> entry : values.entrySet()) {
116            if (!IGNORE_FIELDS_ON_UPDATE.contains(entry.getKey())) {
117                doc.setPropertyValue(entry.getKey(), entry.getValue());
118            }
119        }
120        session.saveDocument(doc);
121    }
122
123    @Override
124    public boolean exists(CoreSession session, String parentPath, String name, Map<String, Serializable> values) {
125        String targetPath = new Path(parentPath).append(name).toString();
126        DocumentRef docRef = new PathRef(targetPath);
127        return session.exists(docRef);
128    }
129
130    @Override
131    @Deprecated
132    public boolean exists(CoreSession session, String parentPath, String name, String type,
133            Map<String, Serializable> values) {
134        return exists(session, parentPath, name, null);
135    }
136
137    @Override
138    public void setImporterOptions(CSVImporterOptions importerOptions) {
139        this.importerOptions = importerOptions;
140    }
141
142}