]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
242f715b3c7fb1b6e5f0d9c53b4fe6d05486d2fa
[tmp/jakarta-migration.git] /
1 /**     \r
2  * QueryManagerNuxeoImpl.java\r
3  *\r
4  * {Purpose of This Class}\r
5  *\r
6  * {Other Notes Relating to This Class (Optional)}\r
7  *\r
8  * $LastChangedBy: $\r
9  * $LastChangedRevision: $\r
10  * $LastChangedDate: $\r
11  *\r
12  * This document is a part of the source code and related artifacts\r
13  * for CollectionSpace, an open source collections management system\r
14  * for museums and related institutions:\r
15  *\r
16  * http://www.collectionspace.org\r
17  * http://wiki.collectionspace.org\r
18  *\r
19  * Copyright © 2009 {Contributing Institution}\r
20  *\r
21  * Licensed under the Educational Community License (ECL), Version 2.0.\r
22  * You may not use this file except in compliance with this License.\r
23  *\r
24  * You may obtain a copy of the ECL 2.0 License at\r
25  * https://source.collectionspace.org/collection-space/LICENSE.txt\r
26  */\r
27 package org.collectionspace.services.common.query.nuxeo;\r
28 \r
29 import org.slf4j.Logger;\r
30 import org.slf4j.LoggerFactory;\r
31 \r
32 import java.util.regex.Pattern;\r
33 \r
34 import org.nuxeo.ecm.core.api.DocumentModel;\r
35 import org.nuxeo.ecm.core.api.DocumentModelList;\r
36 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;\r
37 //import org.nuxeo.ecm.core.client.NuxeoClient;\r
38 \r
39 import org.collectionspace.services.jaxb.InvocableJAXBSchema;\r
40 //import org.collectionspace.services.nuxeo.client.java.NuxeoConnector;\r
41 //import org.collectionspace.services.nuxeo.client.java.NxConnect;\r
42 import org.collectionspace.services.nuxeo.client.java.NuxeoClientEmbedded;\r
43 import org.collectionspace.services.nuxeo.client.java.NuxeoConnectorEmbedded;\r
44 \r
45 import org.collectionspace.services.client.IQueryManager;\r
46 import org.collectionspace.services.common.invocable.Invocable;\r
47 import org.collectionspace.services.common.invocable.InvocableUtils;\r
48 import org.collectionspace.services.common.storage.DatabaseProductType;\r
49 import org.collectionspace.services.common.storage.JDBCTools;\r
50 \r
51 public class QueryManagerNuxeoImpl implements IQueryManager {\r
52 \r
53         private static String ECM_FULLTEXT_LIKE = "ecm:fulltext"\r
54                         + SEARCH_TERM_SEPARATOR + IQueryManager.SEARCH_LIKE;\r
55         private static String SEARCH_LIKE_FORM = null;\r
56 \r
57         private final Logger logger = LoggerFactory\r
58                         .getLogger(QueryManagerNuxeoImpl.class);\r
59 \r
60         // Consider that letters, letter-markers, numbers, '_' and apostrophe are\r
61         // words\r
62         private static Pattern nonWordChars = Pattern\r
63                         .compile("[^\\p{L}\\p{M}\\p{N}_']");\r
64         private static Pattern unescapedDblQuotes = Pattern.compile("(?<!\\\\)\"");\r
65         private static Pattern unescapedSingleQuote = Pattern.compile("(?<!\\\\)'");\r
66         private static Pattern kwdSearchProblemChars = Pattern\r
67                         .compile("[\\:\\(\\)]");\r
68         private static Pattern kwdSearchHyphen = Pattern.compile(" - ");\r
69 \r
70         private static String getLikeForm() {\r
71                 if (SEARCH_LIKE_FORM == null) {\r
72                         try {\r
73                                 DatabaseProductType type = JDBCTools.getDatabaseProductType();\r
74                                 if (type == DatabaseProductType.MYSQL) {\r
75                                         SEARCH_LIKE_FORM = IQueryManager.SEARCH_LIKE;\r
76                                 } else if (type == DatabaseProductType.POSTGRESQL) {\r
77                                         SEARCH_LIKE_FORM = IQueryManager.SEARCH_ILIKE;\r
78                                 }\r
79                         } catch (Exception e) {\r
80                                 SEARCH_LIKE_FORM = IQueryManager.SEARCH_LIKE;\r
81                         }\r
82                 }\r
83                 return SEARCH_LIKE_FORM;\r
84         }\r
85 \r
86         // TODO: This is currently just an example fixed query. This should\r
87         // eventually be\r
88         // removed or replaced with a more generic method.\r
89         /*\r
90          * (non-Javadoc)\r
91          * \r
92          * @see\r
93          * org.collectionspace.services.common.query.IQueryManager#execQuery(java\r
94          * .lang.String)\r
95          */\r
96         @Override\r
97         @Deprecated\r
98         public void execQuery(String queryString) {\r
99                 NuxeoClientEmbedded client = null;\r
100                 try {\r
101                         client = NuxeoConnectorEmbedded.getInstance().getClient();\r
102                         RepositoryInstance repoSession = client.openRepository();\r
103 \r
104                         DocumentModelList docModelList = repoSession\r
105                                         .query("SELECT * FROM Relation WHERE relations_common:subjectCsid='updated-Subject-1'");\r
106                         // DocumentModelList docModelList =\r
107                         // repoSession.query("SELECT * FROM Relation");\r
108                         // DocumentModelList docModelList =\r
109                         // repoSession.query("SELECT * FROM CollectionObject WHERE collectionobject:objectNumber='objectNumber-1251305545865'");\r
110                         for (DocumentModel docModel : docModelList) {\r
111                                 System.out\r
112                                                 .println("--------------------------------------------");\r
113                                 System.out.println(docModel.getPathAsString());\r
114                                 System.out.println(docModel.getName());\r
115                                 System.out.println(docModel.getPropertyValue("dc:title"));\r
116                                 // System.out.println("subjectCsid=" +\r
117                                 // docModel.getProperty("relations_common",\r
118                                 // "subjectCsid").toString());\r
119                         }\r
120 \r
121                 } catch (Exception e) {\r
122                         // TODO Auto-generated catch block\r
123                         e.printStackTrace();\r
124                 }\r
125         }\r
126 \r
127         @Override\r
128         public String createWhereClauseFromAdvancedSearch(String advancedSearch) {\r
129                 String result = null;\r
130                 //\r
131                 // Process search term.  FIXME: REM - Do we need to perform and string filtering here?\r
132                 //\r
133                 if (advancedSearch != null && !advancedSearch.isEmpty()) {\r
134                         StringBuffer advancedSearchWhereClause = new StringBuffer(\r
135                                         advancedSearch);\r
136                         result = advancedSearchWhereClause.toString();\r
137                 }\r
138                 \r
139                 return result;\r
140         }\r
141 \r
142         /*\r
143          * (non-Javadoc)\r
144          * \r
145          * @see org.collectionspace.services.common.query.IQueryManager#\r
146          * createWhereClauseFromKeywords(java.lang.String)\r
147          */\r
148         // TODO handle keywords containing escaped punctuation chars, then we need\r
149         // to qualify the\r
150         // search by matching on the fulltext.simpletext field.\r
151         // TODO handle keywords containing unescaped double quotes by matching the\r
152         // phrase\r
153         // against the fulltext.simpletext field.\r
154         // Both these require using JDBC, since we cannot get to the fulltext table\r
155         // in NXQL\r
156         @Override\r
157         public String createWhereClauseFromKeywords(String keywords) {\r
158                 String result = null;\r
159                 StringBuffer fullTextWhereClause = new StringBuffer(SEARCH_GROUP_OPEN);\r
160                 // StringBuffer phraseWhereClause = new StringBuffer(SEARCH_GROUP_OPEN);\r
161                 boolean phrasesToAdd = false;\r
162                 // Split on unescaped double quotes to handle phrases\r
163                 String[] phrases = unescapedDblQuotes.split(keywords.trim());\r
164                 boolean first = true;\r
165                 for (String phrase : phrases) {\r
166                         String trimmed = phrase.trim();\r
167                         // Ignore empty strings from match, or goofy input\r
168                         if (trimmed.isEmpty())\r
169                                 continue;\r
170                         // Add the phrase to the string to pass in for full text matching.\r
171                         // Note that we can pass in a set of words and it will do the OR for\r
172                         // us.\r
173                         if (first) {\r
174                                 fullTextWhereClause.append(ECM_FULLTEXT_LIKE + "'");\r
175                                 first = false;\r
176                         } else {\r
177                                 fullTextWhereClause.append(SEARCH_TERM_SEPARATOR);\r
178                         }\r
179                         // ignore the special chars except single quote here - can't hurt\r
180                         // TODO this should become a special function that strips things the\r
181                         // fulltext will ignore, including non-word chars and too-short\r
182                         // words,\r
183                         // and escaping single quotes. Can return a boolean for anything\r
184                         // stripped,\r
185                         // which triggers the back-up search. We can think about whether\r
186                         // stripping\r
187                         // short words not in a quoted phrase should trigger the backup.\r
188                         trimmed = unescapedSingleQuote.matcher(trimmed).replaceAll("\\\\'");\r
189                         // If there are non-word chars in the phrase, we need to match the\r
190                         // phrase exactly against the fulltext table for this object\r
191                         // if(nonWordChars.matcher(trimmed).matches()) {\r
192                         // }\r
193                         // Replace problem chars with spaces. Patches CSPACE-4147,\r
194                         // CSPACE-4106\r
195                         trimmed = kwdSearchProblemChars.matcher(trimmed).replaceAll(" ");\r
196                         trimmed = kwdSearchHyphen.matcher(trimmed).replaceAll(" ");\r
197 \r
198                         fullTextWhereClause.append(trimmed);\r
199                         if (logger.isTraceEnabled() == true) {\r
200                                 logger.trace("Current built whereClause is: "\r
201                                                 + fullTextWhereClause.toString());\r
202                         }\r
203                 }\r
204                 if (first) {\r
205                         throw new RuntimeException(\r
206                                         "No usable keywords specified in string:[" + keywords + "]");\r
207                 }\r
208                 fullTextWhereClause.append("'" + SEARCH_GROUP_CLOSE);\r
209 \r
210                 result = fullTextWhereClause.toString();\r
211                 if (logger.isDebugEnabled()) {\r
212                         logger.debug("Final built WHERE clause is: " + result);\r
213                 }\r
214 \r
215                 return result;\r
216         }\r
217 \r
218         /*\r
219          * (non-Javadoc)\r
220          * \r
221          * @see org.collectionspace.services.common.query.IQueryManager#\r
222          * createWhereClauseFromKeywords(java.lang.String)\r
223          */\r
224         // TODO handle keywords containing escaped punctuation chars, then we need\r
225         // to qualify the\r
226         // search by matching on the fulltext.simpletext field.\r
227         // TODO handle keywords containing unescaped double quotes by matching the\r
228         // phrase\r
229         // against the fulltext.simpletext field.\r
230         // Both these require using JDBC, since we cannot get to the fulltext table\r
231         // in NXQL\r
232         @Override\r
233         public String createWhereClauseForPartialMatch(String field,\r
234                         String partialTerm) {\r
235                 String trimmed = (partialTerm == null) ? "" : partialTerm.trim();\r
236                 if (trimmed.isEmpty()) {\r
237                         throw new RuntimeException("No partialTerm specified.");\r
238                 }\r
239                 if (field == null || field.isEmpty()) {\r
240                         throw new RuntimeException("No match field specified.");\r
241                 }\r
242                 String ptClause = field + getLikeForm() + "'%"\r
243                                 + unescapedSingleQuote.matcher(trimmed).replaceAll("\\\\'")\r
244                                 + "%'";\r
245                 return ptClause;\r
246         }\r
247 \r
248         /**\r
249          * Creates a filtering where clause from docType, for invocables.\r
250          * \r
251          * @param docType\r
252          *            the docType\r
253          * \r
254          * @return the string\r
255          */\r
256         @Override\r
257         public String createWhereClauseForInvocableByDocType(String schema,\r
258                         String docType) {\r
259                 String trimmed = (docType == null) ? "" : docType.trim();\r
260                 if (trimmed.isEmpty()) {\r
261                         throw new RuntimeException("No docType specified.");\r
262                 }\r
263                 if (schema == null || schema.isEmpty()) {\r
264                         throw new RuntimeException("No match schema specified.");\r
265                 }\r
266                 String wClause = schema + ":" + InvocableJAXBSchema.FOR_DOC_TYPES\r
267                                 + " = '" + trimmed + "'";\r
268                 return wClause;\r
269         }\r
270 \r
271         /**\r
272          * Creates a filtering where clause from invocation mode, for invocables.\r
273          * \r
274          * @param mode\r
275          *            the mode\r
276          * \r
277          * @return the string\r
278          */\r
279         @Override\r
280         public String createWhereClauseForInvocableByMode(String schema, String mode) {\r
281                 String trimmed = (mode == null) ? "" : mode.trim();\r
282                 if (trimmed.isEmpty()) {\r
283                         throw new RuntimeException("No docType specified.");\r
284                 }\r
285                 if (schema == null || schema.isEmpty()) {\r
286                         throw new RuntimeException("No match schema specified.");\r
287                 }\r
288                 String wClause = InvocableUtils.getPropertyNameForInvocationMode(\r
289                                 schema, trimmed) + " != 0";\r
290                 return wClause;\r
291         }\r
292 \r
293         /**\r
294          * @param input\r
295          * @return true if there were any chars filtered, that will require a backup\r
296          *         qualifying search on the actual text.\r
297          */\r
298         private boolean filterForFullText(String input) {\r
299                 boolean fFilteredChars = false;\r
300 \r
301                 return fFilteredChars;\r
302         }\r
303         \r
304         /**\r
305          * Creates a query to filter a qualified (string) field according to a list of string values. \r
306          * @param qualifiedField The schema-qualified field to filter on\r
307          * @param filterTerms the list of one or more strings to filter on\r
308          * @param fExclude If true, will require qualifiedField NOT match the filters strings.\r
309          *                                      If false, will require qualifiedField does match one of the filters strings.\r
310          * @return queryString\r
311          */\r
312         @Override\r
313         public String createWhereClauseToFilterFromStringList(String qualifiedField, String[] filterTerms, boolean fExclude) {\r
314         // Start with the qualified termStatus field\r
315         StringBuilder filterClause = new StringBuilder(qualifiedField);\r
316         if(filterTerms.length == 1) {\r
317                 filterClause.append(fExclude?" <> '":" = '");\r
318                 filterClause.append(filterTerms[0]);\r
319                 filterClause.append('\'');  \r
320         } else {\r
321                 filterClause.append(fExclude?" NOT IN (":" IN (");\r
322                 for(int i=0; i<filterTerms.length; i++) {\r
323                         if(i>0) {\r
324                                 filterClause.append(',');\r
325                         }\r
326                         filterClause.append('\'');  \r
327                         filterClause.append(filterTerms[i]);\r
328                         filterClause.append('\'');  \r
329                 }\r
330                 filterClause.append(')');  \r
331         }\r
332         return filterClause.toString();\r
333         }\r
334 \r
335 }\r