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