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