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