1   /**
2    * Copyright (c) 2000-2010 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   *
12   *
13   */
14  
15  package com.liferay.portlet;
16  
17  import com.liferay.portal.PortalException;
18  import com.liferay.portal.SystemException;
19  import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
23  import com.liferay.portal.kernel.portlet.LiferayPortletURL;
24  import com.liferay.portal.kernel.servlet.URLEncoder;
25  import com.liferay.portal.kernel.util.ArrayUtil;
26  import com.liferay.portal.kernel.util.GetterUtil;
27  import com.liferay.portal.kernel.util.ParamUtil;
28  import com.liferay.portal.kernel.util.Validator;
29  import com.liferay.portal.model.Layout;
30  import com.liferay.portal.model.LayoutConstants;
31  import com.liferay.portal.model.Portlet;
32  import com.liferay.portal.model.PortletApp;
33  import com.liferay.portal.model.PortletURLListener;
34  import com.liferay.portal.service.LayoutLocalServiceUtil;
35  import com.liferay.portal.service.PortletLocalServiceUtil;
36  import com.liferay.portal.util.PortalUtil;
37  import com.liferay.portal.util.WebKeys;
38  
39  import java.io.Writer;
40  
41  import java.lang.reflect.Constructor;
42  import java.lang.reflect.Method;
43  
44  import java.util.ArrayList;
45  import java.util.LinkedHashMap;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Set;
49  
50  import javax.portlet.MimeResponse;
51  import javax.portlet.PortletException;
52  import javax.portlet.PortletModeException;
53  import javax.portlet.PortletPreferences;
54  import javax.portlet.PortletRequest;
55  import javax.portlet.PortletResponse;
56  import javax.portlet.PortletURL;
57  import javax.portlet.PortletURLGenerationListener;
58  import javax.portlet.ResourceURL;
59  import javax.portlet.WindowStateException;
60  
61  import javax.servlet.http.Cookie;
62  import javax.servlet.http.HttpServletRequest;
63  import javax.servlet.http.HttpServletResponse;
64  
65  import javax.xml.parsers.DocumentBuilder;
66  import javax.xml.parsers.DocumentBuilderFactory;
67  import javax.xml.parsers.ParserConfigurationException;
68  import javax.xml.transform.OutputKeys;
69  import javax.xml.transform.Transformer;
70  import javax.xml.transform.TransformerFactory;
71  import javax.xml.transform.dom.DOMSource;
72  import javax.xml.transform.stream.StreamResult;
73  
74  import org.w3c.dom.DOMException;
75  import org.w3c.dom.Document;
76  import org.w3c.dom.Element;
77  
78  /**
79   * <a href="PortletResponseImpl.java.html"><b><i>View Source</i></b></a>
80   *
81   * @author Brian Wing Shun Chan
82   */
83  public abstract class PortletResponseImpl implements LiferayPortletResponse {
84  
85      public static PortletResponseImpl getPortletResponseImpl(
86          PortletResponse portletResponse) {
87  
88          PortletResponseImpl portletResponseImpl = null;
89  
90          if (portletResponse instanceof PortletResponseImpl) {
91              portletResponseImpl = (PortletResponseImpl)portletResponse;
92          }
93          else {
94  
95              // LEP-4033
96  
97              try {
98                  Method method = portletResponse.getClass().getMethod(
99                      "getResponse");
100 
101                 Object obj = method.invoke(portletResponse, (Object[])null);
102 
103                 portletResponseImpl = getPortletResponseImpl(
104                     (PortletResponse)obj);
105             }
106             catch (Exception e) {
107                 throw new RuntimeException(
108                     "Unable to get the portlet response from " +
109                         portletResponse.getClass().getName());
110             }
111         }
112 
113         return portletResponseImpl;
114     }
115 
116     public void addDateHeader(String name, long date) {
117         if (Validator.isNull(name)) {
118             throw new IllegalArgumentException();
119         }
120 
121         Long[] values = (Long[])_headers.get(name);
122 
123         if (values == null) {
124             setDateHeader(name, date);
125         }
126         else {
127             values = ArrayUtil.append(values, new Long(date));
128 
129             _headers.put(name, values);
130         }
131     }
132 
133     public void addHeader(String name, String value) {
134         if (Validator.isNull(name)) {
135             throw new IllegalArgumentException();
136         }
137 
138         String[] values = (String[])_headers.get(name);
139 
140         if (values == null) {
141             setHeader(name, value);
142         }
143         else {
144             values = ArrayUtil.append(values, value);
145 
146             _headers.put(name, values);
147         }
148     }
149 
150     public void addIntHeader(String name, int value) {
151         if (Validator.isNull(name)) {
152             throw new IllegalArgumentException();
153         }
154 
155         Integer[] values = (Integer[])_headers.get(name);
156 
157         if (values == null) {
158             setIntHeader(name, value);
159         }
160         else {
161             values = ArrayUtil.append(values, new Integer(value));
162 
163             _headers.put(name, values);
164         }
165     }
166 
167     public void addProperty(Cookie cookie) {
168         if (cookie == null) {
169             throw new IllegalArgumentException();
170         }
171 
172         Cookie[] cookies = (Cookie[])_headers.get("cookies");
173 
174         if (cookies == null) {
175             _headers.put("cookies", new Cookie[] {cookie});
176         }
177         else {
178             cookies = ArrayUtil.append(cookies, cookie);
179 
180             _headers.put("cookies", cookies);
181         }
182     }
183 
184     public void addProperty(String key, Element element) {
185         if (key == null) {
186             throw new IllegalArgumentException();
187         }
188 
189         if (key.equalsIgnoreCase(MimeResponse.MARKUP_HEAD_ELEMENT)) {
190             List<Element> values = _markupHeadElements.get(key);
191 
192             if (values != null) {
193                 if (element != null) {
194                     values.add(element);
195                 }
196                 else {
197                     _markupHeadElements.remove(key);
198                 }
199             }
200             else {
201                 if (element != null) {
202                     values = new ArrayList<Element>();
203 
204                     values.add(element);
205 
206                     _markupHeadElements.put(key, values);
207                 }
208             }
209         }
210     }
211 
212     public void addProperty(String key, String value) {
213         if (Validator.isNull(key)) {
214             throw new IllegalArgumentException();
215         }
216 
217         addHeader(key, value);
218     }
219 
220     public PortletURL createActionURL() {
221         return createActionURL(_portletName);
222     }
223 
224     public LiferayPortletURL createActionURL(String portletName) {
225         return createLiferayPortletURL(
226             portletName, PortletRequest.ACTION_PHASE);
227     }
228 
229     public Element createElement(String tagName) throws DOMException {
230         if (_document == null) {
231             try {
232                 DocumentBuilderFactory documentBuilderFactory =
233                     DocumentBuilderFactory.newInstance();
234 
235                 DocumentBuilder documentBuilder =
236                     documentBuilderFactory.newDocumentBuilder();
237 
238                 _document = documentBuilder.newDocument();
239             }
240             catch (ParserConfigurationException pce) {
241                 throw new DOMException(
242                     DOMException.INVALID_STATE_ERR, pce.getMessage());
243             }
244         }
245 
246         return _document.createElement(tagName);
247     }
248 
249     public LiferayPortletURL createLiferayPortletURL(
250         long plid, String portletName, String lifecycle) {
251 
252         try {
253             Layout layout = (Layout)_portletRequestImpl.getAttribute(
254                 WebKeys.LAYOUT);
255 
256             PortletPreferences portletSetup =
257                 PortletPreferencesFactoryUtil.getLayoutPortletSetup(
258                     layout, _portletName);
259 
260             long layoutId = GetterUtil.getLong(portletSetup.getValue(
261                 "portlet-setup-link-to-layout-id", null));
262 
263             if (layoutId > 0) {
264                 try {
265                     Layout linkedLayout = LayoutLocalServiceUtil.getLayout(
266                         layout.getGroupId(), layout.isPrivateLayout(),
267                         layoutId);
268 
269                     plid = linkedLayout.getPlid();
270                 }
271                 catch (PortalException pe) {
272                 }
273             }
274             else {
275 
276                 // Backwards compatibility
277 
278                 plid = GetterUtil.getLong(portletSetup.getValue(
279                     "portlet-setup-link-to-plid", String.valueOf(plid)));
280             }
281         }
282         catch (SystemException e) {
283             if (_log.isWarnEnabled()) {
284                 _log.warn(e);
285             }
286         }
287 
288         if (plid == LayoutConstants.DEFAULT_PLID) {
289             plid = _plid;
290         }
291 
292         PortletURLImpl portletURLImpl = null;
293 
294         Portlet portlet = getPortlet();
295 
296         String portletURLClass = portlet.getPortletURLClass();
297 
298         if (portlet.getPortletId().equals(portletName) &&
299             Validator.isNotNull(portletURLClass)) {
300 
301             try {
302                 Class<?> portletURLClassObj = Class.forName(portletURLClass);
303 
304                 Constructor<?> constructor = portletURLClassObj.getConstructor(
305                     new Class[] {
306                         com.liferay.portlet.PortletResponseImpl.class,
307                         long.class, String.class
308                     });
309 
310                 portletURLImpl = (PortletURLImpl)constructor.newInstance(
311                     new Object[] {this, plid, lifecycle});
312             }
313             catch (Exception e) {
314                 _log.error(e);
315             }
316         }
317 
318         if (portletURLImpl == null) {
319             portletURLImpl = new PortletURLImpl(
320                 _portletRequestImpl, portletName, plid, lifecycle);
321         }
322 
323         PortletApp portletApp = portlet.getPortletApp();
324 
325         Set<PortletURLListener> portletURLListeners =
326             portletApp.getPortletURLListeners();
327 
328         for (PortletURLListener portletURLListener : portletURLListeners) {
329             try {
330                 PortletURLGenerationListener portletURLGenerationListener =
331                     PortletURLListenerFactory.create(portletURLListener);
332 
333                 if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
334                     portletURLGenerationListener.filterActionURL(
335                         portletURLImpl);
336                 }
337                 else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
338                     portletURLGenerationListener.filterRenderURL(
339                         portletURLImpl);
340                 }
341                 else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
342                     portletURLGenerationListener.filterResourceURL(
343                         portletURLImpl);
344                 }
345             }
346             catch (PortletException pe) {
347                 _log.error(pe, pe);
348             }
349         }
350 
351         try {
352             portletURLImpl.setWindowState(_portletRequestImpl.getWindowState());
353         }
354         catch (WindowStateException wse) {
355             _log.error(wse.getMessage());
356         }
357 
358         try {
359             portletURLImpl.setPortletMode(_portletRequestImpl.getPortletMode());
360         }
361         catch (PortletModeException pme) {
362             _log.error(pme.getMessage());
363         }
364 
365         if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
366             portletURLImpl.setCopyCurrentPublicRenderParameters(true);
367         }
368 
369         if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
370             portletURLImpl.setCopyCurrentPublicRenderParameters(true);
371             portletURLImpl.setCopyCurrentRenderParameters(true);
372         }
373 
374         return portletURLImpl;
375     }
376 
377     public LiferayPortletURL createLiferayPortletURL(String lifecycle) {
378         return createLiferayPortletURL(_portletName, lifecycle);
379     }
380 
381     public LiferayPortletURL createLiferayPortletURL(
382         String portletName, String lifecycle) {
383 
384         return createLiferayPortletURL(_plid, portletName, lifecycle);
385     }
386 
387     public PortletURL createRenderURL() {
388         return createRenderURL(_portletName);
389     }
390 
391     public LiferayPortletURL createRenderURL(String portletName) {
392         return createLiferayPortletURL(
393             portletName, PortletRequest.RENDER_PHASE);
394     }
395 
396     public ResourceURL createResourceURL() {
397         return createResourceURL(_portletName);
398     }
399 
400     public LiferayPortletURL createResourceURL(String portletName) {
401         return createLiferayPortletURL(
402             portletName, PortletRequest.RESOURCE_PHASE);
403     }
404 
405     public String encodeURL(String path) {
406         if ((path == null) ||
407             (!path.startsWith("#") && !path.startsWith("/") &&
408                 (path.indexOf("://") == -1))) {
409 
410             // Allow '#' as well to workaround a bug in Oracle ADF 10.1.3
411 
412             throw new IllegalArgumentException(
413                 "URL path must start with a '/' or include '://'");
414         }
415 
416         if (_urlEncoder != null) {
417             return _urlEncoder.encodeURL(_response, path);
418         }
419         else {
420             return path;
421         }
422     }
423 
424     public long getCompanyId() {
425         return _companyId;
426     }
427 
428     public HttpServletRequest getHttpServletRequest() {
429         return _portletRequestImpl.getHttpServletRequest();
430     }
431 
432     public HttpServletResponse getHttpServletResponse() {
433         return _response;
434     }
435 
436     public abstract String getLifecycle();
437 
438     public String getNamespace() {
439         if (_wsrp) {
440             return "wsrp_rewrite_";
441         }
442 
443         if (_namespace == null) {
444             _namespace = PortalUtil.getPortletNamespace(_portletName);
445         }
446 
447         return _namespace;
448     }
449 
450     public long getPlid() {
451         return _plid;
452     }
453 
454     public Portlet getPortlet() {
455         if (_portlet == null) {
456             try {
457                 _portlet = PortletLocalServiceUtil.getPortletById(
458                     _companyId, _portletName);
459             }
460             catch (Exception e) {
461                 _log.error(e);
462             }
463         }
464 
465         return _portlet;
466     }
467 
468     public String getPortletName() {
469         return _portletName;
470     }
471 
472     public PortletRequestImpl getPortletRequest() {
473         return _portletRequestImpl;
474     }
475 
476     public Map<String, String[]> getProperties() {
477         Map<String, String[]> properties =
478             new LinkedHashMap<String, String[]>();
479 
480         for (Map.Entry<String, Object> entry : _headers.entrySet()) {
481             String name = entry.getKey();
482             Object[] values = (Object[])entry.getValue();
483 
484             String[] valuesString = new String[values.length];
485 
486             for (int i = 0; i < values.length; i++) {
487                 valuesString[i] = values[i].toString();
488             }
489 
490             properties.put(name, valuesString);
491         }
492 
493         return properties;
494     }
495 
496     public URLEncoder getUrlEncoder() {
497         return _urlEncoder;
498     }
499 
500     public void setDateHeader(String name, long date) {
501         if (Validator.isNull(name)) {
502             throw new IllegalArgumentException();
503         }
504 
505         if (date <= 0) {
506             _headers.remove(name);
507         }
508         else {
509             _headers.put(name, new Long[] {new Long(date)});
510         }
511     }
512 
513     public void setHeader(String name, String value) {
514         if (Validator.isNull(name)) {
515             throw new IllegalArgumentException();
516         }
517 
518         if (Validator.isNull(value)) {
519             _headers.remove(name);
520         }
521         else {
522             _headers.put(name, new String[] {value});
523         }
524     }
525 
526     public void setIntHeader(String name, int value) {
527         if (Validator.isNull(name)) {
528             throw new IllegalArgumentException();
529         }
530 
531         if (value <= 0) {
532             _headers.remove(name);
533         }
534         else {
535             _headers.put(name, new Integer[] {new Integer(value)});
536         }
537     }
538 
539     public void setPlid(long plid) {
540         _plid = plid;
541 
542         if (_plid <= 0) {
543             Layout layout = (Layout)_portletRequestImpl.getAttribute(
544                 WebKeys.LAYOUT);
545 
546             if (layout != null) {
547                 _plid = layout.getPlid();
548             }
549         }
550     }
551 
552     public void setProperty(String key, String value) {
553         if (key == null) {
554             throw new IllegalArgumentException();
555         }
556 
557         setHeader(key, value);
558     }
559 
560     public void setURLEncoder(URLEncoder urlEncoder) {
561         _urlEncoder = urlEncoder;
562     }
563 
564     public void transferHeaders(HttpServletResponse response) {
565         for (Map.Entry<String, Object> entry : _headers.entrySet()) {
566             String name = entry.getKey();
567             Object values = entry.getValue();
568 
569             if (values instanceof Integer[]) {
570                 Integer[] intValues = (Integer[])values;
571 
572                 for (int value : intValues) {
573                     if (response.containsHeader(name)) {
574                         response.addIntHeader(name, value);
575                     }
576                     else {
577                         response.setIntHeader(name, value);
578                     }
579                 }
580             }
581             else if (values instanceof Long[]) {
582                 Long[] dateValues = (Long[])values;
583 
584                 for (long value : dateValues) {
585                     if (response.containsHeader(name)) {
586                         response.addDateHeader(name, value);
587                     }
588                     else {
589                         response.setDateHeader(name, value);
590                     }
591                 }
592             }
593             else if (values instanceof String[]) {
594                 String[] stringValues = (String[])values;
595 
596                 for (String value : stringValues) {
597                     if (response.containsHeader(name)) {
598                         response.addHeader(name, value);
599                     }
600                     else {
601                         response.setHeader(name, value);
602                     }
603                 }
604             }
605             else if (values instanceof Cookie[]) {
606                 Cookie[] cookies = (Cookie[])values;
607 
608                 for (Cookie cookie : cookies) {
609                     response.addCookie(cookie);
610                 }
611             }
612         }
613     }
614 
615     public void transferMarkupHeadElements() {
616         List<Element> elements = _markupHeadElements.get(
617             MimeResponse.MARKUP_HEAD_ELEMENT);
618 
619         if ((elements == null) || elements.isEmpty()) {
620             return;
621         }
622 
623         HttpServletRequest request = getHttpServletRequest();
624 
625         List<String> markupHeadElements = (List<String>)request.getAttribute(
626             MimeResponse.MARKUP_HEAD_ELEMENT);
627 
628         if (markupHeadElements == null) {
629             markupHeadElements = new ArrayList<String>();
630 
631             request.setAttribute(
632                 MimeResponse.MARKUP_HEAD_ELEMENT, markupHeadElements);
633         }
634 
635         for (Element element : elements) {
636             try {
637                 Writer writer = new UnsyncStringWriter();
638 
639                 TransformerFactory transformerFactory =
640                     TransformerFactory.newInstance();
641 
642                 Transformer transformer = transformerFactory.newTransformer();
643 
644                 transformer.setOutputProperty(
645                     OutputKeys.OMIT_XML_DECLARATION, "yes");
646 
647                 transformer.transform(
648                     new DOMSource(element), new StreamResult(writer));
649 
650                 markupHeadElements.add(writer.toString());
651             }
652             catch (Exception e) {
653                 if (_log.isWarnEnabled()) {
654                     _log.warn(e, e);
655                 }
656             }
657         }
658     }
659 
660     protected void init(
661         PortletRequestImpl portletRequestImpl, HttpServletResponse response,
662         String portletName, long companyId, long plid) {
663 
664         _portletRequestImpl = portletRequestImpl;
665         _response = response;
666         _portletName = portletName;
667         _companyId = companyId;
668         _wsrp = ParamUtil.getBoolean(getHttpServletRequest(), "wsrp");
669 
670         setPlid(plid);
671     }
672 
673     private static Log _log = LogFactoryUtil.getLog(PortletResponseImpl.class);
674 
675     private long _companyId;
676     private Document _document;
677     private Map<String, Object> _headers = new LinkedHashMap<String, Object>();
678     private Map<String, List<Element>> _markupHeadElements =
679         new LinkedHashMap<String, List<Element>>();
680     private String _namespace;
681     private long _plid;
682     private Portlet _portlet;
683     private String _portletName;
684     private PortletRequestImpl _portletRequestImpl;
685     private HttpServletResponse _response;
686     private URLEncoder _urlEncoder;
687     private boolean _wsrp;
688 
689 }