001/*
002 * (C) Copyright 2014 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Benoit Delbosc
016 */
017package org.nuxeo.ecm.platform.query.core;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.codehaus.jackson.annotate.JsonIgnore;
027import org.nuxeo.ecm.core.api.DocumentModel;
028import org.nuxeo.ecm.platform.query.api.Aggregate;
029import org.nuxeo.ecm.platform.query.api.AggregateDefinition;
030import org.nuxeo.ecm.platform.query.api.AggregateRangeDateDefinition;
031import org.nuxeo.ecm.platform.query.api.AggregateRangeDefinition;
032import org.nuxeo.ecm.platform.query.api.Bucket;
033import org.nuxeo.ecm.platform.query.api.PredicateFieldDefinition;
034
035/**
036 * @since 6.0
037 */
038public class AggregateBase<B extends Bucket> implements Aggregate<B> {
039
040    protected final AggregateDefinition definition;
041
042    protected final DocumentModel searchDocument;
043
044    protected List<String> selection;
045
046    protected List<B> buckets;
047
048    protected List<Bucket> extendedBuckets;
049
050    protected Map<String, Bucket> bucketMap = null;
051
052    public AggregateBase(AggregateDefinition definition, DocumentModel searchDocument) {
053        assert (definition != null);
054        this.definition = definition;
055        this.searchDocument = searchDocument;
056    }
057
058    @Override
059    public String getId() {
060        return definition.getId();
061    }
062
063    @Override
064    public String getType() {
065        return definition.getType();
066    }
067
068    @Override
069    public String getField() {
070        return definition.getDocumentField();
071    }
072
073    @Override
074    public Map<String, String> getProperties() {
075        return definition.getProperties();
076    }
077
078    @Override
079    public List<AggregateRangeDefinition> getRanges() {
080        return definition.getRanges();
081    }
082
083    @Override
084    public List<AggregateRangeDateDefinition> getDateRanges() {
085        return definition.getDateRanges();
086    }
087
088    @SuppressWarnings("unchecked")
089    @Override
090    public List<String> getSelection() {
091        if (selection == null) {
092            PredicateFieldDefinition field = definition.getSearchField();
093            if (searchDocument != null) {
094                // property must be nxs:stringList
095                List<String> value = null;
096                Object resolvedProperties = searchDocument.getProperty(field.getSchema(), field.getName());
097                if (resolvedProperties instanceof String[]) {
098                    value = Arrays.asList((String[]) resolvedProperties);
099                } else if (resolvedProperties instanceof List<?>) {
100                    value = (List<String>) searchDocument.getProperty(field.getSchema(), field.getName());
101                }
102                selection = value;
103            }
104            if (selection == null) {
105                selection = Collections.<String> emptyList();
106            }
107        }
108        return selection;
109    }
110
111    @Override
112    public void setSelection(List<String> selection) {
113        this.selection = selection;
114    }
115
116    @Override
117    public List<B> getBuckets() {
118        return buckets;
119    }
120
121    @Override
122    public List<Bucket> getExtendedBuckets() {
123        if (extendedBuckets == null) {
124            extendedBuckets = new ArrayList<Bucket>();
125            final List<String> currentSelection = getSelection();
126            if (currentSelection != null) {
127                for (String s : currentSelection) {
128                    if (!hasBucket(s)) {
129                        extendedBuckets.add(new MockBucket(s));
130                    }
131                }
132            }
133            extendedBuckets.addAll(buckets);
134        }
135        return extendedBuckets;
136    }
137
138    @Override
139    public void setBuckets(List<B> buckets) {
140        this.buckets = buckets;
141        this.bucketMap = null;
142        this.extendedBuckets = null;
143    }
144
145    @JsonIgnore
146    public DocumentModel getSearchDocument() {
147        return searchDocument;
148    }
149
150    @Override
151    public String toString() {
152        return String.format("Aggregate(%s, %s, %s, %s, %s)", getId(), getType(), getField(),
153                (getSelection() != null) ? Arrays.toString(getSelection().toArray()) : null,
154                (buckets != null) ? Arrays.toString(buckets.toArray()) : null);
155    }
156
157    @Override
158    public boolean hasBucket(final String key) {
159        return getBucketMap().containsKey(key);
160    }
161
162    @Override
163    public Bucket getBucket(final String key) {
164        return getBucketMap().get(key);
165    }
166
167    public Map<String, Bucket> getBucketMap() {
168        if (bucketMap == null && getBuckets() != null) {
169            bucketMap = new HashMap<String, Bucket>();
170            for (Bucket b : getBuckets()) {
171                bucketMap.put(b.getKey(), b);
172            }
173        }
174        return bucketMap;
175    }
176
177    @Override
178    public void resetSelection() {
179        PredicateFieldDefinition field = definition.getSearchField();
180        if (searchDocument != null) {
181            searchDocument.setProperty(field.getSchema(), field.getName(), null);
182            selection = Collections.<String> emptyList();
183        }
184    }
185
186}