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
015package org.apache.tapestry.portlet;
016
017import javax.portlet.PortletURL;
018
019import org.apache.hivemind.util.Defense;
020import org.apache.tapestry.engine.ILink;
021import org.apache.tapestry.util.QueryParameterMap;
022
023/**
024 * Wrapper around {@link javax.portlet.PortletURL}.
025 * 
026 * @author Howard M. Lewis Ship
027 * @since 4.0
028 */
029public class PortletLink implements ILink
030{
031    private final PortletURL _portletURL;
032
033    private final QueryParameterMap _parameters;
034
035    public PortletLink(PortletURL portletURL, QueryParameterMap parameters)
036    {
037        Defense.notNull(portletURL, "portletURL");
038        Defense.notNull(parameters, "parameters");
039
040        _portletURL = portletURL;
041        _parameters = parameters;
042    }
043
044    public String getURL()
045    {
046        return getURL(null, true);
047    }
048
049    public String getURL(String anchor, boolean includeParameters)
050    {
051        if (includeParameters)
052            loadParameters();
053
054        String url = _portletURL.toString();
055
056        url = unencode(url);
057
058        if (anchor != null)
059            url = url + "#" + anchor;
060
061        return url;
062    }
063
064    /**
065     * The PortletURL class returns a url that's already XML-escaped, ready for inclusion directly
066     * into the response stream. However, the IMarkupWriter expects to do that encoding too ... and
067     * double encoding is bad. So we back out the most likely encoding (convert '&' to just
068     * '&').
069     */
070
071    private String unencode(String url)
072    {
073        StringBuffer buffer = new StringBuffer(url.length());
074        String text = url;
075
076        while (true)
077        {
078            int ampx = text.indexOf("&");
079
080            if (ampx < 0)
081                break;
082
083            // Take up to and including the '&'
084
085            buffer.append(text.substring(0, ampx + 1));
086
087            text = text.substring(ampx + 5);
088        }
089
090        buffer.append(text);
091
092        return buffer.toString();
093    }
094
095    private void loadParameters()
096    {
097        String[] names = _parameters.getParameterNames();
098
099        for (int i = 0; i < names.length; i++)
100        {
101            String name = names[i];
102            String[] values = _parameters.getParameterValues(name);
103
104            if (values != null)
105                _portletURL.setParameter(name, values);
106        }
107    }
108
109    public String getURL(String scheme, String server, int port, String anchor,
110            boolean includeParameters)
111    {
112        // Ignore scheme, server and port ... those are under the control of the portlet container.
113
114        return getURL(anchor, includeParameters);
115    }
116
117    public String getAbsoluteURL()
118    {
119        throw new UnsupportedOperationException(PortletMessages.unsupportedMethod("getAbsoluteURL"));
120    }
121
122    public String getAbsoluteURL(String scheme, String server, int port, String anchor,
123            boolean includeParameters)
124    {
125        throw new UnsupportedOperationException(PortletMessages.unsupportedMethod("getAbsoluteURL"));
126    }
127
128    public String[] getParameterNames()
129    {
130        return _parameters.getParameterNames();
131    }
132
133    public String[] getParameterValues(String name)
134    {
135        return _parameters.getParameterValues(name);
136    }
137
138}