001    /**
002     * Copyright (c) 2000-2012 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    
043    import java.util.ArrayList;
044    import java.util.LinkedHashMap;
045    import java.util.List;
046    import java.util.Map;
047    import java.util.Set;
048    import java.util.concurrent.ConcurrentHashMap;
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    import javax.portlet.filter.PortletResponseWrapper;
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                    while (!(portletResponse instanceof PortletResponseImpl)) {
088                            if (portletResponse instanceof PortletResponseWrapper) {
089                                    PortletResponseWrapper portletResponseWrapper =
090                                            (PortletResponseWrapper)portletResponse;
091    
092                                    portletResponse = portletResponseWrapper.getResponse();
093                            }
094                            else {
095                                    throw new RuntimeException(
096                                            "Unable to unwrap the portlet response from " +
097                                                    portletResponse.getClass());
098                            }
099                    }
100    
101                    return (PortletResponseImpl)portletResponse;
102            }
103    
104            public void addDateHeader(String name, long date) {
105                    if (Validator.isNull(name)) {
106                            throw new IllegalArgumentException();
107                    }
108    
109                    Long[] values = (Long[])_headers.get(name);
110    
111                    if (values == null) {
112                            setDateHeader(name, date);
113                    }
114                    else {
115                            values = ArrayUtil.append(values, new Long(date));
116    
117                            _headers.put(name, values);
118                    }
119            }
120    
121            public void addHeader(String name, String value) {
122                    if (Validator.isNull(name)) {
123                            throw new IllegalArgumentException();
124                    }
125    
126                    String[] values = (String[])_headers.get(name);
127    
128                    if (values == null) {
129                            setHeader(name, value);
130                    }
131                    else {
132                            values = ArrayUtil.append(values, value);
133    
134                            _headers.put(name, values);
135                    }
136            }
137    
138            public void addIntHeader(String name, int value) {
139                    if (Validator.isNull(name)) {
140                            throw new IllegalArgumentException();
141                    }
142    
143                    Integer[] values = (Integer[])_headers.get(name);
144    
145                    if (values == null) {
146                            setIntHeader(name, value);
147                    }
148                    else {
149                            values = ArrayUtil.append(values, new Integer(value));
150    
151                            _headers.put(name, values);
152                    }
153            }
154    
155            public void addProperty(Cookie cookie) {
156                    if (cookie == null) {
157                            throw new IllegalArgumentException();
158                    }
159    
160                    Cookie[] cookies = (Cookie[])_headers.get("cookies");
161    
162                    if (cookies == null) {
163                            _headers.put("cookies", new Cookie[] {cookie});
164                    }
165                    else {
166                            cookies = ArrayUtil.append(cookies, cookie);
167    
168                            _headers.put("cookies", cookies);
169                    }
170            }
171    
172            public void addProperty(String key, Element element) {
173                    if (key == null) {
174                            throw new IllegalArgumentException();
175                    }
176    
177                    if (key.equalsIgnoreCase(MimeResponse.MARKUP_HEAD_ELEMENT)) {
178                            List<Element> values = _markupHeadElements.get(key);
179    
180                            if (values != null) {
181                                    if (element != null) {
182                                            values.add(element);
183                                    }
184                                    else {
185                                            _markupHeadElements.remove(key);
186                                    }
187                            }
188                            else {
189                                    if (element != null) {
190                                            values = new ArrayList<Element>();
191    
192                                            values.add(element);
193    
194                                            _markupHeadElements.put(key, values);
195                                    }
196                            }
197                    }
198            }
199    
200            public void addProperty(String key, String value) {
201                    if (Validator.isNull(key)) {
202                            throw new IllegalArgumentException();
203                    }
204    
205                    addHeader(key, value);
206            }
207    
208            public PortletURL createActionURL() {
209                    return createActionURL(_portletName);
210            }
211    
212            public LiferayPortletURL createActionURL(String portletName) {
213                    return createLiferayPortletURL(
214                            portletName, PortletRequest.ACTION_PHASE);
215            }
216    
217            public Element createElement(String tagName) throws DOMException {
218                    if (_document == null) {
219                            try {
220                                    DocumentBuilderFactory documentBuilderFactory =
221                                            DocumentBuilderFactory.newInstance();
222    
223                                    DocumentBuilder documentBuilder =
224                                            documentBuilderFactory.newDocumentBuilder();
225    
226                                    _document = documentBuilder.newDocument();
227                            }
228                            catch (ParserConfigurationException pce) {
229                                    throw new DOMException(
230                                            DOMException.INVALID_STATE_ERR, pce.getMessage());
231                            }
232                    }
233    
234                    return _document.createElement(tagName);
235            }
236    
237            public LiferayPortletURL createLiferayPortletURL(
238                    long plid, String portletName, String lifecycle) {
239    
240                    try {
241                            Layout layout = (Layout)_portletRequestImpl.getAttribute(
242                                    WebKeys.LAYOUT);
243    
244                            if (_portletSetup == null) {
245                                    _portletSetup =
246                                            PortletPreferencesFactoryUtil.getStrictLayoutPortletSetup(
247                                                    layout, _portletName);
248                            }
249    
250                            String linkToLayoutUuid = GetterUtil.getString(
251                                    _portletSetup.getValue("portletSetupLinkToLayoutUuid", null));
252    
253                            if (Validator.isNotNull(linkToLayoutUuid)) {
254                                    try {
255                                            Layout linkedLayout =
256                                                    LayoutLocalServiceUtil.getLayoutByUuidAndGroupId(
257                                                            linkToLayoutUuid, layout.getGroupId());
258    
259                                            plid = linkedLayout.getPlid();
260                                    }
261                                    catch (PortalException pe) {
262                                    }
263                            }
264                    }
265                    catch (SystemException se) {
266                            if (_log.isWarnEnabled()) {
267                                    _log.warn(se);
268                            }
269                    }
270    
271                    if (plid == LayoutConstants.DEFAULT_PLID) {
272                            plid = _plid;
273                    }
274    
275                    PortletURLImpl portletURLImpl = null;
276    
277                    Portlet portlet = getPortlet();
278    
279                    String portletURLClass = portlet.getPortletURLClass();
280    
281                    if (portlet.getPortletId().equals(portletName) &&
282                            Validator.isNotNull(portletURLClass)) {
283    
284                            try {
285                                    Constructor<? extends PortletURLImpl> constructor =
286                                            _constructors.get(portletURLClass);
287    
288                                    if (constructor == null) {
289                                            Class<?> portletURLClassObj = Class.forName(
290                                                    portletURLClass);
291    
292                                            constructor = (Constructor<? extends PortletURLImpl>)
293                                                    portletURLClassObj.getConstructor(
294                                                            new Class[] {
295                                                                    com.liferay.portlet.PortletResponseImpl.class,
296                                                                    long.class, String.class
297                                                            });
298    
299                                            _constructors.put(portletURLClass, constructor);
300                                    }
301    
302                                    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.RESOURCE_PHASE)) {
358                            portletURLImpl.setCopyCurrentRenderParameters(true);
359                    }
360    
361                    return portletURLImpl;
362            }
363    
364            public LiferayPortletURL createLiferayPortletURL(String lifecycle) {
365                    return createLiferayPortletURL(_portletName, lifecycle);
366            }
367    
368            public LiferayPortletURL createLiferayPortletURL(
369                    String portletName, String lifecycle) {
370    
371                    return createLiferayPortletURL(_plid, portletName, lifecycle);
372            }
373    
374            public PortletURL createRenderURL() {
375                    return createRenderURL(_portletName);
376            }
377    
378            public LiferayPortletURL createRenderURL(String portletName) {
379                    return createLiferayPortletURL(
380                            portletName, PortletRequest.RENDER_PHASE);
381            }
382    
383            public ResourceURL createResourceURL() {
384                    return createResourceURL(_portletName);
385            }
386    
387            public LiferayPortletURL createResourceURL(String portletName) {
388                    return createLiferayPortletURL(
389                            portletName, PortletRequest.RESOURCE_PHASE);
390            }
391    
392            public String encodeURL(String path) {
393                    if ((path == null) ||
394                            (!path.startsWith("#") && !path.startsWith("/") &&
395                                    (path.indexOf("://") == -1))) {
396    
397                            // Allow '#' as well to workaround a bug in Oracle ADF 10.1.3
398    
399                            throw new IllegalArgumentException(
400                                    "URL path must start with a '/' or include '://'");
401                    }
402    
403                    if (_urlEncoder != null) {
404                            return _urlEncoder.encodeURL(_response, path);
405                    }
406                    else {
407                            return path;
408                    }
409            }
410    
411            public long getCompanyId() {
412                    return _companyId;
413            }
414    
415            public HttpServletRequest getHttpServletRequest() {
416                    return _portletRequestImpl.getHttpServletRequest();
417            }
418    
419            public HttpServletResponse getHttpServletResponse() {
420                    return _response;
421            }
422    
423            public abstract String getLifecycle();
424    
425            public String getNamespace() {
426                    if (_wsrp) {
427                            return "wsrp_rewrite_";
428                    }
429    
430                    if (_namespace == null) {
431                            _namespace = PortalUtil.getPortletNamespace(_portletName);
432                    }
433    
434                    return _namespace;
435            }
436    
437            public long getPlid() {
438                    return _plid;
439            }
440    
441            public Portlet getPortlet() {
442                    if (_portlet == null) {
443                            try {
444                                    _portlet = PortletLocalServiceUtil.getPortletById(
445                                            _companyId, _portletName);
446                            }
447                            catch (Exception e) {
448                                    _log.error(e);
449                            }
450                    }
451    
452                    return _portlet;
453            }
454    
455            public String getPortletName() {
456                    return _portletName;
457            }
458    
459            public PortletRequestImpl getPortletRequest() {
460                    return _portletRequestImpl;
461            }
462    
463            public Map<String, String[]> getProperties() {
464                    Map<String, String[]> properties =
465                            new LinkedHashMap<String, String[]>();
466    
467                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
468                            String name = entry.getKey();
469                            Object[] values = (Object[])entry.getValue();
470    
471                            String[] valuesString = new String[values.length];
472    
473                            for (int i = 0; i < values.length; i++) {
474                                    valuesString[i] = values[i].toString();
475                            }
476    
477                            properties.put(name, valuesString);
478                    }
479    
480                    return properties;
481            }
482    
483            public URLEncoder getUrlEncoder() {
484                    return _urlEncoder;
485            }
486    
487            public void setDateHeader(String name, long date) {
488                    if (Validator.isNull(name)) {
489                            throw new IllegalArgumentException();
490                    }
491    
492                    if (date <= 0) {
493                            _headers.remove(name);
494                    }
495                    else {
496                            _headers.put(name, new Long[] {new Long(date)});
497                    }
498            }
499    
500            public void setHeader(String name, String value) {
501                    if (Validator.isNull(name)) {
502                            throw new IllegalArgumentException();
503                    }
504    
505                    if (Validator.isNull(value)) {
506                            _headers.remove(name);
507                    }
508                    else {
509                            _headers.put(name, new String[] {value});
510                    }
511            }
512    
513            public void setIntHeader(String name, int value) {
514                    if (Validator.isNull(name)) {
515                            throw new IllegalArgumentException();
516                    }
517    
518                    if (value <= 0) {
519                            _headers.remove(name);
520                    }
521                    else {
522                            _headers.put(name, new Integer[] {new Integer(value)});
523                    }
524            }
525    
526            public void setPlid(long plid) {
527                    _plid = plid;
528    
529                    if (_plid <= 0) {
530                            Layout layout = (Layout)_portletRequestImpl.getAttribute(
531                                    WebKeys.LAYOUT);
532    
533                            if (layout != null) {
534                                    _plid = layout.getPlid();
535                            }
536                    }
537            }
538    
539            public void setProperty(String key, String value) {
540                    if (key == null) {
541                            throw new IllegalArgumentException();
542                    }
543    
544                    setHeader(key, value);
545            }
546    
547            public void setURLEncoder(URLEncoder urlEncoder) {
548                    _urlEncoder = urlEncoder;
549            }
550    
551            public void transferHeaders(HttpServletResponse response) {
552                    for (Map.Entry<String, Object> entry : _headers.entrySet()) {
553                            String name = entry.getKey();
554                            Object values = entry.getValue();
555    
556                            if (values instanceof Integer[]) {
557                                    Integer[] intValues = (Integer[])values;
558    
559                                    for (int value : intValues) {
560                                            if (response.containsHeader(name)) {
561                                                    response.addIntHeader(name, value);
562                                            }
563                                            else {
564                                                    response.setIntHeader(name, value);
565                                            }
566                                    }
567                            }
568                            else if (values instanceof Long[]) {
569                                    Long[] dateValues = (Long[])values;
570    
571                                    for (long value : dateValues) {
572                                            if (response.containsHeader(name)) {
573                                                    response.addDateHeader(name, value);
574                                            }
575                                            else {
576                                                    response.setDateHeader(name, value);
577                                            }
578                                    }
579                            }
580                            else if (values instanceof String[]) {
581                                    String[] stringValues = (String[])values;
582    
583                                    for (String value : stringValues) {
584                                            if (response.containsHeader(name)) {
585                                                    response.addHeader(name, value);
586                                            }
587                                            else {
588                                                    response.setHeader(name, value);
589                                            }
590                                    }
591                            }
592                            else if (values instanceof Cookie[]) {
593                                    Cookie[] cookies = (Cookie[])values;
594    
595                                    for (Cookie cookie : cookies) {
596                                            response.addCookie(cookie);
597                                    }
598                            }
599                    }
600            }
601    
602            public void transferMarkupHeadElements() {
603                    List<Element> elements = _markupHeadElements.get(
604                            MimeResponse.MARKUP_HEAD_ELEMENT);
605    
606                    if ((elements == null) || elements.isEmpty()) {
607                            return;
608                    }
609    
610                    HttpServletRequest request = getHttpServletRequest();
611    
612                    List<String> markupHeadElements = (List<String>)request.getAttribute(
613                            MimeResponse.MARKUP_HEAD_ELEMENT);
614    
615                    if (markupHeadElements == null) {
616                            markupHeadElements = new ArrayList<String>();
617    
618                            request.setAttribute(
619                                    MimeResponse.MARKUP_HEAD_ELEMENT, markupHeadElements);
620                    }
621    
622                    for (Element element : elements) {
623                            try {
624                                    Writer writer = new UnsyncStringWriter();
625    
626                                    TransformerFactory transformerFactory =
627                                            TransformerFactory.newInstance();
628    
629                                    Transformer transformer = transformerFactory.newTransformer();
630    
631                                    transformer.setOutputProperty(
632                                            OutputKeys.OMIT_XML_DECLARATION, "yes");
633    
634                                    transformer.transform(
635                                            new DOMSource(element), new StreamResult(writer));
636    
637                                    markupHeadElements.add(writer.toString());
638                            }
639                            catch (Exception e) {
640                                    if (_log.isWarnEnabled()) {
641                                            _log.warn(e, e);
642                                    }
643                            }
644                    }
645            }
646    
647            protected void init(
648                    PortletRequestImpl portletRequestImpl, HttpServletResponse response,
649                    String portletName, long companyId, long plid) {
650    
651                    _portletRequestImpl = portletRequestImpl;
652                    _response = response;
653                    _portletName = portletName;
654                    _companyId = companyId;
655                    _wsrp = ParamUtil.getBoolean(getHttpServletRequest(), "wsrp");
656    
657                    setPlid(plid);
658            }
659    
660            private static Log _log = LogFactoryUtil.getLog(PortletResponseImpl.class);
661    
662            private long _companyId;
663            private Map<String, Constructor<? extends PortletURLImpl>> _constructors =
664                    new ConcurrentHashMap<String, Constructor<? extends PortletURLImpl>>();
665            private Document _document;
666            private Map<String, Object> _headers = new LinkedHashMap<String, Object>();
667            private Map<String, List<Element>> _markupHeadElements =
668                    new LinkedHashMap<String, List<Element>>();
669            private String _namespace;
670            private long _plid;
671            private Portlet _portlet;
672            private String _portletName;
673            private PortletRequestImpl _portletRequestImpl;
674            private PortletPreferences _portletSetup;
675            private HttpServletResponse _response;
676            private URLEncoder _urlEncoder;
677            private boolean _wsrp;
678    
679    }