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 }