001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.request.resource;
018
019import org.apache.wicket.request.IUrlRenderer;
020import org.apache.wicket.request.Url;
021import org.apache.wicket.request.UrlUtils;
022import org.apache.wicket.request.cycle.RequestCycle;
023import org.apache.wicket.util.lang.Args;
024
025/**
026 * A ResourceReference that can be used to point to a resource by using an Url. For example to a
027 * resource residing in a CDN (Content Delivering Network) or context relative one.
028 * 
029 * @since 6.0
030 */
031public class UrlResourceReference extends ResourceReference
032{
033        /**
034         * An Url that knows how to render itself, so it doesn't need re-calculating in UrlRenderer. It
035         * should be rendered as is.
036         */
037        private static class CalculatedUrl extends Url implements IUrlRenderer
038        {
039                private CalculatedUrl(Url original)
040                {
041                        super(original);
042                }
043
044                @Override
045                public String renderFullUrl(Url url, Url baseUrl)
046                {
047                        StringMode mode = getStringMode(url);
048                        return url.toString(mode);
049                }
050
051                @Override
052                public String renderRelativeUrl(Url url, Url baseUrl)
053                {
054                        return url.toString();
055                }
056        }
057
058        /**
059         * The url to the resource.
060         */
061        private final Url url;
062
063        private boolean contextRelative = false;
064
065        /**
066         * Constructor.
067         * 
068         * @param url
069         *            the url of the external resource
070         */
071        public UrlResourceReference(final Url url)
072        {
073                super(asName(url));
074
075                this.url = url;
076        }
077
078        private static String asName(Url externalUrl)
079        {
080                Args.notNull(externalUrl, "url");
081                return externalUrl.toString();
082        }
083
084        /**
085         * @return the url of the external resource
086         */
087        public final Url getUrl()
088        {
089                CalculatedUrl _url;
090
091                if (contextRelative)
092                {
093                        String contextRelative = UrlUtils.rewriteToContextRelative(url.toString(),
094                                RequestCycle.get());
095                        _url = new CalculatedUrl(Url.parse(contextRelative, url.getCharset()));
096                }
097                else
098                {
099                        _url = new CalculatedUrl(url);
100                }
101
102                return _url;
103        }
104
105        /**
106         * @return {@code null} because this ResourceReference won't use an IResource to deliver the
107         *         content of the external resource. The browser will make a direct request to the
108         *         external url.
109         */
110        @Override
111        public final IResource getResource()
112        {
113                return null;
114        }
115
116        public UrlResourceReference setContextRelative(final boolean contextRelative)
117        {
118                if (contextRelative && (url.isFull() || url.isContextAbsolute()))
119                {
120                        throw new IllegalStateException(String.format(
121                                "An absolute url '%s' cannot be rendered as context relative", url));
122                }
123                this.contextRelative = contextRelative;
124                return this;
125        }
126
127        public boolean isContextRelative()
128        {
129                return contextRelative;
130        }
131
132        @Override
133        public String toString()
134        {
135                return "UrlResourceReference{" + "url=" + url.toString(getStringMode(url)) +
136                        ", contextRelative=" + contextRelative + '}';
137        }
138
139        private static Url.StringMode getStringMode(Url url)
140        {
141                final Url.StringMode mode;
142                if (url.isFull())
143                {
144                        mode = Url.StringMode.FULL;
145                }
146                else
147                {
148                        mode = Url.StringMode.LOCAL;
149                }
150                return mode;
151        }
152}