001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * 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, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package org.outerj.daisy.repository.serverimpl.query.facets;
017:
018: import java.util.Comparator;
019: import java.util.LinkedList;
020: import java.util.Locale;
021: import java.util.Map;
022: import java.util.PriorityQueue;
023: import java.util.Queue;
024: import java.util.SortedMap;
025: import java.util.TreeMap;
026:
027: import org.apache.commons.logging.Log;
028: import org.outerj.daisy.query.model.ValueExpr;
029: import org.outerj.daisy.repository.HierarchyPath;
030: import org.outerj.daisy.repository.RepositoryException;
031: import org.outerj.daisy.repository.ValueComparator;
032: import org.outerj.daisy.repository.query.FacetConf;
033: import org.outerj.daisy.repository.serverimpl.query.Counter;
034: import org.outerj.daisy.repository.serverimpl.query.Formatter;
035: import org.outerx.daisy.x10.FacetedQueryResultDocument;
036: import org.outerx.daisy.x10.FacetedQueryResultDocument.FacetedQueryResult.Facets.Facet;
037:
038: public abstract class AbstractFacetSampler implements FacetSampler {
039: protected FacetConf facetConf;
040:
041: protected Comparator<Object> comparator;
042:
043: protected Locale locale;
044:
045: protected int valueCount = 0;
046:
047: protected Log logger;
048:
049: protected int threshold = Integer.MAX_VALUE;
050:
051: protected AbstractFacetSampler(FacetConf facetConf, Locale locale,
052: Log logger) {
053: this .facetConf = facetConf;
054: this .locale = locale;
055: this .comparator = new ValueComparator<Object>(facetConf
056: .getSortAscending(), locale);
057: this .logger = logger;
058: Map<String, String> facetProperties = facetConf.getProperties();
059: if (facetProperties != null
060: && facetProperties.containsKey("threshold"))
061: threshold = Integer.parseInt(facetProperties
062: .get("threshold"));
063: }
064:
065: public static FacetSampler createFacetSampler(FacetConf facetConf,
066: Locale locale, Log logger) throws RepositoryException {
067: FacetSampler facetSampler;
068: switch (facetConf.getType()) {
069: case DATE:
070: facetSampler = new DateFacetSampler(facetConf, locale,
071: logger);
072: break;
073: case NUMBER:
074: facetSampler = new NumberFacetSampler(facetConf, locale,
075: logger);
076: break;
077: case STRING:
078: facetSampler = new StringFacetSampler(facetConf, locale,
079: logger);
080: break;
081: default:
082: facetSampler = new DummyFacetSampler(facetConf, locale,
083: logger);
084: }
085:
086: return facetSampler;
087: }
088:
089: protected SortedMap<Object, CountGroup> makeGroupCounts(
090: FacetValues facetValues, ValueExpr valueExpr,
091: Map<String, Formatter> formatters) {
092: SortedMap<Object, CountGroup> countGroups = new TreeMap<Object, CountGroup>(
093: comparator);
094: CountGroup countsObj;
095:
096: for (Map.Entry<Object, Counter> entry : facetValues.getValues()
097: .entrySet()) {
098: Object value = entry.getKey();
099: long counter = entry.getValue().getValue();
100: countsObj = countGroups.get(value);
101:
102: if (countsObj == null) {
103: countGroups.put(value, new CountGroup(this , value,
104: counter, valueExpr, formatters));
105: } else {
106: countsObj.addValue(value, counter);
107: }
108: }
109:
110: if (facetValues.getValues().size() > threshold
111: || (facetValues.getValues().size() > 1 && facetValues
112: .getValues().firstKey() instanceof HierarchyPath))
113: regroup(countGroups);
114:
115: return countGroups;
116: }
117:
118: public void valuesToXml(FacetValues facetValues, Facet facetXml,
119: ValueExpr valueExpr, Map<String, Formatter> formatters) {
120: Map<Object, CountGroup> countGroups = makeGroupCounts(
121: facetValues, valueExpr, formatters);
122: valueCount = 0;
123: Queue<CountGroup> sortedGroups = reorderGroups(countGroups);
124: facetXml.setAvailableValues(sortedGroups.size());
125:
126: CountGroup cg;
127: while ((cg = sortedGroups.poll()) != null
128: && (facetConf.getMaxValues() < 0 || valueCount < facetConf
129: .getMaxValues())) {
130: valueCount++;
131: FacetedQueryResultDocument.FacetedQueryResult.Facets.Facet.Value valueXml = facetXml
132: .addNewValue();
133:
134: if (cg.getMin().equals(cg.getMax())
135: || cg.getMin() instanceof HierarchyPath)
136: valueXml.setIsDiscrete(false);
137: else
138: valueXml.setIsDiscrete(true);
139:
140: valueXml.setUserFormat(cg.getUserValue());
141: valueXml.setQueryFormat(cg.getQueryValue());
142: valueXml.setCount(cg.getCount());
143: }
144: }
145:
146: protected abstract String createUserFormat(CountGroup group,
147: ValueExpr valueExpr, Formatter valueFormatter);
148:
149: protected abstract String createQueryFormat(CountGroup g,
150: ValueExpr valueExpr, Formatter queryFormatter);
151:
152: protected abstract void regroup(
153: SortedMap<Object, CountGroup> countGroups);
154:
155: public Comparator<Object> getComparator() {
156: return comparator;
157: }
158:
159: public int getValueCount() {
160: return valueCount;
161: }
162:
163: public Locale getLocale() {
164: return this .locale;
165: }
166:
167: private Queue<CountGroup> reorderGroups(
168: Map<Object, CountGroup> countGroups) {
169: Queue<CountGroup> sortedGroups;
170: if (countGroups.size() > 0) {
171: if (facetConf.getSortOnValue()) {
172: if (facetConf.getProperties()
173: .containsKey("sortValueOn")
174: && facetConf.getProperties().get("sortValueOn")
175: .equals("label")) {
176: sortedGroups = new PriorityQueue<CountGroup>(
177: countGroups.size(),
178: new GroupUserValueComparator(facetConf
179: .getSortAscending(), locale));
180: sortedGroups.addAll(countGroups.values());
181: } else {
182: sortedGroups = new LinkedList<CountGroup>(
183: countGroups.values());
184: }
185: } else {
186: sortedGroups = new PriorityQueue<CountGroup>(
187: countGroups.size(), new GroupCountComparator(
188: facetConf.getSortAscending()));
189: sortedGroups.addAll(countGroups.values());
190: }
191: } else {
192: sortedGroups = new LinkedList<CountGroup>();
193: }
194:
195: return sortedGroups;
196: }
197:
198: private class GroupCountComparator implements
199: Comparator<CountGroup> {
200: private boolean sortAscending;
201:
202: public GroupCountComparator(boolean sortAscending) {
203: this .sortAscending = sortAscending;
204: }
205:
206: public int compare(CountGroup o1, CountGroup o2) {
207: int result = (int) (o1.getCount() - o2.getCount());
208: return sortAscending ? result : result * -1;
209: }
210: }
211:
212: private class GroupUserValueComparator implements
213: Comparator<CountGroup> {
214: private Comparator<Object> delegate;
215:
216: public GroupUserValueComparator(boolean sortAscending,
217: Locale locale) {
218: this .delegate = new ValueComparator<Object>(sortAscending,
219: locale);
220: }
221:
222: public int compare(CountGroup o1, CountGroup o2) {
223: return delegate.compare(o1.getUserValue(), o2
224: .getUserValue());
225: }
226:
227: }
228:
229: }
|