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 CoreSession coreSession;
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        this.coreSession = session;
070        return this;
071    }
072
073    public DocumentModel getDocumentModel() {
074        assert (source != null);
075        String type = (String) getProperty("ecm:primaryType");
076        @SuppressWarnings("unchecked")
077        List<String> mixinTypes = (List<String>) getProperty("ecm:mixinType");
078        String id = (String) getProperty("ecm:uuid");
079        String path = (String) getProperty("ecm:path");
080        String parentId = (String) getProperty("ecm:parentId");
081        String repositoryName = (String) getProperty("ecm:repository");
082        boolean isProxy = Boolean.TRUE.equals(getProperty("ecm:isProxy"));
083        String sourceId = null; // TODO write this in JsonESDocumentWriter
084
085        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
086        DocumentType docType = schemaManager.getDocumentType(type);
087
088        // fixup facets, keep only instance facets
089        Set<String> facets = new HashSet<>(mixinTypes == null ? Collections.emptyList() : mixinTypes);
090        facets.remove(FacetNames.IMMUTABLE); // system facet
091        facets.removeAll(docType.getFacets());
092
093        Path pathObj = path == null ? null : new Path(path);
094        DocumentRef docRef = new IdRef(id);
095        DocumentRef parentRef = parentId == null ? null : new IdRef(parentId);
096        DocumentModelImpl doc = new DocumentModelImpl(type, id, pathObj, docRef, parentRef, null, facets, sourceId,
097                isProxy, coreSession, repositoryName, null);
098
099        // preload DataModel to prevent DB access
100        for (String schemaName : doc.getSchemas()) { // all schemas including from facets
101            Schema schema = schemaManager.getSchema(schemaName);
102            doc.addDataModel(DocumentModelFactory.createDataModel(null, schema));
103        }
104
105        for (String prop : source.keySet()) {
106            String schema = prop.split(":")[0];
107            Serializable value = getProperty(prop);
108            if (value == null) {
109                continue;
110            }
111            if ("ecm".equals(schema)) {
112                switch (prop) {
113                case "ecm:currentLifeCycleState":
114                    doc.prefetchCurrentLifecycleState((String) value);
115                    break;
116                default:
117                    // others not taken in account
118                }
119                continue;
120            }
121            // regular property
122            try {
123                doc.setPropertyValue(prop, value);
124            } catch (PropertyException e) {
125                if (log.isDebugEnabled()) {
126                    log.debug(String.format("fetchDocFromEs cannot set property %s to %s", prop, value));
127                }
128            }
129        }
130        doc.setIsImmutable(true);
131        return doc;
132    }
133
134    protected Serializable getProperty(String name) {
135        return (Serializable) source.get(name);
136    }
137
138}