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