View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.devacfr.maven.skins.reflow;
20  
21  import java.net.URI;
22  
23  import javax.annotation.Nonnull;
24  import javax.annotation.Nullable;
25  
26  import org.apache.maven.doxia.site.inheritance.URIPathDescriptor;
27  import org.apache.velocity.tools.config.DefaultKey;
28  
29  import com.google.common.base.Strings;
30  
31  /**
32   * An Apache Velocity tool that provides utility methods to work with URIs/URLs and links.
33   *
34   * @author Andrius Velykis
35   * @since 1.0
36   */
37  // instancied by Velocity
38  @SuppressWarnings({ "checkstyle:finalclass", "checkstyle:hideutilityclassconstructor" })
39  @DefaultKey("uriTool")
40  public class URITool {
41  
42      /**
43       * Resolves the link as relative to the base dir URI.
44       * <p>
45       * Relativizes only absolute links, if the link has the same scheme, host and port as the base, it is made into a
46       * relative link as viewed from the base.
47       * </p>
48       * <p>
49       * This is the same method that's used to relativize project links in Maven site.
50       * </p>
51       *
52       * @param baseDirUri
53       *            URI that will serve as the base to calculate the relative one
54       * @param link
55       *            The link to relativize (make it relative to the base URI if possible)
56       * @return the relative link, if calculated, or the original link if not.
57       * @since 1.0
58       */
59      @Nullable public static String relativizeLink(@Nullable final String baseDirUri, @Nullable final String link) {
60          // taken from
61          // org.apache.maven.doxia.site.decoration.inheritance.DecorationModelInheritanceAssembler
62  
63          if (link == null || baseDirUri == null) {
64              return link;
65          }
66          try {
67              final URIPathDescriptor path = new URIPathDescriptor(baseDirUri, link);
68              return normalisedBaseUrl(path.relativizeLink().toString());
69          } catch (final IllegalArgumentException e) {
70              return link;
71          }
72      }
73  
74      /**
75       * Creates a URI by parsing the given string.
76       *
77       * @param uri
78       *            The string to be parsed into a URI
79       * @return Returns the new URI.
80       */
81      @Nonnull
82      public static URI toURI(@Nonnull final String uri) {
83          return URI.create(uri);
84      }
85  
86      /**
87       * @param parentBaseUrl
88       *            The base URI. Has to be a valid absolute URI. In addition, the path of the URI should not have any
89       *            file part, ie <code>http://maven.apache.org/</code> is valid,
90       *            <code>http://maven.apache.org/index.html</code> is not.
91       * @param childBaseUrl
92       *            the new base URI. Has to be parsable as a URI.
93       * @return Returns new instance of {@link URLRebaser} allowing to calculate/relative the link as viewed from a
94       *         different base. This returns the {@code parentBaseUrl} link if link is absolute.
95       * @see URIPathDescriptor#rebaseLink(String)
96       * @see URLRebaser#rebaseLink(String)
97       */
98      public static URLRebaser createURLRebaser(@Nullable final String parentBaseUrl,
99          @Nullable final String childBaseUrl) {
100         return new URLRebaser(parentBaseUrl, childBaseUrl);
101     }
102 
103     /**
104      * remove url path separator ('/') to the end of path.
105      *
106      * @param baseUrl
107      *            a base url
108      * @return Returns a <code>String</code> representing base path instance.
109      */
110     @Nullable public static String normalisedBaseUrl(@Nullable final String baseUrl) {
111         if (Strings.isNullOrEmpty(baseUrl)) {
112             return baseUrl;
113         }
114         if (baseUrl.endsWith("/")) {
115             return baseUrl.substring(0, baseUrl.length() - 1);
116         }
117 
118         return baseUrl;
119     }
120 
121     /**
122      * URL rebaser: based on an old and a new path, can rebase a link based on old path to a value based on the new
123      * path.
124      */
125     public static class URLRebaser {
126 
127         /** */
128         private final String oldPath;
129 
130         /** */
131         private final String newPath;
132 
133         /**
134          * Construct a URL rebaser.
135          *
136          * @param oldPath
137          *            the old path. The base URI. Has to be a valid absolute URI. In addition, the path of the URI
138          *            should not have any file part, ie <code>http://maven.apache.org/</code> is valid,
139          *            <code>http://maven.apache.org/index.html</code> is not.
140          * @param newPath
141          *            the new base URI. Has to be parsable as a URI.
142          */
143         protected URLRebaser(@Nullable final String oldPath, @Nullable final String newPath) {
144             this.oldPath = oldPath;
145             this.newPath = newPath;
146         }
147 
148         /**
149          * Get the new path.
150          *
151          * @return the new path.
152          */
153         @Nullable public String getNewPath() {
154             return this.newPath;
155         }
156 
157         /**
158          * Get the old path.
159          *
160          * @return the old path.
161          */
162         @Nullable public String getOldPath() {
163             return this.oldPath;
164         }
165 
166         /**
167          * Rebase only affects relative links, a relative link wrt an old base gets translated, so it points to the same
168          * location as viewed from a new base.
169          *
170          * @param link
171          *            link to rebase
172          * @return Returns a {@link String} representing link rebased.
173          */
174         public String rebaseLink(@Nullable final String link) {
175             if (link == null || getOldPath() == null) {
176                 return link;
177             }
178 
179             if (link.contains("${project.")) {
180                 throw new IllegalArgumentException("site.xml late interpolation ${project.*} expression found"
181                         + " in link: '" + link + "'. Use early interpolation ${this.*}");
182             }
183 
184             final URIPathDescriptor oldPath = new URIPathDescriptor(getOldPath(), link);
185 
186             return oldPath.rebaseLink(getNewPath()).toString();
187         }
188     }
189 }