001    /**
002     * Copyright (c) 2000-2010 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.portlet;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
023    import com.liferay.portal.kernel.portlet.LiferayPortletURL;
024    import com.liferay.portal.kernel.servlet.URLEncoder;
025    import com.liferay.portal.kernel.util.ArrayUtil;
026    import com.liferay.portal.kernel.util.GetterUtil;
027    import com.liferay.portal.kernel.util.ParamUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.model.Layout;
030    import com.liferay.portal.model.LayoutConstants;
031    import com.liferay.portal.model.Portlet;
032    import com.liferay.portal.model.PortletApp;
033    import com.liferay.portal.model.PortletURLListener;
034    import com.liferay.portal.service.LayoutLocalServiceUtil;
035    import com.liferay.portal.service.PortletLocalServiceUtil;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.WebKeys;
038    
039    import java.io.Writer;
040    
041    import java.lang.reflect.Constructor;
042    import java.lang.reflect.Method;
043    
044    import java.util.ArrayList;
045    import java.util.LinkedHashMap;
046    import java.util.List;
047    import java.util.Map;
048    import java.util.Set;
049    
050    import javax.portlet.MimeResponse;
051    import javax.portlet.PortletException;
052    import javax.portlet.PortletModeException;
053    import javax.portlet.PortletPreferences;
054    import javax.portlet.PortletRequest;
055    import javax.portlet.PortletResponse;
056    import javax.portlet.PortletURL;
057    import javax.portlet.PortletURLGenerationListener;
058    import javax.portlet.ResourceURL;
059    import javax.portlet.WindowStateException;
060    
061    import javax.servlet.http.Cookie;
062    import javax.servlet.http.HttpServletRequest;
063    import javax.servlet.http.HttpServletResponse;
064    
065    import javax.xml.parsers.DocumentBuilder;
066    import javax.xml.parsers.DocumentBuilderFactory;
067    import javax.xml.parsers.ParserConfigurationException;
068    import javax.xml.transform.OutputKeys;
069    import javax.xml.transform.Transformer;
070    import javax.xml.transform.TransformerFactory;
071    import javax.xml.transform.dom.DOMSource;
072    import javax.xml.transform.stream.StreamResult;
073    
074    import org.w3c.dom.DOMException;
075    import org.w3c.dom.Document;
076    import org.w3c.dom.Element;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     */
081    public abstract class PortletResponseImpl implements LiferayPortletResponse {
082    
083            public static PortletResponseImpl getPortletResponseImpl(
084                    PortletResponse portletResponse) {
085    
086                    PortletResponseImpl portletResponseImpl = null;
087    
088                    if (portletResponse instanceof PortletResponseImpl) {
089                            portletResponseImpl = (PortletResponseImpl)portletResponse;
090                    }
091                    else {
092    
093                            // LEP-4033
094    
095                            try {
096                                    Method method = portletResponse.getClass().getMethod(
097                                            "getResponse");
098    
099                                    Object obj = method.invoke(portletResponse, (Object[])null);
100    
101                                    portletResponseImpl = getPortletResponseImpl(
102                                            (PortletResponse)obj);
103                            }
104                            catch (Exception e) {
105                                    throw new RuntimeException(
106                                            "Unable to get the portlet response from " +
107                                                    portletResponse.getClass().getName());
108                            }
109                    }
110    
111                    return portletResponseImpl;
112            }
113    
114            public void addDateHeader(String name, long date) {
115                    if (Validator.isNull(name)) {
116                            throw new IllegalArgumentException();
117                    }
118    
119                    if (_headers.containsKey(name)) {
120                            Long[] values = (Long[])_headers.get(name);
121    
122                            values = ArrayUtil.append(values, new Long(date));
123    
124                            _headers.put(name, values);
125                    }
126                    else {
127                            setDateHeader(name, date);
128                    }
129            }
130    
131            public void addHeader(String name, String value) {
132                    if (Validator.isNull(name)) {
133                            throw new IllegalArgumentException();
134                    }
135    
136                    if (_headers.containsKey(name)) {
137                            String[] values = (String[])_headers.get(name);
138    
139                            values = ArrayUtil.append(values, value);
140    
141                            _headers.put(name, values);
142                    }
143                    else {
144                            setHeader(name, value);
145                    }
146            }
147    
148            public void addIntHeader(String name, int value) {
149                    if (Validator.isNull(name)) {
150                            throw new IllegalArgumentException();
151                    }
152    
153                    if (_headers.containsKey(name)) {
154                            Integer[] values = (Integer[])_headers.get(name);
155    
156                            values = ArrayUtil.append(values, new Integer(value));
157    
158                            _headers.put(name, values);
159                    }
160                    else {
161                            setIntHeader(name, value);
162                    }
163            }
164    
165            public void addProperty(Cookie cookie) {
166                    if (cookie == null) {
167                            throw new IllegalArgumentException();
168                    }
169    
170                    if (_headers.containsKey("cookies")) {
171                            Cookie[] cookies = (Cookie[])_headers.get("cookies");
172    
173                            cookies = ArrayUtil.append(cookies, cookie);
174    
175                            _headers.put("cookies", cookies);
176                    }
177                    else {
178                            Cookie[] cookies = new Cookie[] {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                            String linkToLayoutUuid = GetterUtil.getString(
261                                    portletSetup.getValue(
262                                            "portlet-setup-link-to-layout-uuid", null));
263    
264                            if (Validator.isNotNull(linkToLayoutUuid)) {
265                                    try {
266                                            Layout linkedLayout =
267                                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
268                                                            linkToLayoutUuid, layout.getGroupId());
269    
270                                            plid = linkedLayout.getPlid();
271                                    }
272                                    catch (PortalException pe) {
273                                    }
274                            }
275                    }
276                    catch (SystemException e) {
277                            if (_log.isWarnEnabled()) {
278                                    _log.warn(e);
279                            }
280                    }
281    
282                    if (plid == LayoutConstants.DEFAULT_PLID) {
283                            plid = _plid;
284                    }
285    
286                    PortletURLImpl portletURLImpl = null;
287    
288                    Portlet portlet = getPortlet();
289    
290                    String portletURLClass = portlet.getPortletURLClass();
291    
292                    if (portlet.getPortletId().equals(portletName) &&
293                            Validator.isNotNull(portletURLClass)) {
294    
295                            try {
296                                    Class<?> portletURLClassObj = Class.forName(portletURLClass);
297    
298                                    Constructor<?> constructor = portletURLClassObj.getConstructor(
299                                            new Class[] {
300                                                    com.liferay.portlet.PortletResponseImpl.class,
301                                                    long.class, String.class
302                                            });
303    
304                                    portletURLImpl = (PortletURLImpl)constructor.newInstance(
305                                            new Object[] {this, plid, lifecycle});
306                            }
307                            catch (Exception e) {
308                                    _log.error(e);
309                            }
310                    }
311    
312                    if (portletURLImpl == null) {
313                            portletURLImpl = new PortletURLImpl(
314                                    _portletRequestImpl, portletName, plid, lifecycle);
315                    }
316    
317                    PortletApp portletApp = portlet.getPortletApp();
318    
319                    Set<PortletURLListener> portletURLListeners =
320                            portletApp.getPortletURLListeners();
321    
322                    for (PortletURLListener portletURLListener : portletURLListeners) {
323                            try {
324                                    PortletURLGenerationListener portletURLGenerationListener =
325                                            PortletURLListenerFactory.create(portletURLListener);
326    
327                                    if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
328                                            portletURLGenerationListener.filterActionURL(
329                                                    portletURLImpl);
330                                    }
331                                    else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
332                                            portletURLGenerationListener.filterRenderURL(
333                                                    portletURLImpl);
334                                    }
335                                    else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
336                                            portletURLGenerationListener.filterResourceURL(
337                                                    portletURLImpl);
338                                    }
339                            }
340                            catch (PortletException pe) {
341                                    _log.error(pe, pe);
342                            }
343                    }
344    
345                    try {
346                            portletURLImpl.setWindowState(_portletRequestImpl.getWindowState());
347                    }
348                    catch (WindowStateException wse) {
349                            _log.error(wse.getMessage());
350                    }
351    
352                    try {
353                            portletURLImpl.setPortletMode(_portletRequestImpl.getPortletMode());
354                    }
355                    catch (PortletModeException pme) {
356                            _log.error(pme.getMessage());
357                    }
358    
359                    if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
360                            portletURLImpl.setCopyCurrentPublicRenderParameters(true);
361                    }
362    
363                    if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
364                            portletURLImpl.setCopyCurrentPublicRenderParameters(true);
365                            portletURLImpl.setCopyCurrentRenderParameters(true);
366                    }
367    
368                    return portletURLImpl;
369            }
370    
371            public LiferayPortletURL createLiferayPortletURL(String lifecycle) {
372                    return createLiferayPortletURL(_portletName, lifecycle);
373            }
374    
375            public LiferayPortletURL createLiferayPortletURL(
376                    String portletName, String lifecycle) {
377    
378                    return createLiferayPortletURL(_plid, portletName, lifecycle);
379            }
380    
381            public PortletURL createRenderURL() {
382                    return createRenderURL(_portletName);
383            }
384    
385            public LiferayPortletURL createRenderURL(String portletName) {
386                    return createLiferayPortletURL(
387                            portletName, PortletRequest.RENDER_PHASE);
388            }
389    
390            public ResourceURL createResourceURL() {
391                    return createResourceURL(_portletName);
392            }
393    
394            public LiferayPortletURL createResourceURL(String portletName) {
395                    return createLiferayPortletURL(
396                            portletName, PortletRequest.RESOURCE_PHASE);
397            }
398    
399            public String encodeURL(String path) {
400                    if ((path == null) ||
401                            (!path.startsWith("#") && !path.startsWith("/") &&
402                                    (path.indexOf("://") == -1))) {
403    
404                            // Allow '#' as well to workaround a bug in Oracle ADF 10.1.3
405    
406                            throw new IllegalArgumentException(
407                                    "URL path must start with a '/' or include '://'");
408                    }
409    
410                    if (_urlEncoder != null) {
411                            return _urlEncoder.encodeURL(_response, path);
412                    }
413                    else {
414                            return path;
415                    }
416            }
417    
418            public long getCompanyId() {
419                    return _companyId;
420            }
421    
422            public HttpServletRequest getHttpServletRequest() {
423                    return _portletRequestImpl.getHttpServletRequest();
424            }
425    
426            public HttpServletResponse getHttpServletResponse() {
427                    return _response;
428            }
429    
430            public abstract String getLifecycle();
431    
432            public String getNamespace() {
433                    if (_wsrp) {
434                            return "wsrp_rewrite_";
435                    }
436    
437                    if (_namespace == null) {
438                            _namespace = PortalUtil.getPortletNamespace(_portletName);
439                    }
440    
441                    return _namespace;
442            }
443    
444            public long getPlid() {
445                    return _plid;
446            }
447    
448            public Portlet getPortlet() {
449                    if (_portlet == null) {
450                            try {
451                                    _portlet = PortletLocalServiceUtil.getPortletById(
452                                            _companyId, _portletName);
453                            }
454                            catch (Exception e) {
455                                    _log.error(e);
456                            }
457                    }
458    
459                    return _portlet;
460            }
461    
462            public String getPortletName() {
463                    return _portletName;
464            }
465    
466            public PortletRequestImpl getPortletRequest() {
467                    return _portletRequestImpl;
468            }
469    
470            public Map<String, String[]> getProperties() {
471                    Map<String, String[]> properties =
472                            new LinkedHashMap<String, String[]>();
473    
474                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
475                            String name = entry.getKey();
476                            Object[] values = (Object[])entry.getValue();
477    
478                            String[] valuesString = new String[values.length];
479    
480                            for (int i = 0; i < values.length; i++) {
481                                    valuesString[i] = values[i].toString();
482                            }
483    
484                            properties.put(name, valuesString);
485                    }
486    
487                    return properties;
488            }
489    
490            public URLEncoder getUrlEncoder() {
491                    return _urlEncoder;
492            }
493    
494            public void setDateHeader(String name, long date) {
495                    if (Validator.isNull(name)) {
496                            throw new IllegalArgumentException();
497                    }
498    
499                    if (date <= 0) {
500                            _headers.remove(name);
501                    }
502                    else {
503                            _headers.put(name, new Long[] {new Long(date)});
504                    }
505            }
506    
507            public void setHeader(String name, String value) {
508                    if (Validator.isNull(name)) {
509                            throw new IllegalArgumentException();
510                    }
511    
512                    if (Validator.isNull(value)) {
513                            _headers.remove(name);
514                    }
515                    else {
516                            _headers.put(name, new String[] {value});
517                    }
518            }
519    
520            public void setIntHeader(String name, int value) {
521                    if (Validator.isNull(name)) {
522                            throw new IllegalArgumentException();
523                    }
524    
525                    if (value <= 0) {
526                            _headers.remove(name);
527                    }
528                    else {
529                            _headers.put(name, new Integer[] {new Integer(value)});
530                    }
531            }
532    
533            public void setPlid(long plid) {
534                    _plid = plid;
535    
536                    if (_plid <= 0) {
537                            Layout layout = (Layout)_portletRequestImpl.getAttribute(
538                                    WebKeys.LAYOUT);
539    
540                            if (layout != null) {
541                                    _plid = layout.getPlid();
542                            }
543                    }
544            }
545    
546            public void setProperty(String key, String value) {
547                    if (key == null) {
548                            throw new IllegalArgumentException();
549                    }
550    
551                    setHeader(key, value);
552            }
553    
554            public void setURLEncoder(URLEncoder urlEncoder) {
555                    _urlEncoder = urlEncoder;
556            }
557    
558            public void transferHeaders(HttpServletResponse response) {
559                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
560                            String name = entry.getKey();
561                            Object values = entry.getValue();
562    
563                            if (values instanceof Integer[]) {
564                                    Integer[] intValues = (Integer[])values;
565    
566                                    for (int value : intValues) {
567                                            if (response.containsHeader(name)) {
568                                                    response.addIntHeader(name, value);
569                                            }
570                                            else {
571                                                    response.setIntHeader(name, value);
572                                            }
573                                    }
574                            }
575                            else if (values instanceof Long[]) {
576                                    Long[] dateValues = (Long[])values;
577    
578                                    for (long value : dateValues) {
579                                            if (response.containsHeader(name)) {
580                                                    response.addDateHeader(name, value);
581                                            }
582                                            else {
583                                                    response.setDateHeader(name, value);
584                                            }
585                                    }
586                            }
587                            else if (values instanceof String[]) {
588                                    String[] stringValues = (String[])values;
589    
590                                    for (String value : stringValues) {
591                                            if (response.containsHeader(name)) {
592                                                    response.addHeader(name, value);
593                                            }
594                                            else {
595                                                    response.setHeader(name, value);
596                                            }
597                                    }
598                            }
599                            else if (values instanceof Cookie[]) {
600                                    Cookie[] cookies = (Cookie[])values;
601    
602                                    for (Cookie cookie : cookies) {
603                                            response.addCookie(cookie);
604                                    }
605                            }
606                    }
607            }
608    
609            public void transferMarkupHeadElements() {
610                    List<Element> elements = _markupHeadElements.get(
611                            MimeResponse.MARKUP_HEAD_ELEMENT);
612    
613                    if ((elements == null) || elements.isEmpty()) {
614                            return;
615                    }
616    
617                    HttpServletRequest request = getHttpServletRequest();
618    
619                    List<String> markupHeadElements = (List<String>)request.getAttribute(
620                            MimeResponse.MARKUP_HEAD_ELEMENT);
621    
622                    if (markupHeadElements == null) {
623                            markupHeadElements = new ArrayList<String>();
624                    }
625    
626                    for (Element element : elements) {
627                            try {
628                                    Writer writer = new UnsyncStringWriter();
629    
630                                    TransformerFactory transformerFactory =
631                                            TransformerFactory.newInstance();
632    
633                                    Transformer transformer = transformerFactory.newTransformer();
634    
635                                    transformer.setOutputProperty(
636                                            OutputKeys.OMIT_XML_DECLARATION, "yes");
637    
638                                    transformer.transform(
639                                            new DOMSource(element), new StreamResult(writer));
640    
641                                    markupHeadElements.add(writer.toString());
642                            }
643                            catch (Exception e) {
644                                    if (_log.isWarnEnabled()) {
645                                            _log.warn(e, e);
646                                    }
647                            }
648                    }
649    
650                    request.setAttribute(
651                            MimeResponse.MARKUP_HEAD_ELEMENT, markupHeadElements);
652            }
653    
654            protected void init(
655                    PortletRequestImpl portletRequestImpl, HttpServletResponse response,
656                    String portletName, long companyId, long plid) {
657    
658                    _portletRequestImpl = portletRequestImpl;
659                    _response = response;
660                    _portletName = portletName;
661                    _companyId = companyId;
662                    _wsrp = ParamUtil.getBoolean(getHttpServletRequest(), "wsrp");
663    
664                    setPlid(plid);
665            }
666    
667            private static Log _log = LogFactoryUtil.getLog(PortletResponseImpl.class);
668    
669            private long _companyId;
670            private Document _document;
671            private Map<String, Object> _headers = new LinkedHashMap<String, Object>();
672            private Map<String, List<Element>> _markupHeadElements =
673                    new LinkedHashMap<String, List<Element>>();
674            private String _namespace;
675            private long _plid;
676            private Portlet _portlet;
677            private String _portletName;
678            private PortletRequestImpl _portletRequestImpl;
679            private HttpServletResponse _response;
680            private URLEncoder _urlEncoder;
681            private boolean _wsrp;
682    
683    }