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                                                            layout.isPrivateLayout());
279    
280                                            plid = linkedLayout.getPlid();
281                                    }
282                                    catch (PortalException pe) {
283                                    }
284                            }
285                    }
286                    catch (SystemException se) {
287                            if (_log.isWarnEnabled()) {
288                                    _log.warn(se);
289                            }
290                    }
291    
292                    if (plid == LayoutConstants.DEFAULT_PLID) {
293                            plid = _plid;
294                    }
295    
296                    PortletURLImpl portletURLImpl = null;
297    
298                    Portlet portlet = getPortlet();
299    
300                    String portletURLClass = portlet.getPortletURLClass();
301    
302                    if (portlet.getPortletId().equals(portletName) &&
303                            Validator.isNotNull(portletURLClass)) {
304    
305                            try {
306                                    Constructor<? extends PortletURLImpl> constructor =
307                                            _constructors.get(portletURLClass);
308    
309                                    if (constructor == null) {
310                                            Class<?> portletURLClassObj = Class.forName(
311                                                    portletURLClass);
312    
313                                            constructor = (Constructor<? extends PortletURLImpl>)
314                                                    portletURLClassObj.getConstructor(
315                                                            new Class[] {
316                                                                    com.liferay.portlet.PortletResponseImpl.class,
317                                                                    long.class, String.class
318                                                            });
319    
320                                            _constructors.put(portletURLClass, constructor);
321                                    }
322    
323                                    portletURLImpl = constructor.newInstance(
324                                            new Object[] {this, plid, lifecycle});
325                            }
326                            catch (Exception e) {
327                                    _log.error(e);
328                            }
329                    }
330    
331                    if (portletURLImpl == null) {
332                            portletURLImpl = new PortletURLImpl(
333                                    _portletRequestImpl, portletName, plid, lifecycle);
334                    }
335    
336                    PortletApp portletApp = portlet.getPortletApp();
337    
338                    Set<PortletURLListener> portletURLListeners =
339                            portletApp.getPortletURLListeners();
340    
341                    for (PortletURLListener portletURLListener : portletURLListeners) {
342                            try {
343                                    PortletURLGenerationListener portletURLGenerationListener =
344                                            PortletURLListenerFactory.create(portletURLListener);
345    
346                                    if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
347                                            portletURLGenerationListener.filterActionURL(
348                                                    portletURLImpl);
349                                    }
350                                    else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
351                                            portletURLGenerationListener.filterRenderURL(
352                                                    portletURLImpl);
353                                    }
354                                    else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
355                                            portletURLGenerationListener.filterResourceURL(
356                                                    portletURLImpl);
357                                    }
358                            }
359                            catch (PortletException pe) {
360                                    _log.error(pe, pe);
361                            }
362                    }
363    
364                    try {
365                            portletURLImpl.setWindowState(_portletRequestImpl.getWindowState());
366                    }
367                    catch (WindowStateException wse) {
368                            _log.error(wse.getMessage());
369                    }
370    
371                    try {
372                            portletURLImpl.setPortletMode(_portletRequestImpl.getPortletMode());
373                    }
374                    catch (PortletModeException pme) {
375                            _log.error(pme.getMessage());
376                    }
377    
378                    if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
379                            portletURLImpl.setCopyCurrentRenderParameters(true);
380                    }
381    
382                    return portletURLImpl;
383            }
384    
385            public LiferayPortletURL createLiferayPortletURL(String lifecycle) {
386                    return createLiferayPortletURL(_portletName, lifecycle);
387            }
388    
389            public LiferayPortletURL createLiferayPortletURL(
390                    String portletName, String lifecycle) {
391    
392                    return createLiferayPortletURL(_plid, portletName, lifecycle);
393            }
394    
395            public PortletURL createRenderURL() {
396                    return createRenderURL(_portletName);
397            }
398    
399            public LiferayPortletURL createRenderURL(String portletName) {
400                    return createLiferayPortletURL(
401                            portletName, PortletRequest.RENDER_PHASE);
402            }
403    
404            public ResourceURL createResourceURL() {
405                    return createResourceURL(_portletName);
406            }
407    
408            public LiferayPortletURL createResourceURL(String portletName) {
409                    return createLiferayPortletURL(
410                            portletName, PortletRequest.RESOURCE_PHASE);
411            }
412    
413            public String encodeURL(String path) {
414                    if ((path == null) ||
415                            (!path.startsWith("#") && !path.startsWith("/") &&
416                             !path.contains("://"))) {
417    
418                            // Allow '#' as well to workaround a bug in Oracle ADF 10.1.3
419    
420                            throw new IllegalArgumentException(
421                                    "URL path must start with a '/' or include '://'");
422                    }
423    
424                    if (_urlEncoder != null) {
425                            return _urlEncoder.encodeURL(_response, path);
426                    }
427                    else {
428                            return path;
429                    }
430            }
431    
432            public long getCompanyId() {
433                    return _companyId;
434            }
435    
436            public HttpServletRequest getHttpServletRequest() {
437                    return _portletRequestImpl.getHttpServletRequest();
438            }
439    
440            public HttpServletResponse getHttpServletResponse() {
441                    return _response;
442            }
443    
444            public abstract String getLifecycle();
445    
446            public String getNamespace() {
447                    if (_wsrp) {
448                            return "wsrp_rewrite_";
449                    }
450    
451                    if (_namespace == null) {
452                            _namespace = PortalUtil.getPortletNamespace(_portletName);
453                    }
454    
455                    return _namespace;
456            }
457    
458            public long getPlid() {
459                    return _plid;
460            }
461    
462            public Portlet getPortlet() {
463                    if (_portlet == null) {
464                            try {
465                                    _portlet = PortletLocalServiceUtil.getPortletById(
466                                            _companyId, _portletName);
467                            }
468                            catch (Exception e) {
469                                    _log.error(e);
470                            }
471                    }
472    
473                    return _portlet;
474            }
475    
476            public String getPortletName() {
477                    return _portletName;
478            }
479    
480            public PortletRequestImpl getPortletRequest() {
481                    return _portletRequestImpl;
482            }
483    
484            public Map<String, String[]> getProperties() {
485                    Map<String, String[]> properties =
486                            new LinkedHashMap<String, String[]>();
487    
488                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
489                            String name = entry.getKey();
490                            Object[] values = (Object[])entry.getValue();
491    
492                            String[] valuesString = new String[values.length];
493    
494                            for (int i = 0; i < values.length; i++) {
495                                    valuesString[i] = values[i].toString();
496                            }
497    
498                            properties.put(name, valuesString);
499                    }
500    
501                    return properties;
502            }
503    
504            public URLEncoder getUrlEncoder() {
505                    return _urlEncoder;
506            }
507    
508            public void setDateHeader(String name, long date) {
509                    if (Validator.isNull(name)) {
510                            throw new IllegalArgumentException();
511                    }
512    
513                    if (date <= 0) {
514                            _headers.remove(name);
515                    }
516                    else {
517                            _headers.put(name, new Long[] {new Long(date)});
518                    }
519            }
520    
521            public void setHeader(String name, String value) {
522                    if (Validator.isNull(name)) {
523                            throw new IllegalArgumentException();
524                    }
525    
526                    if (Validator.isNull(value)) {
527                            _headers.remove(name);
528                    }
529                    else {
530                            _headers.put(name, new String[] {value});
531                    }
532            }
533    
534            public void setIntHeader(String name, int value) {
535                    if (Validator.isNull(name)) {
536                            throw new IllegalArgumentException();
537                    }
538    
539                    if (value <= 0) {
540                            _headers.remove(name);
541                    }
542                    else {
543                            _headers.put(name, new Integer[] {new Integer(value)});
544                    }
545            }
546    
547            public void setPlid(long plid) {
548                    _plid = plid;
549    
550                    if (_plid <= 0) {
551                            Layout layout = (Layout)_portletRequestImpl.getAttribute(
552                                    WebKeys.LAYOUT);
553    
554                            if (layout != null) {
555                                    _plid = layout.getPlid();
556                            }
557                    }
558            }
559    
560            public void setProperty(String key, String value) {
561                    if (key == null) {
562                            throw new IllegalArgumentException();
563                    }
564    
565                    setHeader(key, value);
566            }
567    
568            public void setURLEncoder(URLEncoder urlEncoder) {
569                    _urlEncoder = urlEncoder;
570            }
571    
572            public void transferHeaders(HttpServletResponse response) {
573                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
574                            String name = entry.getKey();
575                            Object values = entry.getValue();
576    
577                            if (values instanceof Integer[]) {
578                                    Integer[] intValues = (Integer[])values;
579    
580                                    for (int value : intValues) {
581                                            if (response.containsHeader(name)) {
582                                                    response.addIntHeader(name, value);
583                                            }
584                                            else {
585                                                    response.setIntHeader(name, value);
586                                            }
587                                    }
588                            }
589                            else if (values instanceof Long[]) {
590                                    Long[] dateValues = (Long[])values;
591    
592                                    for (long value : dateValues) {
593                                            if (response.containsHeader(name)) {
594                                                    response.addDateHeader(name, value);
595                                            }
596                                            else {
597                                                    response.setDateHeader(name, value);
598                                            }
599                                    }
600                            }
601                            else if (values instanceof String[]) {
602                                    String[] stringValues = (String[])values;
603    
604                                    for (String value : stringValues) {
605                                            if (response.containsHeader(name)) {
606                                                    response.addHeader(name, value);
607                                            }
608                                            else {
609                                                    response.setHeader(name, value);
610                                            }
611                                    }
612                            }
613                            else if (values instanceof Cookie[]) {
614                                    Cookie[] cookies = (Cookie[])values;
615    
616                                    for (Cookie cookie : cookies) {
617                                            response.addCookie(cookie);
618                                    }
619                            }
620                    }
621            }
622    
623            public void transferMarkupHeadElements() {
624                    List<Element> elements = _markupHeadElements.get(
625                            MimeResponse.MARKUP_HEAD_ELEMENT);
626    
627                    if ((elements == null) || elements.isEmpty()) {
628                            return;
629                    }
630    
631                    HttpServletRequest request = getHttpServletRequest();
632    
633                    List<String> markupHeadElements = (List<String>)request.getAttribute(
634                            MimeResponse.MARKUP_HEAD_ELEMENT);
635    
636                    if (markupHeadElements == null) {
637                            markupHeadElements = new ArrayList<String>();
638    
639                            request.setAttribute(
640                                    MimeResponse.MARKUP_HEAD_ELEMENT, markupHeadElements);
641                    }
642    
643                    for (Element element : elements) {
644                            try {
645                                    Writer writer = new UnsyncStringWriter();
646    
647                                    TransformerFactory transformerFactory =
648                                            TransformerFactory.newInstance();
649    
650                                    Transformer transformer = transformerFactory.newTransformer();
651    
652                                    transformer.setOutputProperty(
653                                            OutputKeys.OMIT_XML_DECLARATION, "yes");
654    
655                                    transformer.transform(
656                                            new DOMSource(element), new StreamResult(writer));
657    
658                                    markupHeadElements.add(writer.toString());
659                            }
660                            catch (Exception e) {
661                                    if (_log.isWarnEnabled()) {
662                                            _log.warn(e, e);
663                                    }
664                            }
665                    }
666            }
667    
668            protected void init(
669                    PortletRequestImpl portletRequestImpl, HttpServletResponse response,
670                    String portletName, long companyId, long plid) {
671    
672                    _portletRequestImpl = portletRequestImpl;
673                    _response = response;
674                    _portletName = portletName;
675                    _companyId = companyId;
676                    _wsrp = ParamUtil.getBoolean(getHttpServletRequest(), "wsrp");
677    
678                    setPlid(plid);
679            }
680    
681            private static Log _log = LogFactoryUtil.getLog(PortletResponseImpl.class);
682    
683            private long _companyId;
684            private Map<String, Constructor<? extends PortletURLImpl>> _constructors =
685                    new ConcurrentHashMap<String, Constructor<? extends PortletURLImpl>>();
686            private Document _document;
687            private Map<String, Object> _headers = new LinkedHashMap<String, Object>();
688            private Map<String, List<Element>> _markupHeadElements =
689                    new LinkedHashMap<String, List<Element>>();
690            private String _namespace;
691            private long _plid;
692            private Portlet _portlet;
693            private String _portletName;
694            private PortletRequestImpl _portletRequestImpl;
695            private PortletPreferences _portletSetup;
696            private HttpServletResponse _response;
697            private URLEncoder _urlEncoder;
698            private boolean _wsrp;
699    
700    }