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