001/*
002 * (C) Copyright 2014 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 */
019package org.nuxeo.ecm.platform.query.core;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.nuxeo.ecm.core.api.DocumentModel;
029import org.nuxeo.ecm.platform.query.api.Aggregate;
030import org.nuxeo.ecm.platform.query.api.AggregateDefinition;
031import org.nuxeo.ecm.platform.query.api.AggregateRangeDateDefinition;
032import org.nuxeo.ecm.platform.query.api.AggregateRangeDefinition;
033import org.nuxeo.ecm.platform.query.api.Bucket;
034import org.nuxeo.ecm.platform.query.api.PredicateFieldDefinition;
035
036import com.fasterxml.jackson.annotation.JsonIgnore;
037
038/**
039 * @since 6.0
040 */
041public class AggregateBase<B extends Bucket> implements Aggregate<B> {
042
043    protected final AggregateDefinition definition;
044
045    protected final DocumentModel searchDocument;
046
047    protected List<String> selection;
048
049    protected List<B> buckets;
050
051    protected List<Bucket> extendedBuckets;
052
053    protected Map<String, Bucket> bucketMap = null;
054
055    public AggregateBase(AggregateDefinition definition, DocumentModel searchDocument) {
056        assert (definition != null);
057        this.definition = definition;
058        this.searchDocument = searchDocument;
059    }
060
061    @Override
062    public String getId() {
063        return definition.getId();
064    }
065
066    @Override
067    public String getType() {
068        return definition.getType();
069    }
070
071    @Override
072    public String getField() {
073        return definition.getDocumentField();
074    }
075
076    @Override
077    public Map<String, String> getProperties() {
078        return definition.getProperties();
079    }
080
081    @Override
082    public List<AggregateRangeDefinition> getRanges() {
083        return definition.getRanges();
084    }
085
086    @Override
087    public List<AggregateRangeDateDefinition> getDateRanges() {
088        return definition.getDateRanges();
089    }
090
091    @SuppressWarnings("unchecked")
092    @Override
093    public List<String> getSelection() {
094        if (selection == null) {
095            PredicateFieldDefinition field = definition.getSearchField();
096            if (searchDocument != null) {
097                // property must be nxs:stringList
098                List<String> value = null;
099                Object resolvedProperties = searchDocument.getProperty(field.getSchema(), field.getName());
100                if (resolvedProperties instanceof String[]) {
101                    value = Arrays.asList((String[]) resolvedProperties);
102                } else if (resolvedProperties instanceof List<?>) {
103                    value = (List<String>) searchDocument.getProperty(field.getSchema(), field.getName());
104                }
105                selection = value;
106            }
107            if (selection == null) {
108                selection = Collections.<String> emptyList();
109            }
110        }
111        return selection;
112    }
113
114    @Override
115    public void setSelection(List<String> selection) {
116        this.selection = selection;
117    }
118
119    @Override
120    public List<B> getBuckets() {
121        return buckets;
122    }
123
124    @Override
125    public List<Bucket> getExtendedBuckets() {
126        if (extendedBuckets == null) {
127            extendedBuckets = new ArrayList<Bucket>();
128            final List<String> currentSelection = getSelection();
129            if (currentSelection != null) {
130                for (String s : currentSelection) {
131                    if (!hasBucket(s)) {
132                        extendedBuckets.add(new MockBucket(s));
133                    }
134                }
135            }
136            extendedBuckets.addAll(buckets);
137        }
138        return extendedBuckets;
139    }
140
141    @Override
142    public void setBuckets(List<B> buckets) {
143        this.buckets = buckets;
144        this.bucketMap = null;
145        this.extendedBuckets = null;
146    }
147
148    @JsonIgnore
149    public DocumentModel getSearchDocument() {
150        return searchDocument;
151    }
152
153    @Override
154    public String toString() {
155        return String.format("Aggregate(%s, %s, %s, %s, %s)", getId(), getType(), getField(),
156                (getSelection() != null) ? Arrays.toString(getSelection().toArray()) : null,
157                (buckets != null) ? Arrays.toString(buckets.toArray()) : null);
158    }
159
160    @Override
161    public boolean hasBucket(final String key) {
162        return getBucketMap().containsKey(key);
163    }
164
165    @Override
166    public Bucket getBucket(final String key) {
167        return getBucketMap().get(key);
168    }
169
170    public Map<String, Bucket> getBucketMap() {
171        if (bucketMap == null && getBuckets() != null) {
172            bucketMap = new HashMap<String, Bucket>();
173            for (Bucket b : getBuckets()) {
174                bucketMap.put(b.getKey(), b);
175            }
176        }
177        return bucketMap;
178    }
179
180    @Override
181    public void resetSelection() {
182        PredicateFieldDefinition field = definition.getSearchField();
183        if (searchDocument != null) {
184            searchDocument.setProperty(field.getSchema(), field.getName(), null);
185            selection = Collections.<String> emptyList();
186        }
187    }
188
189}