001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.portlet;
016    
017    import javax.portlet.PortletURL;
018    
019    import org.apache.hivemind.util.Defense;
020    import org.apache.tapestry.IRequestCycle;
021    import org.apache.tapestry.engine.ILink;
022    import org.apache.tapestry.util.QueryParameterMap;
023    
024    /**
025     * Wrapper around {@link javax.portlet.PortletURL}.
026     * 
027     * @author Howard M. Lewis Ship
028     * @since 4.0
029     */
030    public class PortletLink implements ILink
031    {
032        private final IRequestCycle _cycle;
033    
034        private final PortletURL _portletURL;
035    
036        private final boolean _stateful;
037    
038        private final QueryParameterMap _parameters;
039    
040        public PortletLink(IRequestCycle cycle, PortletURL portletURL, QueryParameterMap parameters,
041                boolean stateful)
042        {
043            Defense.notNull(cycle, "cycle");
044            Defense.notNull(portletURL, "portletURL");
045            Defense.notNull(parameters, "parameters");
046    
047            _cycle = cycle;
048            _portletURL = portletURL;
049            _parameters = parameters;
050            _stateful = stateful;
051        }
052    
053        public String getURL()
054        {
055            return getURL(null, true);
056        }
057    
058        public String getURL(String anchor, boolean includeParameters)
059        {
060            if (includeParameters)
061                loadParameters();
062    
063            String url = _portletURL.toString();
064    
065            url = unencode(url);
066    
067            if (_stateful)
068                url = _cycle.encodeURL(url);
069    
070            if (anchor != null)
071                url = url + "#" + anchor;
072    
073            return url;
074        }
075    
076        /**
077         * The PortletURL class returns a url that's already XML-escaped, ready for inclusion directly
078         * into the response stream. However, the IMarkupWriter expects to do that encoding too ... and
079         * double encoding is bad. So we back out the most likely encoding (convert '&' to just
080         * '&').
081         */
082    
083        private String unencode(String url)
084        {
085            StringBuffer buffer = new StringBuffer(url.length());
086            String text = url;
087    
088            while (true)
089            {
090                int ampx = text.indexOf("&");
091    
092                if (ampx < 0)
093                    break;
094    
095                // Take up to and including the '&'
096    
097                buffer.append(text.substring(0, ampx + 1));
098    
099                text = text.substring(ampx + 5);
100            }
101    
102            buffer.append(text);
103    
104            return buffer.toString();
105        }
106    
107        private void loadParameters()
108        {
109            String[] names = _parameters.getParameterNames();
110    
111            for (int i = 0; i < names.length; i++)
112            {
113                String name = names[i];
114                String[] values = _parameters.getParameterValues(name);
115    
116                if (values != null)
117                    _portletURL.setParameter(name, values);
118            }
119        }
120    
121        public String getURL(String scheme, String server, int port, String anchor, boolean includeParameters)
122        {
123            // TODO Auto-generated method stub
124            return null;
125        }
126    
127        public String getAbsoluteURL()
128        {
129            throw new UnsupportedOperationException(PortletMessages.unsupportedMethod("getAbsoluteURL"));
130        }
131    
132        public String getAbsoluteURL(String scheme, String server, int port, String anchor,
133                boolean includeParameters)
134        {
135            throw new UnsupportedOperationException(PortletMessages.unsupportedMethod("getAbsoluteURL"));
136        }
137    
138        public String[] getParameterNames()
139        {
140            return _parameters.getParameterNames();
141        }
142    
143        public String[] getParameterValues(String name)
144        {
145            return _parameters.getParameterValues(name);
146        }
147    
148    }