001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
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.model.Layout;
019    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
020    import com.liferay.portal.kernel.portlet.PortletProvider;
021    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
022    import com.liferay.portal.kernel.portlet.PortletURLFactoryUtil;
023    import com.liferay.portal.kernel.service.LayoutServiceUtil;
024    import com.liferay.portal.kernel.service.UserLocalServiceUtil;
025    import com.liferay.portal.kernel.theme.ThemeDisplay;
026    import com.liferay.portal.kernel.util.ClassUtil;
027    import com.liferay.portal.kernel.util.GetterUtil;
028    import com.liferay.portal.kernel.util.HttpUtil;
029    import com.liferay.portal.kernel.util.PortalUtil;
030    import com.liferay.portal.kernel.util.PropsUtil;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.util.WebKeys;
035    import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
036    import com.liferay.portal.kernel.xml.Document;
037    import com.liferay.portal.kernel.xml.Element;
038    import com.liferay.portal.kernel.xml.SAXReaderUtil;
039    
040    import java.util.Date;
041    
042    import javax.portlet.PortletMode;
043    import javax.portlet.PortletRequest;
044    import javax.portlet.PortletURL;
045    import javax.portlet.WindowState;
046    
047    import javax.servlet.http.HttpServletRequest;
048    
049    /**
050     * @author Charles May
051     * @author Brian Wing Shun Chan
052     */
053    public abstract class BaseOpenSearchImpl implements OpenSearch {
054    
055            public BaseOpenSearchImpl() {
056                    Class<?> clazz = getClass();
057    
058                    _enabled = GetterUtil.getBoolean(PropsUtil.get(clazz.getName()), true);
059    
060                    _openSearchURL = StringPool.BLANK;
061                    _openSearchDescriptionURL = StringPool.BLANK;
062            }
063    
064            public BaseOpenSearchImpl(
065                    String openSearchURL, String openSearchDescriptionURL) {
066    
067                    _openSearchURL = openSearchURL;
068                    _openSearchDescriptionURL = openSearchDescriptionURL;
069    
070                    _enabled = GetterUtil.getBoolean(
071                            PropsUtil.get(ClassUtil.getClassName(this)), true);
072            }
073    
074            @Override
075            public String getClassName() {
076                    return StringPool.BLANK;
077            }
078    
079            @Override
080            public boolean isEnabled() {
081                    return _enabled;
082            }
083    
084            @Override
085            public abstract String search(
086                            HttpServletRequest request, long groupId, long userId,
087                            String keywords, int startPage, int itemsPerPage, String format)
088                    throws SearchException;
089    
090            @Override
091            public String search(
092                            HttpServletRequest request, long userId, String keywords,
093                            int startPage, int itemsPerPage, String format)
094                    throws SearchException {
095    
096                    return search(
097                            request, 0, userId, keywords, startPage, itemsPerPage, format);
098            }
099    
100            @Override
101            public String search(HttpServletRequest request, String url)
102                    throws SearchException {
103    
104                    try {
105                            long userId = PortalUtil.getUserId(request);
106    
107                            if (userId == 0) {
108                                    long companyId = PortalUtil.getCompanyId(request);
109    
110                                    userId = UserLocalServiceUtil.getDefaultUserId(companyId);
111                            }
112    
113                            String keywords = GetterUtil.getString(
114                                    HttpUtil.getParameter(url, "keywords", false));
115                            int startPage = GetterUtil.getInteger(
116                                    HttpUtil.getParameter(url, "p", false), 1);
117                            int itemsPerPage = GetterUtil.getInteger(
118                                    HttpUtil.getParameter(url, "c", false),
119                                    SearchContainer.DEFAULT_DELTA);
120                            String format = GetterUtil.getString(
121                                    HttpUtil.getParameter(url, "format", false));
122    
123                            return search(
124                                    request, userId, keywords, startPage, itemsPerPage, format);
125                    }
126                    catch (SearchException se) {
127                            throw se;
128                    }
129                    catch (Exception e) {
130                            throw new SearchException(e);
131                    }
132            }
133    
134            protected void addSearchResult(
135                    Element root, long groupId, long scopeGroupId, String entryClassName,
136                    long entryClassPK, String title, String link, Date updated,
137                    String summary, double score, String format) {
138    
139                    addSearchResult(
140                            root, groupId, scopeGroupId, entryClassName, entryClassPK, title,
141                            link, updated, summary, new String[0], 0, score, format);
142            }
143    
144            protected void addSearchResult(
145                    Element root, long groupId, long scopeGroupId, String entryClassName,
146                    long entryClassPK, String title, String link, Date updated,
147                    String summary, String[] tags, double ratings, double score,
148                    String format) {
149    
150                    if (format.equals("rss")) {
151                            addSearchResultRSS(
152                                    root, groupId, scopeGroupId, entryClassName, entryClassPK,
153                                    title, link, updated, summary, tags, ratings, score);
154                    }
155                    else {
156                            addSearchResultAtom(
157                                    root, groupId, scopeGroupId, entryClassName, entryClassPK,
158                                    title, link, updated, summary, tags, ratings, score);
159                    }
160            }
161    
162            protected void addSearchResultAtom(
163                    Element root, long groupId, long scopeGroupId, String entryClassName,
164                    long entryClassPK, String title, String link, Date updated,
165                    String summary, String[] tags, double ratings, double score) {
166    
167                    // entry
168    
169                    Element entry = OpenSearchUtil.addElement(
170                            root, "entry", OpenSearchUtil.DEFAULT_NAMESPACE);
171    
172                    // groupId
173    
174                    OpenSearchUtil.addElement(
175                            entry, "groupId", OpenSearchUtil.LIFERAY_NAMESPACE, groupId);
176    
177                    // scopeGroupId
178    
179                    OpenSearchUtil.addElement(
180                            entry, "scopeGroupId", OpenSearchUtil.LIFERAY_NAMESPACE,
181                            scopeGroupId);
182    
183                    // entryClassName
184    
185                    OpenSearchUtil.addElement(
186                            entry, "entryClassName", OpenSearchUtil.LIFERAY_NAMESPACE,
187                            entryClassName);
188    
189                    // entryClassPK
190    
191                    OpenSearchUtil.addElement(
192                            entry, "entryClassPK", OpenSearchUtil.LIFERAY_NAMESPACE,
193                            entryClassPK);
194    
195                    // title
196    
197                    OpenSearchUtil.addElement(
198                            entry, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
199    
200                    // link
201    
202                    Element entryLink = OpenSearchUtil.addElement(
203                            entry, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
204    
205                    entryLink.addAttribute("href", link);
206    
207                    // id
208    
209                    OpenSearchUtil.addElement(
210                            entry, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
211                            "urn:uuid:" + PortalUUIDUtil.generate());
212    
213                    // updated
214    
215                    OpenSearchUtil.addElement(
216                            entry, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, updated);
217    
218                    // summary
219    
220                    OpenSearchUtil.addElement(
221                            entry, "summary", OpenSearchUtil.DEFAULT_NAMESPACE, summary);
222    
223                    // tags
224    
225                    OpenSearchUtil.addElement(
226                            entry, "tags", OpenSearchUtil.DEFAULT_NAMESPACE,
227                            StringUtil.merge(tags));
228    
229                    // ratings
230    
231                    OpenSearchUtil.addElement(
232                            entry, "ratings", OpenSearchUtil.DEFAULT_NAMESPACE, ratings);
233    
234                    // relevance:score
235    
236                    OpenSearchUtil.addElement(
237                            entry, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
238            }
239    
240            protected void addSearchResultRSS(
241                    Element root, long groupId, long scopeGroupId, String entryClassName,
242                    long entryClassPK, String title, String link, Date updated,
243                    String summary, String[] tags, double ratings, double score) {
244    
245                    // item
246    
247                    Element item = root.addElement("item");
248    
249                    // groupId
250    
251                    OpenSearchUtil.addElement(
252                            item, "groupId", OpenSearchUtil.LIFERAY_NAMESPACE, groupId);
253    
254                    // scopeGroupId
255    
256                    OpenSearchUtil.addElement(
257                            item, "scopeGroupId", OpenSearchUtil.LIFERAY_NAMESPACE,
258                            scopeGroupId);
259    
260                    // entryClassName
261    
262                    OpenSearchUtil.addElement(
263                            item, "entryClassName", OpenSearchUtil.LIFERAY_NAMESPACE,
264                            entryClassName);
265    
266                    // entryClassPK
267    
268                    OpenSearchUtil.addElement(
269                            item, "entryClassPK", OpenSearchUtil.LIFERAY_NAMESPACE,
270                            entryClassPK);
271    
272                    // title
273    
274                    OpenSearchUtil.addElement(
275                            item, "title", OpenSearchUtil.NO_NAMESPACE, title);
276    
277                    // link
278    
279                    OpenSearchUtil.addElement(
280                            item, "link", OpenSearchUtil.NO_NAMESPACE, link);
281    
282                    // summary
283    
284                    OpenSearchUtil.addElement(
285                            item, "description", OpenSearchUtil.NO_NAMESPACE, summary);
286    
287                    // tags
288    
289                    OpenSearchUtil.addElement(
290                            item, "tags", OpenSearchUtil.NO_NAMESPACE, StringUtil.merge(tags));
291    
292                    // ratings
293    
294                    OpenSearchUtil.addElement(
295                            item, "ratings", OpenSearchUtil.NO_NAMESPACE, ratings);
296    
297                    // relevance:score
298    
299                    OpenSearchUtil.addElement(
300                            item, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
301            }
302    
303            protected Object[] addSearchResults(
304                    String[] queryTerms, String keywords, int startPage, int itemsPerPage,
305                    int total, int start, String title, String searchPath, String format,
306                    ThemeDisplay themeDisplay) {
307    
308                    int totalPages = 0;
309    
310                    if ((total % itemsPerPage) == 0) {
311                            totalPages = total / itemsPerPage;
312                    }
313                    else {
314                            totalPages = (total / itemsPerPage) + 1;
315                    }
316    
317                    int previousPage = startPage - 1;
318                    int nextPage = startPage + 1;
319    
320                    Document doc = SAXReaderUtil.createDocument();
321    
322                    if (format.equals("rss")) {
323                            return addSearchResultsRSS(
324                                    doc, queryTerms, keywords, startPage, itemsPerPage, total,
325                                    start, totalPages, previousPage, nextPage, title, searchPath,
326                                    themeDisplay);
327                    }
328                    else {
329                            return addSearchResultsAtom(
330                                    doc, queryTerms, keywords, startPage, itemsPerPage, total,
331                                    start, totalPages, previousPage, nextPage, title, searchPath,
332                                    themeDisplay);
333                    }
334            }
335    
336            protected Object[] addSearchResultsAtom(
337                    Document doc, String[] queryTerms, String keywords, int startPage,
338                    int itemsPerPage, int total, int start, int totalPages,
339                    int previousPage, int nextPage, String title, String searchPath,
340                    ThemeDisplay themeDisplay) {
341    
342                    // feed
343    
344                    Element root = doc.addElement("feed");
345    
346                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.DEFAULT_NAMESPACE));
347                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
348                    root.add(
349                            OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
350    
351                    // title
352    
353                    OpenSearchUtil.addElement(
354                            root, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
355    
356                    // updated
357    
358                    OpenSearchUtil.addElement(
359                            root, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, new Date());
360    
361                    // author
362    
363                    Element author = OpenSearchUtil.addElement(
364                            root, "author", OpenSearchUtil.DEFAULT_NAMESPACE);
365    
366                    // name
367    
368                    OpenSearchUtil.addElement(
369                            author, "name", OpenSearchUtil.DEFAULT_NAMESPACE,
370                            themeDisplay.getUserId());
371    
372                    // id
373    
374                    OpenSearchUtil.addElement(
375                            root, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
376                            "urn:uuid:" + PortalUUIDUtil.generate());
377    
378                    // queryTerms
379    
380                    OpenSearchUtil.addElement(
381                            root, "queryTerms", OpenSearchUtil.DEFAULT_NAMESPACE,
382                            StringUtil.merge(queryTerms, StringPool.COMMA_AND_SPACE));
383    
384                    // opensearch:totalResults
385    
386                    OpenSearchUtil.addElement(
387                            root, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
388    
389                    // opensearch:startIndex
390    
391                    OpenSearchUtil.addElement(
392                            root, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
393    
394                    // opensearch:itemsPerPage
395    
396                    OpenSearchUtil.addElement(
397                            root, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
398    
399                    // opensearch:Query
400    
401                    Element query = OpenSearchUtil.addElement(
402                            root, "Query", OpenSearchUtil.OS_NAMESPACE);
403    
404                    query.addAttribute("role", "request");
405                    query.addAttribute("searchTerms", keywords);
406                    query.addAttribute("startPage", String.valueOf(startPage));
407    
408                    // links
409    
410                    String searchURL = getOpenSearchURL(searchPath, themeDisplay);
411    
412                    OpenSearchUtil.addLink(
413                            root, searchURL, "self", keywords, startPage, itemsPerPage);
414                    OpenSearchUtil.addLink(
415                            root, searchURL, "first", keywords, 1, itemsPerPage);
416    
417                    if (previousPage > 0) {
418                            OpenSearchUtil.addLink(
419                                    root, searchURL, "previous", keywords, previousPage,
420                                    itemsPerPage);
421                    }
422    
423                    if (nextPage <= totalPages) {
424                            OpenSearchUtil.addLink(
425                                    root, searchURL, "next", keywords, nextPage, itemsPerPage);
426                    }
427    
428                    OpenSearchUtil.addLink(
429                            root, searchURL, "last", keywords, totalPages, itemsPerPage);
430    
431                    Element link = OpenSearchUtil.addElement(
432                            root, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
433    
434                    link.addAttribute("rel", "search");
435                    link.addAttribute(
436                            "href", getOpenSearchDescriptionURL(searchPath, themeDisplay));
437                    link.addAttribute("type", "application/opensearchdescription+xml");
438    
439                    return new Object[] {doc, root};
440            }
441    
442            protected Object[] addSearchResultsRSS(
443                    Document doc, String[] queryTerms, String keywords, int startPage,
444                    int itemsPerPage, int total, int start, int totalPages,
445                    int previousPage, int nextPage, String title, String searchPath,
446                    ThemeDisplay themeDisplay) {
447    
448                    // rss
449    
450                    Element root = doc.addElement("rss");
451    
452                    root.addAttribute("version", "2.0");
453                    root.add(
454                            SAXReaderUtil.createNamespace(
455                                    "atom", "http://www.w3.org/2005/Atom"));
456                    root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
457                    root.add(
458                            OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
459    
460                    // channel
461    
462                    Element channel = root.addElement("channel");
463    
464                    // title
465    
466                    OpenSearchUtil.addElement(
467                            channel, "title", OpenSearchUtil.NO_NAMESPACE, title);
468    
469                    // link
470    
471                    OpenSearchUtil.addElement(
472                            channel, "link", OpenSearchUtil.NO_NAMESPACE,
473                            getOpenSearchURL(searchPath, themeDisplay));
474    
475                    // description
476    
477                    OpenSearchUtil.addElement(
478                            channel, "description", OpenSearchUtil.NO_NAMESPACE, title);
479    
480                    // queryTerms
481    
482                    OpenSearchUtil.addElement(
483                            channel, "queryTerms", OpenSearchUtil.NO_NAMESPACE,
484                            StringUtil.merge(queryTerms, StringPool.COMMA_AND_SPACE));
485    
486                    // opensearch:totalResults
487    
488                    OpenSearchUtil.addElement(
489                            channel, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
490    
491                    // opensearch:startIndex
492    
493                    OpenSearchUtil.addElement(
494                            channel, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
495    
496                    // opensearch:itemsPerPage
497    
498                    OpenSearchUtil.addElement(
499                            channel, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
500    
501                    // opensearch:Query
502    
503                    Element query = OpenSearchUtil.addElement(
504                            channel, "Query", OpenSearchUtil.OS_NAMESPACE);
505    
506                    query.addAttribute("role", "request");
507                    query.addAttribute("searchTerms", keywords);
508                    query.addAttribute("startPage", String.valueOf(startPage));
509    
510                    return new Object[] {doc, channel};
511            }
512    
513            protected String getOpenSearchDescriptionURL(
514                    String searchPath, ThemeDisplay themeDisplay) {
515    
516                    if (Validator.isNotNull(_openSearchDescriptionURL)) {
517                            return _openSearchDescriptionURL;
518                    }
519    
520                    return themeDisplay.getPortalURL() + searchPath + "_description.xml";
521            }
522    
523            protected String getOpenSearchURL(
524                    String searchPath, ThemeDisplay themeDisplay) {
525    
526                    if (Validator.isNotNull(_openSearchURL)) {
527                            return _openSearchURL;
528                    }
529    
530                    return themeDisplay.getPortalURL() + searchPath;
531            }
532    
533            protected long getPlid(
534                            HttpServletRequest request, String portletId, long scopeGroupId)
535                    throws Exception {
536    
537                    Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
538    
539                    long layoutGroupId = scopeGroupId;
540    
541                    if (layout != null) {
542                            layoutGroupId = layout.getGroupId();
543                    }
544    
545                    long plid = LayoutServiceUtil.getDefaultPlid(
546                            layoutGroupId, scopeGroupId, false, portletId);
547    
548                    if (plid == 0) {
549                            plid = LayoutServiceUtil.getDefaultPlid(
550                                    layoutGroupId, scopeGroupId, true, portletId);
551                    }
552    
553                    if (plid == 0) {
554                            if (layout != null) {
555                                    plid = layout.getPlid();
556                            }
557                    }
558    
559                    return plid;
560            }
561    
562            protected PortletURL getPortletURL(
563                            HttpServletRequest request, String portletId)
564                    throws Exception {
565    
566                    return getPortletURL(request, portletId, 0);
567            }
568    
569            protected PortletURL getPortletURL(
570                            HttpServletRequest request, String portletId, long scopeGroupId)
571                    throws Exception {
572    
573                    long plid = getPlid(request, portletId, scopeGroupId);
574    
575                    PortletURL portletURL = PortletURLFactoryUtil.create(
576                            request, portletId, plid, PortletRequest.RENDER_PHASE);
577    
578                    portletURL.setPortletMode(PortletMode.VIEW);
579                    portletURL.setWindowState(WindowState.MAXIMIZED);
580    
581                    return portletURL;
582            }
583    
584            protected PortletURL getPortletURL(
585                            HttpServletRequest request, String className,
586                            PortletProvider.Action action, long scopeGroupId)
587                    throws Exception {
588    
589                    LiferayPortletURL portletURL =
590                            (LiferayPortletURL)PortletProviderUtil.getPortletURL(
591                                    request, className, action);
592    
593                    long plid = getPlid(request, portletURL.getPortletId(), scopeGroupId);
594    
595                    portletURL.setPlid(plid);
596    
597                    portletURL.setPortletMode(PortletMode.VIEW);
598                    portletURL.setWindowState(WindowState.MAXIMIZED);
599    
600                    return portletURL;
601            }
602    
603            private final boolean _enabled;
604            private final String _openSearchDescriptionURL;
605            private final String _openSearchURL;
606    
607    }