1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.templatingkit.search;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.NodeData;
38 import info.magnolia.jcr.util.NodeTypes;
39 import info.magnolia.jcr.util.NodeUtil;
40 import info.magnolia.jcr.util.PropertyUtil;
41 import info.magnolia.module.templatingkit.templates.category.TemplateCategoryUtil;
42 import info.magnolia.templating.functions.TemplatingFunctions;
43
44 import java.util.ArrayList;
45 import java.util.Calendar;
46 import java.util.List;
47 import java.util.regex.Pattern;
48
49 import javax.jcr.Node;
50 import javax.jcr.NodeIterator;
51 import javax.jcr.Property;
52 import javax.jcr.PropertyIterator;
53 import javax.jcr.PropertyType;
54 import javax.jcr.RepositoryException;
55
56 import org.apache.commons.lang3.StringUtils;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63 public class SearchResultItem {
64 private static final Logger log = LoggerFactory.getLogger(SearchResultItem.class);
65
66 private static final Pattern HTML_STRIP = Pattern.compile("<.*?>", Pattern.DOTALL);
67
68
69
70
71 protected int chars = 100;
72
73
74
75
76 protected int maxSnippets = 3;
77
78 private Calendar date;
79 private String author;
80 private String category;
81 private String title;
82 private String text;
83 private Node node;
84 private String link;
85 protected String query;
86
87
88 public SearchResultItem(Node node, String query, TemplatingFunctions templatingFunctions) {
89 this.query = query;
90 this.node = node;
91 this.title = PropertyUtil.getString(node, "title");
92 this.author = PropertyUtil.getString(node, "author");
93
94 this.category = StringUtils.capitalize(TemplateCategoryUtil.getTemplateSubCategory(node));
95 if (StringUtils.isEmpty(category)) {
96 this.category = StringUtils.capitalize(TemplateCategoryUtil.getTemplateCategory(node));
97 }
98
99 this.date = PropertyUtil.getDate(node, "date");
100 if (date == null) {
101 try {
102 this.date = NodeTypes.LastModified.getLastModified(node);
103 } catch (RepositoryException e) {
104
105 }
106 }
107
108 this.link = templatingFunctions.link(node);
109 this.text = this.getSnippets();
110 }
111
112 public SearchResultItem(Node node, String query, String title, String author, String category, Calendar date, String link) {
113 this.query = query;
114 this.node = node;
115 this.title = title;
116 this.author = author;
117
118 this.category = category;
119 this.date = date;
120 this.link = link;
121
122 this.text = this.getSnippets();
123 }
124
125 public Calendar getDate() {
126 return date;
127 }
128
129 public String getAuthor() {
130 return author;
131 }
132
133 public String getCategory() {
134 return category;
135 }
136
137 public String getTitle() {
138 return title;
139 }
140
141 public String getText() {
142 return text;
143 }
144
145 public String getLink() {
146 return link;
147 }
148
149 public Node getNode() {
150 return node;
151 }
152
153 public String getSnippets() {
154
155 log.debug("collecting snippets");
156
157 StringBuffer snippets = new StringBuffer();
158 int numberOfSnippets = 0;
159
160 boolean endProcess = false;
161 try {
162 if (processProperties(numberOfSnippets, snippets, node)) {
163
164 NodeIterator iterator = node.getNodes();
165 while (iterator.hasNext() && !endProcess) {
166 Node paragraphCollection = iterator.nextNode();
167 if (!processProperties(numberOfSnippets, snippets, paragraphCollection)) {
168 endProcess = true;
169 break;
170 }
171 Iterable<Node> paragraphs = NodeUtil.asIterable(paragraphCollection.getNodes());
172
173 for (Node paragraph : paragraphs) {
174 if (!processProperties(numberOfSnippets, snippets, paragraph)) {
175 endProcess = true;
176 break;
177 }
178 log.debug("Iterating on paragraph {}", paragraph);
179
180 }
181 }
182 }
183 } catch (RepositoryException e) {
184 log.error("An error occurred while gettting search snippets", e);
185 }
186
187 return snippets.toString();
188 }
189
190
191 public int getMaxSnippets() {
192 return maxSnippets;
193 }
194
195 public void setMaxSnippets(int maxSnippets) {
196 this.maxSnippets = maxSnippets;
197 }
198
199 protected boolean processProperties(int numberOfSnippets, StringBuffer snippets, Node node) throws RepositoryException {
200
201 List<String> snippetList = new ArrayList<String>();
202
203 PropertyIterator iterator = node.getProperties();
204 while (iterator.hasNext()) {
205 Property property = iterator.nextProperty();
206 if (property.getType() == PropertyType.STRING) {
207 highlightSnippet(snippetList, property);
208 if (snippetList.size() + numberOfSnippets >= maxSnippets) {
209 break;
210 }
211 }
212 }
213 for (String snippet : snippetList) {
214 snippets.append(snippet);
215 }
216 return snippetList.size() + numberOfSnippets < maxSnippets;
217 }
218
219
220
221
222 @Deprecated
223 protected boolean processNodeDatas(int numberOfSnippets, StringBuffer snippets, Content paragraph) throws RepositoryException {
224 return processProperties(numberOfSnippets, snippets, paragraph.getJCRNode());
225 }
226
227
228
229
230 @Deprecated
231 protected void highlightSnippet(List<String> snippetList, NodeData property) throws RepositoryException {
232 highlightSnippet(snippetList, property.getJCRProperty());
233 }
234
235 protected void highlightSnippet(List<String> snippetList, Property property) throws RepositoryException {
236 if (property.isMultiple()) {
237 return;
238 }
239 String resultString = property.getString();
240
241 log.debug("Iterating on property {}", property.getName());
242 log.debug("Property value is {}", resultString);
243
244 String searchTerm = this.query;
245
246 if (skipProperty(property.getName(), resultString, searchTerm)) {
247 return;
248 }
249
250
251 if (searchTerm != null && searchTerm.length() > 2) {
252
253 log.debug("Looking for search term [{}] in [{}]", searchTerm, resultString);
254
255
256 if (StringUtils.startsWith(searchTerm, "\"") && StringUtils.endsWith(searchTerm, "\"")) {
257 searchTerm = searchTerm.substring(1, searchTerm.length() - 1);
258 }
259
260
261
262 if (!StringUtils.contains(resultString.toLowerCase(), searchTerm.toLowerCase())) {
263 return;
264 }
265
266
267 resultString = stripHtmlTags(resultString);
268
269
270 int pos = resultString.toLowerCase().indexOf(searchTerm.toLowerCase());
271 if (pos > -1) {
272
273 int posEnd = pos + searchTerm.length();
274 int from = (pos - chars / 2);
275 if (from < 0) {
276 from = 0;
277 }
278
279 int to = from + chars;
280 if (to > resultString.length()) {
281 to = resultString.length();
282 }
283
284 StringBuffer snippet = new StringBuffer();
285
286 snippet.append(StringUtils.substring(resultString, from, pos));
287 snippet.append("<em class=\"highlight\">");
288 snippet.append(StringUtils.substring(resultString, pos, posEnd));
289 snippet.append("</em>");
290 snippet.append(StringUtils.substring(resultString, posEnd, to));
291
292 if (from > 0) {
293 snippet.insert(0, "... ");
294 }
295 if (to < resultString.length()) {
296 snippet.append("... ");
297 }
298
299 log.debug("Search term found, adding snippet {}", snippet);
300
301 snippetList.add(snippet + "<br />");
302 }
303 }
304 }
305
306 protected boolean skipProperty(String name, String resultString, String searchTerm) {
307
308
309 return resultString.length() < 20;
310 }
311
312 protected String stripHtmlTags(String resultString) {
313 return HTML_STRIP.matcher(resultString).replaceAll("");
314 }
315
316
317 }