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