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