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