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 * Guillaume Renard <grenard@nuxeo.com> 018 */ 019package org.nuxeo.elasticsearch.io.marshallers.json; 020 021import static org.nuxeo.ecm.core.io.registry.MarshallingConstants.FETCH_PROPERTIES; 022import static org.nuxeo.ecm.core.io.registry.MarshallingConstants.MAX_DEPTH_PARAM; 023import static org.nuxeo.ecm.core.io.registry.MarshallingConstants.TRANSLATE_PROPERTIES; 024import static org.nuxeo.ecm.core.io.registry.reflect.Instantiations.SINGLETON; 025import static org.nuxeo.ecm.core.io.registry.reflect.Priorities.REFERENCE; 026 027import java.io.Closeable; 028import java.io.IOException; 029import java.lang.reflect.Type; 030import java.util.List; 031 032import javax.inject.Inject; 033import javax.ws.rs.core.MediaType; 034 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037import org.codehaus.jackson.JsonGenerationException; 038import org.codehaus.jackson.JsonGenerator; 039import org.nuxeo.ecm.core.api.model.Property; 040import org.nuxeo.ecm.core.api.model.impl.DocumentPartImpl; 041import org.nuxeo.ecm.core.api.model.impl.PropertyFactory; 042import org.nuxeo.ecm.core.io.marshallers.json.ExtensibleEntityJsonWriter; 043import org.nuxeo.ecm.core.io.marshallers.json.document.DocumentModelJsonWriter; 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.ListType; 048import org.nuxeo.ecm.core.schema.types.Schema; 049import org.nuxeo.ecm.core.schema.utils.DateParser; 050import org.nuxeo.ecm.directory.io.DirectoryEntryJsonWriter; 051import org.nuxeo.ecm.platform.query.api.Aggregate; 052import org.nuxeo.ecm.platform.query.api.Bucket; 053import org.nuxeo.ecm.platform.query.core.BucketRange; 054import org.nuxeo.ecm.platform.query.core.BucketRangeDate; 055import org.nuxeo.elasticsearch.aggregate.SignificantTermAggregate; 056import org.nuxeo.elasticsearch.aggregate.TermAggregate; 057 058/** 059 * @since 8.4 060 */ 061@SuppressWarnings("rawtypes") 062@Setup(mode = SINGLETON, priority = REFERENCE) 063public class AggregateJsonWriter extends ExtensibleEntityJsonWriter<Aggregate> { 064 065 private static final Log log = LogFactory.getLog(AggregateJsonWriter.class); 066 067 public static final String ENTITY_TYPE = "aggregate"; 068 069 public static final String FETCH_KEY = "key"; 070 071 @Inject 072 private SchemaManager schemaManager; 073 074 public AggregateJsonWriter() { 075 super(ENTITY_TYPE, Aggregate.class); 076 } 077 078 public AggregateJsonWriter(String entityType, Class<Aggregate> entityClass) { 079 super(entityType, entityClass); 080 } 081 082 @Override 083 public boolean accept(Class<?> clazz, Type genericType, MediaType mediatype) { 084 return true; 085 } 086 087 @SuppressWarnings("unchecked") 088 @Override 089 protected void writeEntityBody(Aggregate agg, JsonGenerator jg) throws IOException { 090 boolean fetch = ctx.getFetched(ENTITY_TYPE).contains(FETCH_KEY); 091 jg.writeObjectField("id", agg.getId()); 092 jg.writeObjectField("field", agg.getField()); 093 jg.writeObjectField("properties", agg.getProperties()); 094 jg.writeObjectField("ranges", agg.getRanges()); 095 jg.writeObjectField("selection", agg.getSelection()); 096 jg.writeObjectField("type", agg.getType()); 097 if (!fetch || !(agg instanceof TermAggregate || agg instanceof SignificantTermAggregate)) { 098 jg.writeObjectField("buckets", agg.getBuckets()); 099 jg.writeObjectField("extendedBuckets", agg.getExtendedBuckets()); 100 } else { 101 String fieldName = agg.getField(); 102 Field field = schemaManager.getField(fieldName); 103 if (field != null) { 104 try (Closeable resource = ctx.wrap() 105 .with(FETCH_PROPERTIES + "." + DocumentModelJsonWriter.ENTITY_TYPE, 106 "properties") 107 .with(FETCH_PROPERTIES + "." + DirectoryEntryJsonWriter.ENTITY_TYPE, 108 "parent") 109 .with(TRANSLATE_PROPERTIES + "." + DirectoryEntryJsonWriter.ENTITY_TYPE, 110 "label") 111 .with(MAX_DEPTH_PARAM, "max") 112 .open()) { 113 114 writeBuckets("buckets", agg.getBuckets(), field, jg); 115 writeBuckets("extendedBuckets", agg.getExtendedBuckets(), field, jg); 116 } 117 } else { 118 log.warn(String.format("Could not resolve field %s for aggrgeate %s", fieldName, agg.getId())); 119 jg.writeObjectField("buckets", agg.getBuckets()); 120 jg.writeObjectField("extendedBuckets", agg.getExtendedBuckets()); 121 } 122 } 123 } 124 125 protected void writeBuckets(String fieldName, List<Bucket> buckets, Field field, JsonGenerator jg) 126 throws IOException, JsonGenerationException { 127 // prepare document part in order to use property 128 Schema schema = field.getDeclaringType().getSchema(); 129 DocumentPartImpl part = new DocumentPartImpl(schema); 130 // write data 131 jg.writeArrayFieldStart(fieldName); 132 for (Bucket bucket : buckets) { 133 jg.writeStartObject(); 134 135 jg.writeObjectField("key", bucket.getKey()); 136 137 Property prop = PropertyFactory.createProperty(part, field, Property.NONE); 138 if (prop.isList()) { 139 ListType t = (ListType) prop.getType(); 140 t.getField(); 141 prop = PropertyFactory.createProperty(part, t.getField(), Property.NONE); 142 } 143 log.debug(String.format("Writing %s for field %s resolved to %s", fieldName, field.getName().toString(), 144 prop.getName())); 145 prop.setValue(bucket.getKey()); 146 147 writeEntityField("fetchedKey", prop, jg); 148 jg.writeNumberField("docCount", bucket.getDocCount()); 149 jg.writeEndObject(); 150 151 if (bucket instanceof BucketRange) { 152 BucketRange bucketRange = (BucketRange) bucket; 153 jg.writeNumberField("from", bucketRange.getFrom()); 154 jg.writeNumberField("to", bucketRange.getTo()); 155 } 156 157 if (bucket instanceof BucketRangeDate) { 158 BucketRangeDate bucketRange = (BucketRangeDate) bucket; 159 jg.writeStringField("fromAsDate", DateParser.formatW3CDateTime(bucketRange.getFromAsDate().toDate())); 160 jg.writeStringField("toAsDate", DateParser.formatW3CDateTime(bucketRange.getToAsDate().toDate())); 161 } 162 } 163 jg.writeEndArray(); 164 } 165 166}