001    // Copyright 2009 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.tapestry5.internal.services;
016    
017    import javax.servlet.http.HttpServletRequest;
018    
019    import org.apache.tapestry5.Link;
020    import org.apache.tapestry5.ioc.Invocation;
021    import org.apache.tapestry5.ioc.MethodAdvice;
022    import org.apache.tapestry5.ioc.internal.util.Defense;
023    import org.apache.tapestry5.services.*;
024    import org.apache.tapestry5.urlrewriter.SimpleRequestWrapper;
025    import org.apache.tapestry5.urlrewriter.URLRewriteContext;
026    
027    /**
028     * Advices
029     * {@linkplain ComponentEventLinkEncoder#createComponentEventLink(org.apache.tapestry5.services.ComponentEventRequestParameters, boolean)}
030     * and
031     * {@linkplain ComponentEventLinkEncoder#createPageRenderLink(org.apache.tapestry5.services.PageRenderRequestParameters)}
032     * to rewrites the returned links using {@linkplain URLRewriter}.
033     */
034    public class ComponentEventLinkEncoderMethodAdvice implements MethodAdvice
035    {
036    
037        private final URLRewriter urlRewriter;
038    
039        private final Request request;
040    
041        private final HttpServletRequest httpServletRequest;
042    
043        private final Response response;
044    
045        private final boolean forPageLink;
046    
047        /**
048         * Index of the invocation parameter that contains either the ComponentEventRequestParameter
049         * or the PageRenderRequestParameter objects.
050         */
051        private static final int CONTEXT_PARAMETER_INDEX =0;
052    
053        /**
054         * Single constructor of this class.
055         * 
056         * @param urlRewriter
057         *            an {@link URLRewriter}. It cannot be null.
058         * @param request
059         *            a {@link Request}. It cannot be null.
060         * @param httpServletRequest
061         *            an {@link HttpServletRequest}. It cannot be null.
062         * @param response
063         *            a {@link Response}. It cannot be null.
064         * @param forPageLink
065         *            true if the advice is for page link creation, false for component event link creation.
066         */
067        public ComponentEventLinkEncoderMethodAdvice(URLRewriter urlRewriter,
068                Request request, HttpServletRequest httpServletRequest, Response response,
069                boolean forPageLink)
070        {
071    
072            Defense.notNull(urlRewriter, "urlRewriter");
073            Defense.notNull(request, "request");
074            Defense.notNull(httpServletRequest, "httpServletRequest");
075            Defense.notNull(response, "response");
076    
077            this.httpServletRequest = httpServletRequest;
078            this.urlRewriter = urlRewriter;
079            this.request = request;
080            this.response = response;
081            this.forPageLink = forPageLink;
082        }
083    
084        public void advise(Invocation invocation)
085        {
086            invocation.proceed();
087            String name = invocation.getMethodName();
088    
089            Link link = (Link) invocation.getResult();
090            URLRewriteContext context = setupContext(invocation);
091            Link newLink = rewriteIfNeeded(link,context);
092    
093            if (newLink != null)
094            {
095                invocation.overrideResult(newLink);
096            }
097    
098        }
099    
100        private URLRewriteContext setupContext(final Invocation invocation) {
101    
102            if (forPageLink) {
103                return new URLRewriteContext()
104                {
105    
106                    public boolean isIncoming()
107                    {
108                        return false;
109                    }
110    
111                    public PageRenderRequestParameters getPageParameters()
112                    {
113                        return (PageRenderRequestParameters) invocation.getParameter(CONTEXT_PARAMETER_INDEX);
114                    }
115    
116                    public ComponentEventRequestParameters getComponentEventParameters()
117                    {
118                        return null;
119                    }
120                };
121            }
122            return new URLRewriteContext()
123            {
124    
125                public boolean isIncoming()
126                {
127                    return false;
128                }
129    
130                public PageRenderRequestParameters getPageParameters()
131                {
132                    return null;
133                }
134    
135                public ComponentEventRequestParameters getComponentEventParameters()
136                {
137                    return (ComponentEventRequestParameters) invocation.getParameter(CONTEXT_PARAMETER_INDEX);
138                }
139            };
140        }
141    
142        /**
143         * Returns a rewritten Link or null.
144         * 
145         * @param link
146         *            a {@link Link}.
147         */
148        Link rewriteIfNeeded(Link link, URLRewriteContext context)
149        {
150            Link newLink = null;
151            SimpleRequestWrapper fakeRequest = new SimpleRequestWrapper(request, link.toAbsoluteURI());
152    
153            Request rewritten = urlRewriter.processLink(fakeRequest,context);
154    
155            // if the original request is equal to the rewritten one, no
156            // rewriting is needed
157            if (fakeRequest != rewritten)
158            {
159    
160                final String originalServerName = request.getServerName();
161                final String rewrittenServerName = rewritten.getServerName();
162                boolean absolute = originalServerName.equals(rewrittenServerName) == false;
163                final String newPath = rewritten.getPath();
164    
165                String newUrl = absolute ? fullUrl(rewritten) : newPath;
166    
167                newLink = new LinkImpl(newUrl, false, false, response, null);
168    
169            }
170    
171            return newLink;
172    
173        }
174    
175        String fullUrl(Request request)
176        {
177    
178            String protocol = request.isSecure() ? "https://" : "http://";
179            final int localPort = httpServletRequest.getLocalPort();
180            String port = localPort == 80 ? "" : ":" + localPort;
181    
182            final String path = request.getPath();
183            final String contextPath = request.getContextPath();
184            return String.format("%s%s%s%s%s", protocol, request.getServerName(), port, contextPath, path);
185    
186        }
187    
188    }