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    }