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