1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.search;
21  
22  import com.liferay.portal.SystemException;
23  import com.liferay.portal.kernel.dao.search.SearchContainer;
24  import com.liferay.portal.kernel.search.OpenSearch;
25  import com.liferay.portal.kernel.search.SearchException;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.HttpUtil;
28  import com.liferay.portal.kernel.util.StringUtil;
29  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
30  import com.liferay.portal.kernel.xml.Document;
31  import com.liferay.portal.kernel.xml.Element;
32  import com.liferay.portal.kernel.xml.SAXReaderUtil;
33  import com.liferay.portal.model.Layout;
34  import com.liferay.portal.service.LayoutLocalServiceUtil;
35  import com.liferay.portal.service.UserLocalServiceUtil;
36  import com.liferay.portal.theme.ThemeDisplay;
37  import com.liferay.portal.util.PortalUtil;
38  import com.liferay.portal.util.WebKeys;
39  import com.liferay.portlet.PortletURLImpl;
40  
41  import java.util.Date;
42  
43  import javax.portlet.PortletMode;
44  import javax.portlet.PortletModeException;
45  import javax.portlet.PortletRequest;
46  import javax.portlet.PortletURL;
47  import javax.portlet.WindowState;
48  import javax.portlet.WindowStateException;
49  
50  import javax.servlet.http.HttpServletRequest;
51  
52  /**
53   * <a href="BaseOpenSearchImpl.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Charles May
56   * @author Brian Wing Shun Chan
57   *
58   */
59  public abstract class BaseOpenSearchImpl implements OpenSearch {
60  
61      public boolean isEnabled() {
62          return true;
63      }
64  
65      public String search(HttpServletRequest request, String url)
66          throws SearchException {
67  
68          try {
69              long userId = PortalUtil.getUserId(request);
70  
71              if (userId == 0) {
72                  long companyId = PortalUtil.getCompanyId(request);
73  
74                  userId = UserLocalServiceUtil.getDefaultUserId(companyId);
75              }
76  
77              String keywords = GetterUtil.getString(
78                  HttpUtil.getParameter(url, "keywords", false));
79              int startPage = GetterUtil.getInteger(
80                  HttpUtil.getParameter(url, "p", false), 1);
81              int itemsPerPage = GetterUtil.getInteger(
82                  HttpUtil.getParameter(url, "c", false),
83                  SearchContainer.DEFAULT_DELTA);
84              String format = GetterUtil.getString(
85                  HttpUtil.getParameter(url, "format", false));
86  
87              return search(
88                  request, userId, keywords, startPage, itemsPerPage, format);
89          }
90          catch (SearchException se) {
91              throw se;
92          }
93          catch (Exception e) {
94              throw new SearchException(e);
95          }
96      }
97  
98      public String search(
99              HttpServletRequest request, long userId, String keywords,
100             int startPage, int itemsPerPage, String format)
101         throws SearchException {
102 
103         return search(
104             request, 0, userId, keywords, startPage, itemsPerPage, format);
105     }
106 
107     public abstract String search(
108             HttpServletRequest request, long groupId, long userId,
109             String keywords, int startPage, int itemsPerPage, String format)
110         throws SearchException;
111 
112     protected void addSearchResult(
113         Element root, String title, String link, Date updated,
114         String summary, double score, String format) {
115 
116         addSearchResult(
117             root, title, link, updated, summary, new String[0], 0, score,
118             format);
119     }
120 
121     protected void addSearchResult(
122         Element root, String title, String link, Date updated, String summary,
123         String[] tags, double ratings, double score, String format) {
124 
125         if (format.equals("rss")) {
126             addSearchResultRSS(
127                 root, title, link, updated, summary, tags, ratings, score);
128         }
129         else {
130             addSearchResultAtom(
131                 root, title, link, updated, summary, tags, ratings, score);
132         }
133     }
134 
135     protected void addSearchResultAtom(
136         Element root, String title, String link, Date updated, String summary,
137         String[] tags, double ratings, double score) {
138 
139         // entry
140 
141         Element entry = OpenSearchUtil.addElement(
142             root, "entry", OpenSearchUtil.DEFAULT_NAMESPACE);
143 
144         // title
145 
146         OpenSearchUtil.addElement(
147             entry, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
148 
149         // link
150 
151         Element entryLink = OpenSearchUtil.addElement(
152             entry, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
153 
154         entryLink.addAttribute("href", link);
155 
156         // id
157 
158         OpenSearchUtil.addElement(
159             entry, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
160             "urn:uuid:" + PortalUUIDUtil.generate());
161 
162         // updated
163 
164         OpenSearchUtil.addElement(
165             entry, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, updated);
166 
167         // summary
168 
169         OpenSearchUtil.addElement(
170             entry, "summary", OpenSearchUtil.DEFAULT_NAMESPACE, summary);
171 
172         // tags
173 
174         OpenSearchUtil.addElement(
175             entry, "tags", OpenSearchUtil.DEFAULT_NAMESPACE,
176             StringUtil.merge(tags));
177 
178         // ratings
179 
180         OpenSearchUtil.addElement(
181             entry, "ratings", OpenSearchUtil.DEFAULT_NAMESPACE, ratings);
182 
183         // relevance:score
184 
185         OpenSearchUtil.addElement(
186             entry, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
187     }
188 
189     protected void addSearchResultRSS(
190         Element root, String title, String link, Date updated, String summary,
191         String[] tags, double ratings, double score) {
192 
193         // item
194 
195         Element item = root.addElement("item");
196 
197         // title
198 
199         OpenSearchUtil.addElement(
200             item, "title", OpenSearchUtil.NO_NAMESPACE, title);
201 
202         // link
203 
204         OpenSearchUtil.addElement(
205             item, "link", OpenSearchUtil.NO_NAMESPACE, link);
206 
207         // summary
208 
209         OpenSearchUtil.addElement(
210             item, "description", OpenSearchUtil.NO_NAMESPACE, summary);
211 
212         // tags
213 
214         OpenSearchUtil.addElement(
215             item, "tags", OpenSearchUtil.NO_NAMESPACE, StringUtil.merge(tags));
216 
217         // ratings
218 
219         OpenSearchUtil.addElement(
220             item, "ratings", OpenSearchUtil.NO_NAMESPACE, ratings);
221 
222         // relevance:score
223 
224         OpenSearchUtil.addElement(
225             item, "score", OpenSearchUtil.RELEVANCE_NAMESPACE, score);
226     }
227 
228     protected Object[] addSearchResults(
229         String keywords, int startPage, int itemsPerPage, int total, int start,
230         String title, String searchPath, String format,
231         ThemeDisplay themeDisplay) {
232 
233         int totalPages = 0;
234 
235         if (total % itemsPerPage == 0) {
236             totalPages = total / itemsPerPage;
237         }
238         else {
239             totalPages = (total / itemsPerPage) + 1;
240         }
241 
242         int previousPage = startPage - 1;
243         int nextPage = startPage + 1;
244 
245         Document doc = SAXReaderUtil.createDocument();
246 
247         if (format.equals("rss")) {
248             return addSearchResultsRSS(
249                 doc, keywords, startPage, itemsPerPage, total, start,
250                 totalPages, previousPage, nextPage, title, searchPath,
251                 themeDisplay);
252         }
253         else {
254             return addSearchResultsAtom(
255                 doc, keywords, startPage, itemsPerPage, total, start,
256                 totalPages, previousPage, nextPage, title, searchPath,
257                 themeDisplay);
258         }
259     }
260 
261     protected Object[] addSearchResultsAtom(
262         Document doc, String keywords, int startPage, int itemsPerPage,
263         int total, int start, int totalPages, int previousPage, int nextPage,
264         String title, String searchPath, ThemeDisplay themeDisplay) {
265 
266         // feed
267 
268         Element root = doc.addElement("feed");
269 
270         root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.DEFAULT_NAMESPACE));
271         root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
272         root.add(
273             OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
274 
275         // title
276 
277         OpenSearchUtil.addElement(
278             root, "title", OpenSearchUtil.DEFAULT_NAMESPACE, title);
279 
280         // updated
281 
282         OpenSearchUtil.addElement(
283             root, "updated", OpenSearchUtil.DEFAULT_NAMESPACE, new Date());
284 
285         // author
286 
287         Element author = OpenSearchUtil.addElement(
288             root, "author", OpenSearchUtil.DEFAULT_NAMESPACE);
289 
290         // name
291 
292         OpenSearchUtil.addElement(
293             author, "name", OpenSearchUtil.DEFAULT_NAMESPACE,
294             themeDisplay.getUserId());
295 
296         // id
297 
298         OpenSearchUtil.addElement(
299             root, "id", OpenSearchUtil.DEFAULT_NAMESPACE,
300             "urn:uuid:" + PortalUUIDUtil.generate());
301 
302         // opensearch:totalResults
303 
304         OpenSearchUtil.addElement(
305             root, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
306 
307         // opensearch:startIndex
308 
309         OpenSearchUtil.addElement(
310             root, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
311 
312         // opensearch:itemsPerPage
313 
314         OpenSearchUtil.addElement(
315             root, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
316 
317         // opensearch:Query
318 
319         Element query = OpenSearchUtil.addElement(
320             root, "Query", OpenSearchUtil.OS_NAMESPACE);
321 
322         query.addAttribute("role", "request");
323         query.addAttribute("searchTerms", keywords);
324         query.addAttribute("startPage", String.valueOf(startPage));
325 
326         // links
327 
328         String searchURL = themeDisplay.getURLPortal() + searchPath;
329 
330         OpenSearchUtil.addLink(
331             root, searchURL, "self", keywords, startPage, itemsPerPage);
332         OpenSearchUtil.addLink(
333             root, searchURL, "first", keywords, 1, itemsPerPage);
334 
335         if (previousPage > 0) {
336             OpenSearchUtil.addLink(
337                 root, searchURL, "previous", keywords, previousPage,
338                 itemsPerPage);
339         }
340 
341         if (nextPage <= totalPages) {
342             OpenSearchUtil.addLink(
343                 root, searchURL, "next", keywords, nextPage, itemsPerPage);
344         }
345 
346         OpenSearchUtil.addLink(
347             root, searchURL, "last", keywords, totalPages, itemsPerPage);
348 
349         Element link = OpenSearchUtil.addElement(
350             root, "link", OpenSearchUtil.DEFAULT_NAMESPACE);
351 
352         link.addAttribute("rel", "search");
353         link.addAttribute("href", searchPath + "_description.xml");
354         link.addAttribute("type", "application/opensearchdescription+xml");
355 
356         return new Object[] {doc, root};
357     }
358 
359     protected Object[] addSearchResultsRSS(
360         Document doc, String keywords, int startPage, int itemsPerPage,
361         int total, int start, int totalPages, int previousPage, int nextPage,
362         String title, String searchPath, ThemeDisplay themeDisplay) {
363 
364         // rss
365 
366         Element root = doc.addElement("rss");
367 
368         root.addAttribute("version", "2.0");
369         root.add(
370             SAXReaderUtil.createNamespace(
371                 "atom", "http://www.w3.org/2005/Atom"));
372         root.add(OpenSearchUtil.getNamespace(OpenSearchUtil.OS_NAMESPACE));
373         root.add(
374             OpenSearchUtil.getNamespace(OpenSearchUtil.RELEVANCE_NAMESPACE));
375 
376         // channel
377 
378         Element channel = root.addElement("channel");
379 
380         // title
381 
382         OpenSearchUtil.addElement(
383             channel, "title", OpenSearchUtil.NO_NAMESPACE, title);
384 
385         // link
386 
387         OpenSearchUtil.addElement(
388             channel, "link", OpenSearchUtil.NO_NAMESPACE,
389             themeDisplay.getURLPortal() + searchPath);
390 
391         // description
392 
393         OpenSearchUtil.addElement(
394             channel, "description", OpenSearchUtil.NO_NAMESPACE, title);
395 
396         // opensearch:totalResults
397 
398         OpenSearchUtil.addElement(
399             channel, "totalResults", OpenSearchUtil.OS_NAMESPACE, total);
400 
401         // opensearch:startIndex
402 
403         OpenSearchUtil.addElement(
404             channel, "startIndex", OpenSearchUtil.OS_NAMESPACE, start + 1);
405 
406         // opensearch:itemsPerPage
407 
408         OpenSearchUtil.addElement(
409             channel, "itemsPerPage", OpenSearchUtil.OS_NAMESPACE, itemsPerPage);
410 
411         // opensearch:Query
412 
413         Element query = OpenSearchUtil.addElement(
414             channel, "Query", OpenSearchUtil.OS_NAMESPACE);
415 
416         query.addAttribute("role", "request");
417         query.addAttribute("searchTerms", keywords);
418         query.addAttribute("startPage", String.valueOf(startPage));
419 
420         return new Object[] {doc, channel};
421     }
422 
423     protected PortletURL getPortletURL(
424             HttpServletRequest request, String portletId)
425         throws PortletModeException, SystemException, WindowStateException {
426 
427         return getPortletURL(request, portletId, 0);
428     }
429 
430     protected PortletURL getPortletURL(
431             HttpServletRequest request, String portletId, long groupId)
432         throws PortletModeException, SystemException, WindowStateException {
433 
434         long plid = LayoutLocalServiceUtil.getDefaultPlid(
435             groupId, false, portletId);
436 
437         if (plid == 0) {
438             plid = LayoutLocalServiceUtil.getDefaultPlid(
439                 groupId, true, portletId);
440         }
441 
442         if (plid == 0) {
443             Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
444 
445             if (layout != null) {
446                 plid = layout.getPlid();
447             }
448         }
449 
450         PortletURL portletURL = new PortletURLImpl(
451             request, portletId, plid, PortletRequest.RENDER_PHASE);
452 
453         portletURL.setWindowState(WindowState.MAXIMIZED);
454         portletURL.setPortletMode(PortletMode.VIEW);
455 
456         return portletURL;
457     }
458 
459 }