001/*
002 * (C) Copyright 2014-2016 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 *     Benoit Delbosc
018 *     Florent Guillaume
019 */
020package org.nuxeo.elasticsearch.io;
021
022import java.io.Serializable;
023import java.util.Collections;
024import java.util.HashSet;
025import java.util.List;
026import java.util.Map;
027import java.util.Set;
028
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031import org.elasticsearch.common.bytes.BytesArray;
032import org.elasticsearch.search.lookup.SourceLookup;
033import org.nuxeo.common.utils.Path;
034import org.nuxeo.ecm.core.api.CoreSession;
035import org.nuxeo.ecm.core.api.DocumentModel;
036import org.nuxeo.ecm.core.api.DocumentModelFactory;
037import org.nuxeo.ecm.core.api.DocumentRef;
038import org.nuxeo.ecm.core.api.IdRef;
039import org.nuxeo.ecm.core.api.PropertyException;
040import org.nuxeo.ecm.core.api.impl.DocumentModelImpl;
041import org.nuxeo.ecm.core.schema.DocumentType;
042import org.nuxeo.ecm.core.schema.FacetNames;
043import org.nuxeo.ecm.core.schema.SchemaManager;
044import org.nuxeo.ecm.core.schema.types.Schema;
045import org.nuxeo.runtime.api.Framework;
046
047/**
048 * Read a DocumentModel from an ES Json export.
049 *
050 * @since 5.9.5
051 */
052public class JsonDocumentModelReader {
053    private static final Log log = LogFactory.getLog(JsonDocumentModelReader.class);
054
055    private final Map<String, Object> source;
056
057    private String sid;
058
059    public JsonDocumentModelReader(String json) {
060        byte[] bytes = json.getBytes();
061        source = SourceLookup.sourceAsMap(new BytesArray(bytes, 0, bytes.length));
062    }
063
064    public JsonDocumentModelReader(Map<String, Object> source) {
065        this.source = source;
066    }
067
068    public JsonDocumentModelReader session(CoreSession session) {
069        sid = session.getSessionId();
070        return this;
071    }
072
073    public JsonDocumentModelReader sid(String sid) {
074        this.sid = sid;
075        return this;
076    }
077
078    public DocumentModel getDocumentModel() {
079        assert (source != null);
080        String type = (String) getProperty("ecm:primaryType");
081        @SuppressWarnings("unchecked")
082        List<String> mixinTypes = (List<String>) getProperty("ecm:mixinType");
083        String id = (String) getProperty("ecm:uuid");
084        String path = (String) getProperty("ecm:path");
085        String parentId = (String) getProperty("ecm:parentId");
086        String repositoryName = (String) getProperty("ecm:repository");
087        boolean isProxy = Boolean.TRUE.equals(getProperty("ecm:isProxy"));
088        String sourceId = null; // TODO write this in JsonESDocumentWriter
089
090        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
091        DocumentType docType = schemaManager.getDocumentType(type);
092
093        // fixup facets, keep only instance facets
094        Set<String> facets = new HashSet<>(mixinTypes == null ? Collections.emptyList() : mixinTypes);
095        facets.remove(FacetNames.IMMUTABLE); // system facet
096        facets.removeAll(docType.getFacets());
097
098        Path pathObj = path == null ? null : new Path(path);
099        DocumentRef docRef = new IdRef(id);
100        DocumentRef parentRef = parentId == null ? null : new IdRef(parentId);
101        DocumentModelImpl doc = new DocumentModelImpl(sid, type, id, pathObj, docRef, parentRef, null, facets, sourceId,
102                repositoryName, isProxy);
103
104        // preload DataModel to prevent DB access
105        for (String schemaName : doc.getSchemas()) { // all schemas including from facets
106            Schema schema = schemaManager.getSchema(schemaName);
107            doc.addDataModel(DocumentModelFactory.createDataModel(null, schema));
108        }
109
110        for (String prop : source.keySet()) {
111            String schema = prop.split(":")[0];
112            Serializable value = getProperty(prop);
113            if (value == null) {
114                continue;
115            }
116            if ("ecm".equals(schema)) {
117                switch (prop) {
118                case "ecm:currentLifeCycleState":
119                    doc.prefetchCurrentLifecycleState((String) value);
120                    break;
121                default:
122                    // others not taken in account
123                }
124                continue;
125            }
126            // regular property
127            try {
128                doc.setPropertyValue(prop, value);
129            } catch (PropertyException e) {
130                if (log.isDebugEnabled()) {
131                    log.debug(String.format("fetchDocFromEs cannot set property %s to %s", prop, value));
132                }
133            }
134        }
135        doc.setIsImmutable(true);
136        return doc;
137    }
138
139    protected Serializable getProperty(String name) {
140        return (Serializable) source.get(name);
141    }
142
143}