001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.kernel.search;
016    
017    import com.liferay.portal.kernel.dao.search.SearchContainer;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.HttpUtil;
020    import com.liferay.portal.kernel.util.PropsUtil;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.kernel.util.StringUtil;
023    import com.liferay.portal.kernel.util.WebKeys;
024    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
025    import com.liferay.portal.kernel.xml.Document;
026    import com.liferay.portal.kernel.xml.Element;
027    import com.liferay.portal.kernel.xml.SAXReaderUtil;
028    import com.liferay.portal.model.Layout;
029    import com.liferay.portal.service.LayoutLocalServiceUtil;
030    import com.liferay.portal.service.UserLocalServiceUtil;
031    import com.liferay.portal.theme.ThemeDisplay;
032    import com.liferay.portal.util.PortalUtil;
033    import com.liferay.portlet.PortletURLFactoryUtil;
034    
035    import java.util.Date;
036    
037    import javax.portlet.PortletMode;
038    import javax.portlet.PortletRequest;
039    import javax.portlet.PortletURL;
040    import javax.portlet.WindowState;
041    
042    import javax.servlet.http.HttpServletRequest;
043    
044    /**
045     * @author Charles May
046     * @author Brian Wing Shun Chan
047     */
048    public abstract class BaseOpenSearchImpl implements OpenSearch {
049    
050            public boolean isEnabled() {
051                    return _enabled;
052            }
053    
054            public abstract String search(
055                            HttpServletRequest request, long groupId, long userId,
056                            String keywords, int startPage, int itemsPerPage, String format)
057                    throws SearchException;
058    
059            public String search(
060                            HttpServletRequest request, long userId, String keywords,
061                            int startPage, int itemsPerPage, String format)
062                    throws SearchException {
063    
064                    return search(
065                            request, 0, userId, keywords, startPage, itemsPerPage, format);
066            }
067    
068            public String search(HttpServletRequest request, String url)
069                    throws SearchException {
070    
071                    try {
072                            long userId = PortalUtil.getUserId(request);
073    
074                            if (userId == 0) {
075                                    long companyId = PortalUtil.getCompanyId(request);
076    
077                                    userId = UserLocalServiceUtil.getDefaultUserId(companyId);
078                            }
079    
080                            String keywords = GetterUtil.getString(
081                                    HttpUtil.getParameter(url, "keywords", false));
082                            int startPage = GetterUtil.getInteger(
083                                    HttpUtil.getParameter(url, "p", false), 1);
084                            int itemsPerPage = GetterUtil.getInteger(
085                                    HttpUtil.getParameter(url, "c", false),
086                                    SearchContainer.DEFAULT_DELTA);
087                            String format = GetterUtil.getString(
088                                    HttpUtil.getParameter(url, "format", false));
089    
090                            return search(
091                                    request, userId, keywords, startPage, itemsPerPage, format);
092                    }
093                    catch (SearchException se) {
094                            throw se;
095                    }
096                    catch (Exception e) {
097                            throw new SearchException(e);
098                    }
099            }
100    
101            protected void addSearchResult(
102                    Element root, long groupId, long scopeGroupId, String entryClassName,
103                    long entryClassPK, String title, String link, Date updated,
104                    String summary, double score, String format) {
105    
106                    addSearchResult(
107                            root, groupId, scopeGroupId, entryClassName, entryClassPK, title,
108                            link, updated, summary, new String[0], 0, score, format);
109            }
110    
111            protected void addSearchResult(
112                    Element root, long groupId, long scopeGroupId, String entryClassName,
113                    long entryClassPK, String title, String link, Date updated,
114                    String summary, String[] tags, double ratings, double score,
115                    String format) {
116    
117                    if (format.equals("rss")) {
118                            addSearchResultRSS(
119                                    root, groupId, scopeGroupId, entryClassName, entryClassPK,
120                                    title, link, updated, summary, tags, ratings, score);
121                    }
122                    else {
123                            addSearchResultAtom(
124                                    root, groupId, scopeGroupId, entryClassName, entryClassPK,
125                                    title, link, updated, summary, tags, ratings, score);
126                    }
127            }
128    
129            protected void addSearchResultAtom(
130                    Element root, long groupId, long scopeGroupId, String entryClassName,
131                    long entryClassPK, String title, String link, Date updated,
132                    String summary, String[] tags, double ratings, double score) {
133    
134                    // entry
135    
136                    Element entry = OpenSearchUtil.addElement(
137                            root, "entry", OpenSearchUtil.DEFAULT_NAMESPACE);
138    
139                    // groupId
140    
141                    OpenSearchUtil.addElement(
142                            entry, "groupId", OpenSearchUtil.LIFERAY_NAMESPACE, groupId);
143    
144                    // scopeGroupId
145    
146                    OpenSearchUtil.addElement(
147                            entry, "scopeGroupId", OpenSearchUtil.LIFERAY_NAMESPACE,
148                            scopeGroupId);
149    
150                    // entryClassName
151    
152                    OpenSearchUtil.addElement(
153                            entry, "entryClassName", OpenSearchUtil.LIFERAY_NAMESPACE,
154                            entryClassName);
155    
156                    // entryClassPK
157    
158                    OpenSearchUtil.addElement(
159                            entry, "entryClassPK", OpenSearchUtil.LIFERAY_NAMESPACE,
160                            entryClassPK);
161    
162                    // title
163    
164                    OpenSearchUtil.addElement(
165                            entry, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
166    
167                    // link
168    
169                    Element entryLink = OpenSearchUtil.addElement(
170                            entry, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
171    
172                    entryLink.addAttribute("href", link);
173    
174                    // id
175    
176                    OpenSearchUtil.addElement(
177                            entry, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
178                            "urn:uuid:" + PortalUUIDUtil.generate());
179    
180                    // updated
181    
182                    OpenSearchUtil.addElement(
183                            entry, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, updated);
184    
185                    // summary
186    
187                    OpenSearchUtil.addElement(
188                            entry, "summary", OpenSearchUtil.DEFAULT_NAMESPACE, summary);
189    
190                    // tags
191    
192                    OpenSearchUtil.addElement(
193                            entry, "tags", OpenSearchUtil.DEFAULT_NAMESPACE,
194                            StringUtil.merge(tags));
195    
196                    // ratings
197    
198                    OpenSearchUtil.addElement(
199                            entry, "ratings", OpenSearchUtil.DEFAULT_NAMESPACE, ratings);
200    
201                    // relevance:score
202    
203                    OpenSearchUtil.addElement(
204                            entry, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
205            }
206    
207            protected void addSearchResultRSS(
208                    Element root, long groupId, long scopeGroupId, String entryClassName,
209                    long entryClassPK, String title, String link, Date updated,
210                    String summary, String[] tags, double ratings, double score) {
211    
212                    // item
213    
214                    Element item = root.addElement("item");
215    
216                    // groupId
217    
218                    OpenSearchUtil.addElement(
219                            item, "groupId", OpenSearchUtil.LIFERAY_NAMESPACE, groupId);
220    
221                    // scopeGroupId
222    
223                    OpenSearchUtil.addElement(
224                            item, "scopeGroupId", OpenSearchUtil.LIFERAY_NAMESPACE,
225                            scopeGroupId);
226    
227                    // entryClassName
228    
229                    OpenSearchUtil.addElement(
230                            item, "entryClassName", OpenSearchUtil.LIFERAY_NAMESPACE,
231                            entryClassName);
232    
233                    // entryClassPK
234    
235                    OpenSearchUtil.addElement(
236                            item, "entryClassPK", OpenSearchUtil.LIFERAY_NAMESPACE,
237                            entryClassPK);
238    
239                    // title
240    
241                    OpenSearchUtil.addElement(
242                            item, "title", OpenSearchUtil.NO_NAMESPACE, title);
243    
244                    // link
245    
246                    OpenSearchUtil.addElement(
247                            item, "link", OpenSearchUtil.NO_NAMESPACE, link);
248    
249                    // summary
250    
251                    OpenSearchUtil.addElement(
252                            item, "description", OpenSearchUtil.NO_NAMESPACE, summary);
253    
254                    // tags
255    
256                    OpenSearchUtil.addElement(
257                            item, "tags", OpenSearchUtil.NO_NAMESPACE, StringUtil.merge(tags));
258    
259                    // ratings
260    
261                    OpenSearchUtil.addElement(
262                            item, "ratings", OpenSearchUtil.NO_NAMESPACE, ratings);
263    
264                    // relevance:score
265    
266                    OpenSearchUtil.addElement(
267                            item, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
268            }
269    
270            /**
271             * @deprecated
272             */
273            protected Object[] addSearchResults(
274                    String keywords, int startPage, int itemsPerPage, int total, int start,
275                    String title, String searchPath, String format,
276                    ThemeDisplay themeDisplay) {
277    
278                    return addSearchResults(
279                            new String[0], keywords, startPage, itemsPerPage, total, start,
280                            title, searchPath, format, themeDisplay);
281            }
282    
283            protected Object[] addSearchResults(
284                    String[] queryTerms, String keywords, int startPage, int itemsPerPage,
285                    int total, int start, String title, String searchPath, String format,
286                    ThemeDisplay themeDisplay) {
287    
288                    int totalPages = 0;
289    
290                    if (total % itemsPerPage == 0) {
291                            totalPages = total / itemsPerPage;
292                    }
293                    else {
294                            totalPages = (total / itemsPerPage) + 1;
295                    }
296    
297                    int previousPage = startPage - 1;
298                    int nextPage = startPage + 1;
299    
300                    Document doc = SAXReaderUtil.createDocument();
301    
302                    if (format.equals("rss")) {
303                            return addSearchResultsRSS(
304                                    doc, queryTerms, keywords, startPage, itemsPerPage, total,
305                                    start, totalPages, previousPage, nextPage, title, searchPath,
306                                    themeDisplay);
307                    }
308                    else {
309                            return addSearchResultsAtom(
310                                    doc, queryTerms, keywords, startPage, itemsPerPage, total,
311                                    start, totalPages, previousPage, nextPage, title, searchPath,
312                                    themeDisplay);
313                    }
314            }
315    
316            protected Object[] addSearchResultsAtom(
317                    Document doc, String[] queryTerms, String keywords, int startPage,
318                    int itemsPerPage, int total, int start, int totalPages,
319                    int previousPage, int nextPage, String title, String searchPath,
320                    ThemeDisplay themeDisplay) {
321    
322                    // feed
323    
324                    Element root = doc.addElement("feed");
325    
326                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.DEFAULT_NAMESPACE));
327                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
328                    root.add(
329                            OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
330    
331                    // title
332    
333                    OpenSearchUtil.addElement(
334                            root, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
335    
336                    // updated
337    
338                    OpenSearchUtil.addElement(
339                            root, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, new Date());
340    
341                    // author
342    
343                    Element author = OpenSearchUtil.addElement(
344                            root, "author", OpenSearchUtil.DEFAULT_NAMESPACE);
345    
346                    // name
347    
348                    OpenSearchUtil.addElement(
349                            author, "name", OpenSearchUtil.DEFAULT_NAMESPACE,
350                            themeDisplay.getUserId());
351    
352                    // id
353    
354                    OpenSearchUtil.addElement(
355                            root, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
356                            "urn:uuid:" + PortalUUIDUtil.generate());
357    
358                    // queryTerms
359    
360                    OpenSearchUtil.addElement(
361                            root, "queryTerms", OpenSearchUtil.DEFAULT_NAMESPACE,
362                            StringUtil.merge(queryTerms, StringPool.COMMA_AND_SPACE));
363    
364                    // opensearch:totalResults
365    
366                    OpenSearchUtil.addElement(
367                            root, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
368    
369                    // opensearch:startIndex
370    
371                    OpenSearchUtil.addElement(
372                            root, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
373    
374                    // opensearch:itemsPerPage
375    
376                    OpenSearchUtil.addElement(
377                            root, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
378    
379                    // opensearch:Query
380    
381                    Element query = OpenSearchUtil.addElement(
382                            root, "Query", OpenSearchUtil.OS_NAMESPACE);
383    
384                    query.addAttribute("role", "request");
385                    query.addAttribute("searchTerms", keywords);
386                    query.addAttribute("startPage", String.valueOf(startPage));
387    
388                    // links
389    
390                    String searchURL = themeDisplay.getURLPortal() + searchPath;
391    
392                    OpenSearchUtil.addLink(
393                            root, searchURL, "self", keywords, startPage, itemsPerPage);
394                    OpenSearchUtil.addLink(
395                            root, searchURL, "first", keywords, 1, itemsPerPage);
396    
397                    if (previousPage > 0) {
398                            OpenSearchUtil.addLink(
399                                    root, searchURL, "previous", keywords, previousPage,
400                                    itemsPerPage);
401                    }
402    
403                    if (nextPage <= totalPages) {
404                            OpenSearchUtil.addLink(
405                                    root, searchURL, "next", keywords, nextPage, itemsPerPage);
406                    }
407    
408                    OpenSearchUtil.addLink(
409                            root, searchURL, "last", keywords, totalPages, itemsPerPage);
410    
411                    Element link = OpenSearchUtil.addElement(
412                            root, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
413    
414                    link.addAttribute("rel", "search");
415                    link.addAttribute("href", searchPath + "_description.xml");
416                    link.addAttribute("type", "application/opensearchdescription+xml");
417    
418                    return new Object[] {doc, root};
419            }
420    
421            protected Object[] addSearchResultsRSS(
422                    Document doc, String[] queryTerms, String keywords, int startPage,
423                    int itemsPerPage, int total, int start, int totalPages,
424                    int previousPage, int nextPage, String title, String searchPath,
425                    ThemeDisplay themeDisplay) {
426    
427                    // rss
428    
429                    Element root = doc.addElement("rss");
430    
431                    root.addAttribute("version", "2.0");
432                    root.add(
433                            SAXReaderUtil.createNamespace(
434                                    "atom", "http://www.w3.org/2005/Atom"));
435                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
436                    root.add(
437                            OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
438    
439                    // channel
440    
441                    Element channel = root.addElement("channel");
442    
443                    // title
444    
445                    OpenSearchUtil.addElement(
446                            channel, "title", OpenSearchUtil.NO_NAMESPACE, title);
447    
448                    // link
449    
450                    OpenSearchUtil.addElement(
451                            channel, "link", OpenSearchUtil.NO_NAMESPACE,
452                            themeDisplay.getURLPortal() + searchPath);
453    
454                    // description
455    
456                    OpenSearchUtil.addElement(
457                            channel, "description", OpenSearchUtil.NO_NAMESPACE, title);
458    
459                    // queryTerms
460    
461                    OpenSearchUtil.addElement(
462                            channel, "queryTerms", OpenSearchUtil.NO_NAMESPACE,
463                            StringUtil.merge(queryTerms, StringPool.COMMA_AND_SPACE));
464    
465                    // opensearch:totalResults
466    
467                    OpenSearchUtil.addElement(
468                            channel, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
469    
470                    // opensearch:startIndex
471    
472                    OpenSearchUtil.addElement(
473                            channel, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
474    
475                    // opensearch:itemsPerPage
476    
477                    OpenSearchUtil.addElement(
478                            channel, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
479    
480                    // opensearch:Query
481    
482                    Element query = OpenSearchUtil.addElement(
483                            channel, "Query", OpenSearchUtil.OS_NAMESPACE);
484    
485                    query.addAttribute("role", "request");
486                    query.addAttribute("searchTerms", keywords);
487                    query.addAttribute("startPage", String.valueOf(startPage));
488    
489                    return new Object[] {doc, channel};
490            }
491    
492            protected PortletURL getPortletURL(
493                            HttpServletRequest request, String portletId)
494                    throws Exception {
495    
496                    return getPortletURL(request, portletId, 0);
497            }
498    
499            protected PortletURL getPortletURL(
500                            HttpServletRequest request, String portletId, long groupId)
501                    throws Exception {
502    
503                    long plid = LayoutLocalServiceUtil.getDefaultPlid(
504                            groupId, false, portletId);
505    
506                    if (plid == 0) {
507                            plid = LayoutLocalServiceUtil.getDefaultPlid(
508                                    groupId, true, portletId);
509                    }
510    
511                    if (plid == 0) {
512                            Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
513    
514                            if (layout != null) {
515                                    plid = layout.getPlid();
516                            }
517                    }
518    
519                    PortletURL portletURL = PortletURLFactoryUtil.create(
520                            request, portletId, plid, PortletRequest.RENDER_PHASE);
521    
522                    portletURL.setWindowState(WindowState.MAXIMIZED);
523                    portletURL.setPortletMode(PortletMode.VIEW);
524    
525                    return portletURL;
526            }
527    
528            private boolean _enabled = GetterUtil.getBoolean(
529                    PropsUtil.get(getClass().getName()), true);
530    
531    }