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