001/*
002 * (C) Copyright 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 *     Gabriel Barata <gbarata@nuxeo.com>
018 */
019package org.nuxeo.ecm.platform.search.core;
020
021import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
022import static org.nuxeo.ecm.core.io.registry.MarshallingConstants.WILDCARD_VALUE;
023import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON;
024import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE;
025
026import java.io.Closeable;
027import java.io.IOException;
028import java.io.OutputStream;
029import java.util.Arrays;
030import java.util.Collection;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Iterator;
034import java.util.Map;
035import java.util.Set;
036
037import javax.inject.Inject;
038
039import org.nuxeo.ecm.core.api.DocumentModel;
040import org.nuxeo.ecm.core.api.model.Property;
041import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter;
042import org.nuxeo.ecm.core.io.marshallers.json.OutputStreamWithJsonWriter;
043import org.nuxeo.ecm.core.io.registry.Writer;
044import org.nuxeo.ecm.core.io.registry.reflect.Setup;
045import org.nuxeo.ecm.core.schema.SchemaManager;
046import org.nuxeo.ecm.core.schema.types.Field;
047import org.nuxeo.ecm.core.schema.types.Schema;
048
049import com.fasterxml.jackson.core.JsonGenerator;
050import org.nuxeo.runtime.api.Framework;
051
052/**
053 * @since 8.3
054 */
055@Setup(mode = SINGLETON, priority = REFERENCE)
056public class SavedSearchWriter extends ExtensibleEntityJsonWriter<SavedSearch> {
057
058    public static final String ENTITY_TYPE = "savedSearch";
059
060    @Inject
061    private SchemaManager schemaManager;
062
063    public SavedSearchWriter() {
064        super(ENTITY_TYPE, SavedSearch.class);
065    }
066
067    @Override
068    protected void writeEntityBody(SavedSearch search, JsonGenerator jg) throws IOException {
069        jg.writeStringField("id", search.getId());
070        jg.writeStringField("title", search.getTitle());
071        jg.writeStringField("queryParams", search.getQueryParams());
072        jg.writeStringField("query", search.getQuery());
073        jg.writeStringField("queryLanguage", search.getQueryLanguage());
074        jg.writeStringField("pageProviderName", search.getPageProviderName());
075        jg.writeStringField("pageSize", search.getPageSize() == null ? null : search.getPageSize().toString());
076        jg.writeStringField("currentPageIndex", search.getCurrentPageIndex() == null ? null
077                : search.getCurrentPageIndex().toString());
078        jg.writeStringField("maxResults", search.getMaxResults() == null ? null : search.getMaxResults().toString());
079        jg.writeStringField("sortBy", search.getSortBy());
080        jg.writeStringField("sortOrder", search.getSortOrder());
081        jg.writeStringField("contentViewData", search.getContentViewData());
082
083        Map<String, String> params = search.getNamedParams();
084        if (params == null) {
085            params = new HashMap<>();
086        }
087
088        jg.writeObjectFieldStart("params");
089        Iterator<String> it = params.keySet().iterator();
090        while (it.hasNext()) {
091            String param = it.next();
092            jg.writeStringField(param, search.getNamedParams().get(param));
093        }
094
095        // write own schema properties as search parameters (unprefixed)
096        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
097        DocumentModel doc = search.getDocument();
098        Set<String> ownSchemas = new HashSet<>(Arrays.asList(doc.getSchemas()));
099        doc.getFacets()
100           .stream()
101           .map(facet -> schemaManager.getFacet(facet).getSchemas())
102           .flatMap(Collection::stream)
103           .forEach(schema -> ownSchemas.remove(schema.getName()));
104        for (String schema : ownSchemas) {
105            writeSchemaProperties(jg, doc, schema, false);
106        }
107        jg.writeEndObject();
108
109        // write document model properties
110        Set<String> schemas = ctx.getProperties();
111        if (schemas.size() > 0) {
112            jg.writeObjectFieldStart("properties");
113            if (schemas.contains(WILDCARD_VALUE)) {
114                // full document
115                for (String schema : doc.getSchemas()) {
116                    writeSchemaProperties(jg, doc, schema);
117                }
118            } else {
119                for (String schema : schemas) {
120                    if (doc.hasSchema(schema)) {
121                        writeSchemaProperties(jg, doc, schema);
122                    }
123                }
124            }
125            jg.writeEndObject();
126        }
127    }
128
129    private void writeSchemaProperties(JsonGenerator jg, DocumentModel doc, String schemaName) throws IOException {
130        writeSchemaProperties(jg, doc, schemaName, true);
131    }
132
133    private void writeSchemaProperties(JsonGenerator jg, DocumentModel doc, String schemaName, boolean usePrefix)
134            throws IOException {
135        Writer<Property> propertyWriter = registry.getWriter(ctx, Property.class, APPLICATION_JSON_TYPE);
136        // provides the current document to the property marshaller
137        try (Closeable resource = ctx.wrap().with(ENTITY_TYPE, doc).open()) {
138            Schema schema = schemaManager.getSchema(schemaName);
139            String prefix = "";
140            if (usePrefix) {
141                prefix = schema.getNamespace().prefix;
142                if (prefix == null || prefix.length() == 0) {
143                    prefix = schemaName;
144                }
145                prefix = prefix + ":";
146            }
147            for (Field field : schema.getFields()) {
148                String prefixedName = prefix + field.getName().getLocalName();
149                jg.writeFieldName(prefixedName);
150                Property property = doc.getProperty(prefixedName);
151                OutputStream out = new OutputStreamWithJsonWriter(jg);
152                propertyWriter.write(property, Property.class, Property.class, APPLICATION_JSON_TYPE, out);
153            }
154        }
155    }
156}