001 package org.mycore.frontend.indexbrowser.lucene;
002
003 import java.util.ArrayList;
004 import java.util.Iterator;
005 import java.util.LinkedList;
006 import java.util.List;
007 import java.util.StringTokenizer;
008
009 import org.apache.log4j.Logger;
010 import org.jdom.output.XMLOutputter;
011 import org.mycore.parsers.bool.MCRAndCondition;
012 import org.mycore.parsers.bool.MCRCondition;
013 import org.mycore.parsers.bool.MCROrCondition;
014 import org.mycore.services.fieldquery.MCRCachedQueryData;
015 import org.mycore.services.fieldquery.MCRFieldDef;
016 import org.mycore.services.fieldquery.MCRFieldValue;
017 import org.mycore.services.fieldquery.MCRHit;
018 import org.mycore.services.fieldquery.MCRQuery;
019 import org.mycore.services.fieldquery.MCRQueryCondition;
020 import org.mycore.services.fieldquery.MCRQueryManager;
021 import org.mycore.services.fieldquery.MCRResults;
022 import org.mycore.services.fieldquery.MCRSortBy;
023
024 /**
025 * Searcher class for the index browser. Creates a list of MCRIndexBrowserEntries
026 * which contains the results of the search.
027 * <p>
028 * This class is excluded from MCRIndexBrowserData.
029 * </p>
030 * @author Matthias Eichner
031 *
032 */
033 public class MCRIndexBrowserSearcher {
034
035 protected static Logger LOGGER = Logger.getLogger(MCRIndexBrowserSearcher.class);
036
037 protected MCRIndexBrowserIncomingData browseData;
038 protected MCRIndexBrowserConfig indexConfig;
039
040 protected MCRQuery query;
041 protected MCRResults results;
042
043 protected List<MCRIndexBrowserEntry> hitList;
044
045 public MCRIndexBrowserSearcher(MCRIndexBrowserIncomingData browseData, MCRIndexBrowserConfig indexConfig) {
046 this.browseData = browseData;
047 this.indexConfig = indexConfig;
048 }
049
050 /**
051 * Starts the search and returns the result list.
052 * @return the result list
053 */
054 public List<MCRIndexBrowserEntry> doSearch() {
055 query = buildQuery();
056 results = search();
057 LOGGER.debug("Results found hits:" + results.getNumHits());
058 hitList = createLinkedListfromSearch();
059 // for further search and research (by refine and other posibilities
060 // the query must be in the Cache
061 MCRCachedQueryData.cache(results, query.buildXML(), query.getCondition());
062 return hitList;
063 }
064
065 /**
066 * Creates the search query for a new index browser
067 * request. The result of this query will be cached.
068 * @return a new MCRQuery.
069 */
070 protected MCRQuery buildQuery() {
071 MCRCondition cond = buildCondition();
072 List<MCRSortBy> sortCriteria = buildSortCriteria();
073 MCRQuery query = new MCRQuery(cond, sortCriteria, 0);
074 if(LOGGER.isDebugEnabled()) {
075 XMLOutputter out = new XMLOutputter(org.jdom.output.Format.getPrettyFormat());
076 LOGGER.debug("Query: \n" + out.outputString(query.buildXML()));
077 }
078 return query;
079 }
080
081 /**
082 * Create the condition of the query.
083 * @return a new condition.
084 */
085 protected MCRCondition buildCondition() {
086 MCRAndCondition cAnd = new MCRAndCondition();
087 MCRFieldDef fieldproject;
088 MCRFieldDef fieldtype;
089 if (indexConfig.getIndex().indexOf(",") != -1) {
090 MCROrCondition cOr = new MCROrCondition();
091 StringTokenizer st = new StringTokenizer(indexConfig.getIndex(), ",");
092 while (st.hasMoreTokens()) {
093 String next = st.nextToken();
094 int ilen = next.indexOf("_");
095 if (ilen == -1) {
096 fieldtype = MCRFieldDef.getDef("objectType");
097 cOr.addChild(new MCRQueryCondition(fieldtype, "=", next));
098 } else {
099 MCRAndCondition iAnd = new MCRAndCondition();
100 fieldtype = MCRFieldDef.getDef("objectType");
101 iAnd.addChild(new MCRQueryCondition(fieldtype, "=", next.substring(ilen + 1, next.length())));
102 fieldproject = MCRFieldDef.getDef("objectProject");
103 iAnd.addChild(new MCRQueryCondition(fieldproject, "=", next.substring(0, ilen)));
104 cOr.addChild(iAnd);
105 }
106 }
107 cAnd.addChild(cOr);
108 } else {
109 int ilen = indexConfig.getIndex().indexOf("_");
110 if (ilen == -1) {
111 fieldtype = MCRFieldDef.getDef("objectType");
112 cAnd.addChild(new MCRQueryCondition(fieldtype, "=", indexConfig.getIndex()));
113 } else {
114 fieldtype = MCRFieldDef.getDef("objectType");
115 cAnd.addChild(new MCRQueryCondition(fieldtype, "=", indexConfig.getIndex().substring(ilen + 1, indexConfig.getIndex().length())));
116 fieldproject = MCRFieldDef.getDef("objectProject");
117 cAnd.addChild(new MCRQueryCondition(fieldproject, "=", indexConfig.getIndex().substring(0, ilen)));
118 }
119 }
120 if (browseData.getSearch() != null && browseData.getSearch().length() > 0) {
121 MCRFieldDef field = MCRFieldDef.getDef(indexConfig.getBrowseField());
122 String value = browseData.getSearch();
123 if("wraps".equals(browseData.getMode())){
124 value="*"+value+"*";
125 }
126 String operator = getOperator();
127 cAnd.addChild(new MCRQueryCondition(field, operator, value));
128 }
129 return cAnd;
130 }
131
132 /**
133 * Creates the sort criteria of the query.
134 * @return a new list of sort criteria.
135 */
136 protected List<MCRSortBy> buildSortCriteria() {
137 boolean order = "ascending".equalsIgnoreCase(indexConfig.getOrder());
138 List<MCRSortBy> sortCriteria = new ArrayList<MCRSortBy>();
139
140 for (String sortFieldValue : indexConfig.getSortFields()) {
141 MCRFieldDef field = MCRFieldDef.getDef(sortFieldValue);
142 if (null != field)
143 sortCriteria.add(new MCRSortBy(field, order));
144 else
145 LOGGER.error("MCRFieldDef not available: " + sortFieldValue);
146 }
147 return sortCriteria;
148 }
149
150 protected MCRResults search() {
151 return MCRQueryManager.search(query);
152 }
153
154 /**
155 * Creates a list of MCRIndexBrowserEntries from the results of the search.
156 * Each entry has gets the id and the sort values of the mcr hit object.
157 *
158 * @return a new list of MCRIndexBrowserEntries
159 */
160 protected List<MCRIndexBrowserEntry> createLinkedListfromSearch() {
161 // at first we must create the full list with all results
162 List<MCRIndexBrowserEntry> hitList = new LinkedList<MCRIndexBrowserEntry>();
163
164 for (MCRHit hit : results) {
165 MCRIndexBrowserEntry entry = new MCRIndexBrowserEntry();
166
167 List<MCRFieldValue> sortData = hit.getSortData();
168 // only necessary if the sort entry list is empty
169 // or the first sort entry differs from the query sort entry
170 MCRFieldDef mainSortField = query.getSortBy().get(0).getField();
171 if (sortData.size() == 0 || !sortData.get(0).getField().equals(mainSortField)) {
172 //main sortfield has no value for this hit
173 MCRFieldValue value = new MCRFieldValue(mainSortField, "???undefined???");
174 sortData.add(0, value);
175 }
176 Iterator<MCRFieldValue> it = sortData.iterator();
177 while(it.hasNext()) {
178 entry.addSortValue(it.next().getValue());
179 }
180 entry.setObjectId(hit.getID());
181 hitList.add(entry);
182 }
183 return hitList;
184 }
185
186 /**
187 * Returns the lucene search operator as String to be used doing a lucene
188 * query. This will be taken from MyBrowseData.mode; If MyBrowseData.mode ==
189 * "prefix" -> return "like", If MyBrowseData.mode == "equals" -> return
190 * "=", Else return "like"
191 *
192 * @return The lucene search operator as String
193 *
194 */
195 protected String getOperator() {
196 if (browseData != null && browseData.getMode() != null && browseData.getMode().equalsIgnoreCase("equals"))
197 return "=";
198 else if (browseData != null && browseData.getMode() != null && browseData.getMode().equalsIgnoreCase("prefix"))
199 return "like";
200 else if (browseData != null && browseData.getMode() != null && browseData.getMode().equalsIgnoreCase("wraps"))
201 return "like";
202 else
203 return "like";
204 }
205
206 /**
207 * Returns the final created result list of the cache.
208 * @return a list of MCRIndexBrowserEntries
209 */
210 public List<MCRIndexBrowserEntry> getResultList() {
211 return hitList;
212 }
213
214 }