View Javadoc

1   /*
2    * Copyright 2011 The Kuali Foundation.
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.docstore.discovery.service;
17  
18  import org.kuali.ole.docstore.discovery.model.SearchCondition;
19  import org.kuali.ole.docstore.discovery.model.SearchParams;
20  import org.kuali.rice.core.api.config.property.ConfigContext;
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.io.BufferedReader;
25  import java.io.InputStreamReader;
26  import java.io.UnsupportedEncodingException;
27  import java.net.URL;
28  import java.net.URLConnection;
29  import java.net.URLDecoder;
30  import java.net.URLEncoder;
31  import java.text.CharacterIterator;
32  import java.text.StringCharacterIterator;
33  import java.util.*;
34  
35  public class DiscoveryServiceImpl
36          implements DiscoveryService {
37      private static final Logger LOG = LoggerFactory.getLogger(DiscoveryServiceImpl.class);
38      private static String docSearchUrl = null;
39      private static DiscoveryService discoveryService = null;
40  
41      private DiscoveryServiceImpl() {
42          LOG.debug("DiscoveryServiceImpl ");
43          init();
44      }
45  
46      public static DiscoveryService getInstance() {
47          if (null == discoveryService) {
48              discoveryService = new DiscoveryServiceImpl();
49          }
50          return discoveryService;
51      }
52  
53      protected void init() {
54          LOG.debug("DiscoveryServiceImpl init ");
55          if(ConfigContext.getCurrentContextConfig()!=null){
56              setDocSearchUrl(ConfigContext.getCurrentContextConfig().getProperty("docSearchURL"));
57          }
58      }
59  
60      public String search(SearchParams searchParams) {
61          String response = "";
62          LOG.debug("in search1");
63          String searchType = searchParams.getSearchType();
64          LOG.debug("searchType " + searchType);
65          StringBuffer query = new StringBuffer();
66          query.append(SolrServerManager.getInstance().getSolrCoreURL() + "/select");
67          if (searchType.equals(SEARCH_TYPE_MORE_FACET)) {
68              String facetPrefix = searchParams.getFacetPrefix();
69              String facetPageSize = searchParams.getFacetPageSize();
70              String facetSort = searchParams.getFacetSort();
71              String facetOffset = searchParams.getFacetOffset();
72              buildInitialQuery(query, searchParams);
73              query.append("&facet=true");
74  
75              query.append("&facet.mincount=1");
76  
77              query.append("&facet.prefix=" + facetPrefix);
78  
79              query.append("&facet.offset=" + facetOffset);
80  
81              query.append("&facet.limit=" + facetPageSize);
82  
83              query.append("&facet.sort=" + facetSort);
84  
85              query.append("&facet.field=" + searchParams.getFacetField());
86  
87              Map<String, String> facetTermsMap = searchParams.getFacetTermsMap();
88              query.append(buildFilterQuery(facetTermsMap));
89          } else {
90              if (searchParams.getSearchFieldsList() != null && searchParams.getSearchFieldsList().size() <= 0 && (
91                      searchType != null && !searchType.equalsIgnoreCase(SEARCH_TYPE_LINK))) {
92                  buildInitialQuery(query, searchParams);
93                  searchParams.setSearchTerms("");
94              } else if (searchType != null && (searchType.equalsIgnoreCase(SEARCH_TYPE_ADVANCED)
95                      || searchType.equalsIgnoreCase(SEARCH_TYPE_FACET) || searchType
96                      .equalsIgnoreCase(SEARCH_TYPE_FACET_DELETE))) {
97                  buildInitialQuery(query, searchParams);
98                  if (searchParams.getSearchFieldsList().size() > 0) {
99                      query.append("AND(");
100                 }
101                 query.append(buildQueryWithSearchParameters(searchParams.getSearchFieldsList()));
102                 LOG.debug("query for search terms............." + query.toString());
103                 String searchTerms = buildQueryWithSearchParameters(searchParams.getSearchFieldsList())
104                         .replaceAll("_search", "");
105                 try {
106                     searchTerms = URLDecoder.decode(searchTerms, "UTF-8");
107                 } catch (UnsupportedEncodingException e) {
108                     e.printStackTrace();
109                 }
110                 searchParams.setSearchTerms(searchTerms.substring(0, searchTerms.lastIndexOf(")")));
111             }
112             if (SEARCH_TYPE_LINK.equals(searchType)) {
113                 query.append("?q=id:");
114                 query.append(searchParams.getLinkValue());
115             }
116             query.append("&rows=" + searchParams.getResultPageSize());
117             String docType = searchParams.getDocType();
118             LOG.info("docType-->" + docType);
119 
120             query.append("&start=" + searchParams.getResultFromIndex());
121             List<String> facetList = new ArrayList<String>();
122             facetList.add(AUTHOR_FACET);
123             facetList.add(SUBJECT_FACET);
124             facetList.add(FORMAT_FACET);
125             facetList.add(LANGUAGE_FACET);
126             facetList.add(PUBLICATION_DATE_FACET);
127             facetList.add(GENRE_FACET);
128             query.append(buildQueryWithFacetParameters(facetList, 1, 10));
129             LOG.debug("sort terms buildQueryWithSortFields" + searchParams.getSortByTerms());
130             LOG.debug("sort Field buildQueryWithSortFields" + searchParams.getSortField());
131             LOG.debug("sort Order buildQueryWithSortFields" + searchParams.getSortOrder());
132             query.append(buildQueryWithSortFields(searchParams.getSortField(), searchParams.getSortOrder()));
133             query.append(buildQueryWithFieldListParameters(searchParams.getFieldList()));
134             Map<String, String> facetTermsMap = searchParams.getFacetTermsMap();
135             query.append(buildFilterQuery(facetTermsMap));
136             String holdingFields
137                     = "LocalId_display,Uri_display,HoldingsNote_display,ReceiptStatus_display,CallNumber_display,CallNumberPrefix_display,CallNumberType_display,ClassificationPart_display,LocationLevel_display,ShelvingSchemeCode_display";
138             String itemFields
139                     = "LocalId_display,ItemBarcode_display,ItemTypeFullValue_display,VendorLineItemIdentifier_display,ShelvingOrderValue_display,ShelvingSchemeValue_display,PurchaseOrderLineItemIdentifier_display,CopyNumber_display,Enumeration_display,Chronology_display,VolumeNumber_display,ItemStatus_display";
140             String instanceFields = "LocalId_display,Source_display";
141             String patronFields
142                     = "RecordNumber_display,BeginDate_display,Name_display,BorrowerType_display,BarCodeNumber_display,BarCodeStatus_display,";
143             String onixplFields
144                     = "ContractNumber_display,Title_display,Method_display,Status_display,Type_display,Licensor_display,Licensee_display";
145             String licenseBinaryFields
146                     = "Name_display,FileName_display,DateUploaded_display,Owner_display,Notes_display";
147             String eInstanceFields = "AccessStatus_display,Imprint_display,Platform_display,StatisticalSearchingCodeValue_display,EResource_name_display";
148             //query.append("&fl=" + fieldList);
149             query.append(
150                     "&fl=LocalId_display,Title_display,Author_display,Publisher_display,Description_display,Subject_display,Location_display,PublicationDate_display,Format_display,DocType,DocFormat,id,ItemLinks,BibliographicLinks,Barcode_display,instanceIdentifier,holdingsIdentifier,itemIdentifier,bibIdentifier,staffOnlyFlag"
151                     /*
152                                     + "," + "245a,245b"
153                                     + "," + "100a,110a,111a,700a,710a,711a,800a,810a,811a,400a,410a,411a"
154                                     + "," + "600a,610a,611a,630a,650a,651a,653a"
155                                     + "," + "505a"
156                                     + "," + "856u"
157                                     + "," + "260b"
158                     */ + "," + holdingFields + "," + itemFields + "," + instanceFields + "," + patronFields
159                             + "," + onixplFields + "," + licenseBinaryFields + "," + eInstanceFields);
160         }
161         LOG.debug("query---> " + query);
162         try {
163             String queryStr = query.toString().replaceAll(" ", "+");
164 
165             searchParams.setSearchQuery(queryStr);
166             URL url = new URL(queryStr);
167             URLConnection urlc = null;
168             urlc = url.openConnection();
169             urlc.setDoOutput(true);
170             urlc.setAllowUserInteraction(false);
171             BufferedReader br = new BufferedReader(new InputStreamReader(urlc.getInputStream()));
172             StringBuilder sb = new StringBuilder();
173             String line;
174             while ((line = br.readLine()) != null) {
175                 sb.append(line);
176                 sb.append("\n");
177             }
178             br.close();
179             response = sb.toString();
180         } catch (Exception e) {
181             LOG.error("Exception:" + e.getMessage(), e);
182         }
183         return response;
184     }
185 
186     public String getFieldList(String docType) {
187         String fieldList = "";
188         String holdingFields = HOLDINGS_FIELDS;
189         String itemFields = ITEM_FIELDS;
190         String instanceFields = INSTANCE_FIELDS;
191         String bibFields = BIB_FIELDS;
192 
193         if (docType.equalsIgnoreCase(BIBLIOGRAPHIC)) {
194             fieldList = bibFields;
195 
196         } else if (docType.equalsIgnoreCase(INSTANCE)) {
197             fieldList = instanceFields;
198 
199         } else if (docType.equalsIgnoreCase(HOLDINGS)) {
200             fieldList = holdingFields;
201 
202         } else if (docType.equalsIgnoreCase(ITEM)) {
203             fieldList = itemFields;
204         }
205         return fieldList;
206     }
207 
208 
209     public static void setDocSearchUrl(String docSearchUrl) {
210     }
211 
212     public static String getDocSearchUrl() {
213         return docSearchUrl;
214     }
215 
216     public String buildQuery(SearchParams searchParams) {
217         StringBuffer query = new StringBuffer();
218         String searchType = searchParams.getSearchType();
219         query.append(SolrServerManager.getInstance().getSolrCoreURL() + "/select");
220         buildInitialQuery(query, searchParams);
221         if (searchParams.getSearchFieldsList().size() > 0) {
222             query.append("AND(");
223         }
224         query.append(buildQueryWithSearchParameters(searchParams.getSearchFieldsList()));
225         if (searchParams.getResultPageSize() != null) {
226             query.append("&rows=" + searchParams.getResultPageSize());
227         }
228         if (searchParams.getResultFromIndex() != null) {
229             query.append("&start=" + searchParams.getResultFromIndex());
230         }
231         List<String> facetFieldList = searchParams.getFacetFieldList();
232         query.append(buildQueryWithFacetParameters(facetFieldList, 1, 10));
233         query.append(buildQueryWithSortFields(searchParams.getSortField(), searchParams.getSortOrder()));
234         query.append(buildQueryWithFieldListParameters(searchParams.getFieldList()));
235         Map<String, String> facetTermsMap = searchParams.getFacetTermsMap();
236         query.append(buildFilterQuery(facetTermsMap));
237 
238         return query.toString();
239     }
240 
241 
242     public String buildQueryWithSearchParameters(List<SearchCondition> searchFieldsList) {
243         SearchCondition docSearchFieldsDTO = null;
244         StringBuffer queryStringbuffer = new StringBuffer();
245         StringBuffer highlightBuffer = new StringBuffer("&hl.fl=");
246         if (searchFieldsList != null && searchFieldsList.size() > 0) {
247 
248             for (int i = 0; i < searchFieldsList.size(); i++) {
249                 int searchScopeAddLimit = i;
250                 docSearchFieldsDTO = searchFieldsList.get(i);
251                 if (docSearchFieldsDTO.getOperator() != null) {
252                     //queryStringbuffer.append(docSearchFieldsDTO.getOperator());
253                 }
254                 queryStringbuffer.append("(");
255                 if (docSearchFieldsDTO.getDocField().equalsIgnoreCase("all")) {
256                     queryStringbuffer.append("all_text");
257                     highlightBuffer.append("*");
258 
259                 } else {
260                     queryStringbuffer.append(docSearchFieldsDTO.getDocField());
261                     highlightBuffer.append(docSearchFieldsDTO.getDocField());
262 
263 
264                     if (i != searchFieldsList.size() - 1) {
265                         highlightBuffer.append(",");
266                     }
267                 }
268                 queryStringbuffer.append(":");
269                 String searchScope = docSearchFieldsDTO.getSearchScope();
270                 String searchText = docSearchFieldsDTO.getSearchText();
271                 String searchOperator = docSearchFieldsDTO.getOperator();
272 //                searchText = searchText.toLowerCase();
273                 LOG.debug("searchText-->" + searchText);
274 //                searchText = searchText.replaceAll("[~!(){}\\[\\]':-]+"," ");
275 //                String modifiedSearchText = searchText.replaceAll("[~!(){}<>\\[\\]':\\-\\\\^]+", " ").toLowerCase();
276                 String modifiedSearchText = getModifiedText(searchText);
277                 String searchTextVal = null;
278                 if (modifiedSearchText.length() > 0) {
279                     queryStringbuffer.append("(");
280                     if (searchScope.equalsIgnoreCase("AND")) {
281                         modifiedSearchText = modifiedSearchText.replaceAll("\\s+", " ");
282                         searchTextVal = modifiedSearchText.trim().replace(" ", " AND ");
283                     } else if (searchScope.equalsIgnoreCase("OR")) {
284                         modifiedSearchText = modifiedSearchText.replaceAll("\\s+", " ");
285                         searchTextVal = modifiedSearchText.trim().replace(" ", " OR ");
286                     } else if (searchScope.equalsIgnoreCase("phrase")) {
287                         searchTextVal = "\"" + searchText + "\"";
288                     }
289                     try {
290                         searchTextVal = URLEncoder.encode(searchTextVal, "UTF-8");
291                     } catch (UnsupportedEncodingException e) {
292                         e.printStackTrace();
293                     }
294                     queryStringbuffer.append(searchTextVal);
295                     LOG.debug("searchTextVal............" + searchTextVal + "........" + queryStringbuffer.toString());
296                     queryStringbuffer.append(")");
297                 }
298                 queryStringbuffer.append(")");
299                 ++searchScopeAddLimit;
300                 if (searchScopeAddLimit != searchFieldsList.size()) {
301                     queryStringbuffer.append(searchOperator);
302                 }
303             }
304             queryStringbuffer.append(")");
305             String highLight = highlightBuffer.toString().replace("LocalId_search", "LocalId_display");
306             queryStringbuffer.append(highLight);
307 
308             queryStringbuffer.append("&hl=true");
309         }
310 
311 
312         return queryStringbuffer.toString();
313     }
314 
315     public String buildQueryWithFacetParameters(List<String> facetsParametersList, int facetMinCount, int facetLimit) {
316         String facetFieldName = "";
317         String queryWithFacetParameters = "";
318         if (facetsParametersList != null) {
319             StringBuffer facetsQueryStringbuffer = new StringBuffer();
320 
321             facetsQueryStringbuffer.append("&facet=true");
322 
323             facetsQueryStringbuffer.append("&facet.mincount=" + facetMinCount);
324 
325             facetsQueryStringbuffer.append("&");
326 
327             for (int i = 0; i < facetsParametersList.size(); i++) {
328                 facetFieldName = facetsParametersList.get(i);
329                 facetsQueryStringbuffer.append("facet.field=" + facetFieldName);
330                 facetsQueryStringbuffer.append("&");
331 
332             }
333             queryWithFacetParameters = facetsQueryStringbuffer.substring(0, facetsQueryStringbuffer.length() - 1);
334         }
335         return queryWithFacetParameters;
336     }
337 
338 
339     public String buildQueryWithSortFields(String sortField, String sortOrder) {
340         StringBuffer sortFieldsQuery = new StringBuffer();
341         if (null != sortField) {
342             sortFieldsQuery.append("&");
343             sortFieldsQuery.append("sort=");
344             sortFieldsQuery.append(sortField);
345             if (null != sortOrder) {
346                 sortFieldsQuery.append(" ");
347                 sortFieldsQuery.append(sortOrder);
348             }
349         }
350         return sortFieldsQuery.toString();
351     }
352 
353     public String buildQueryWithFieldListParameters(List<String> fieldsList) {
354         String queryWithFieldListParameters = "";
355         if (fieldsList != null) {
356             StringBuffer fieldsListQueryStringbuffer = new StringBuffer();
357             fieldsListQueryStringbuffer.append("&");
358             fieldsListQueryStringbuffer.append("fl=");
359             for (int i = 0; i < fieldsList.size(); i++) {
360                 fieldsListQueryStringbuffer.append(fieldsList.get(i));
361                 fieldsListQueryStringbuffer.append(",");
362             }
363             queryWithFieldListParameters = fieldsListQueryStringbuffer
364                     .substring(0, fieldsListQueryStringbuffer.length() - 1);
365         }
366         return queryWithFieldListParameters;
367     }
368 
369     public static String convertListToStringFieldValues(Map<String, String> map) {
370         StringBuffer sb = new StringBuffer();
371         Set set = map.keySet();
372         Iterator<String> ite = set.iterator();
373         while (ite.hasNext()) {
374             sb.append(ite.next());
375             sb.append("|");
376         }
377         String str = sb.toString();
378         if (str != null && str.length() > 0) {
379             str = str.substring(0, str.length() - 1);
380         }
381         return str;
382     }
383 
384     public String buildFilterQuery(Map<String, String> facetTermsMap) {
385         String filterQuery = "";
386         int temp = 0;
387         int tokenInt = 0;
388         if ((null != facetTermsMap) && (facetTermsMap.size() > 0)) {
389 
390             String facetTerms = convertListToStringFieldValues(facetTermsMap);
391             StringBuffer facetQueryTemp = new StringBuffer();
392             facetQueryTemp.append("&terms=" + facetTerms);
393             facetQueryTemp.append("&fq=");
394             StringTokenizer sttoken = new StringTokenizer(facetTerms, "|");
395             String token;
396             while (sttoken.hasMoreElements()) {
397                 token = sttoken.nextToken();
398                 facetQueryTemp.append("(");
399                 facetQueryTemp.append(facetTermsMap.get(token));
400                 facetQueryTemp.append(":\"");
401                 facetQueryTemp.append(token);
402                 facetQueryTemp.append("\")");
403                 facetQueryTemp.append("AND");
404             }
405             if (facetQueryTemp.length() > 0) {
406                 filterQuery = (facetQueryTemp.toString().substring(0, facetQueryTemp.toString().length() - 3));
407             }
408         }
409         return filterQuery;
410     }
411 
412 
413     /**
414      * @param query
415      * @param searchParams Usage: This method builds initial SOLR query with DocType and DocFormat as SolrParams
416      */
417     private void buildInitialQuery(StringBuffer query, SearchParams searchParams) {
418         query.append("?q=");
419         //query.append("(DocType:" + searchParams.getDocType() + ")");
420         if (searchParams.getDocFormat().equalsIgnoreCase("marc")) {
421             query.append("((DocType:" + searchParams.getDocType() + ")" + "OR(DocType:item))");
422         } else {
423             query.append("(DocType:" + searchParams.getDocType() + ")");
424         }
425 
426         if (searchParams.getDocFormat() != null && !searchParams.getDocFormat().equalsIgnoreCase("all")) {
427             if ("dublin".equals(searchParams.getDocFormat())) {
428                 searchParams.setDocFormat("dublin");
429             }
430             query.append("AND(DocFormat:" + searchParams.getDocFormat() + ")");
431         }
432     }
433 
434     private String getModifiedText(String searchText) {
435         StringBuffer modifiedText = new StringBuffer();
436         StringCharacterIterator stringCharacterIterator = new StringCharacterIterator(searchText);
437         char character = stringCharacterIterator.current();
438         while (character != CharacterIterator.DONE) {
439 
440             if (character == '\\') {
441                 modifiedText.append("\\\\");
442             } else if (character == '?') {
443                 modifiedText.append("\\?");
444             } else if (character == '*') {
445                 modifiedText.append("\\*");
446             } else if (character == '+') {
447                 modifiedText.append("\\+");
448             } else if (character == ':') {
449                 modifiedText.append("\\:");
450             } else if (character == '{') {
451                 modifiedText.append("\\{");
452             } else if (character == '}') {
453                 modifiedText.append("\\}");
454             } else if (character == '[') {
455                 modifiedText.append("\\[");
456             } else if (character == ']') {
457                 modifiedText.append("\\]");
458             } else if (character == '(') {
459                 modifiedText.append("\\(");
460             } else if (character == ')') {
461                 modifiedText.append("\\)");
462             } else if (character == '^') {
463                 modifiedText.append("\\^");
464             } else if (character == '~') {
465                 modifiedText.append("\\~");
466             } else if (character == '-') {
467                 modifiedText.append("\\-");
468             } else if (character == '!') {
469                 modifiedText.append("\\!");
470             } else if (character == '\'') {
471                 modifiedText.append("\\'");
472             } else if (character == '@') {
473                 modifiedText.append("\\@");
474             } else if (character == '#') {
475                 modifiedText.append("\\#");
476             } else if (character == '$') {
477                 modifiedText.append("\\$");
478             } else if (character == '%') {
479                 modifiedText.append("\\%");
480             } else {
481                 //the char is not a special one
482                 //add it to the result as is
483                 modifiedText.append(character);
484             }
485             character = stringCharacterIterator.next();
486         }
487 
488         return modifiedText.toString().toLowerCase();
489     }
490 
491 }