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