001// Copyright 2014 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. 014package org.apache.tapestry5.services; 015 016import java.io.Serializable; 017import java.util.List; 018 019/** 020 * Class that encapsulates information about a component library, going beyond what a library mapping 021 * provides. 022 * 023 * @see LibraryMapping 024 * @see SourceUrlResolver 025 * @since 5.4 026 */ 027public final class ComponentLibraryInfo implements Serializable 028{ 029 private static final long serialVersionUID = 1L; 030 031 private LibraryMapping libraryMapping; 032 033 private SourceUrlResolver sourceUrlResolver; 034 035 private String name, description, homepageUrl, documentationUrl, sourceBrowseUrl, issueTrackerUrl, sourceRootUrl, 036 javadocUrl, groupId, artifactId, version; 037 038 private List<String> tags; 039 040 /** 041 * Returns the actual name of the component library (not the identifier). 042 * For example, "Tapestry 5 Core Library". 043 */ 044 public String getName() 045 { 046 return name; 047 } 048 049 /** 050 * Returns a description of the component library. 051 * For example, "The set of components, pages and mixins provided by Tapestry out-of-the-box.". 052 */ 053 public String getDescription() 054 { 055 return description; 056 } 057 058 /** 059 * Returns the URL of the homepage of the component library. 060 * For example, "http://tapestry.apache.org". 061 */ 062 public String getHomepageUrl() 063 { 064 return homepageUrl; 065 } 066 067 /** 068 * Returns the URL of the component library's documentation. 069 * For example, "http://tapestry.apache.org/documentation.html". 070 */ 071 public String getDocumentationUrl() 072 { 073 return documentationUrl; 074 } 075 076 /** 077 * Returns the URL where the component library's source can be browsed. 078 * For example, "https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary". 079 */ 080 public String getSourceBrowseUrl() 081 { 082 return sourceBrowseUrl; 083 } 084 085 /** 086 * Returns the URL where the root folder of component library's source can be found. 087 * For example, "https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree". 088 */ 089 public String getSourceRootUrl() 090 { 091 return sourceRootUrl; 092 } 093 094 /** 095 * Returns the URL of the component's library issue tracker. 096 * For example, "https://issues.apache.org/jira/browse/TAP5". 097 */ 098 public String getIssueTrackerUrl() 099 { 100 return issueTrackerUrl; 101 } 102 103 /** 104 * Returns the URL of the component library's JavaDoc URL. 105 * For example, "http://tapestry.apache.org/current/apidocs/" 106 */ 107 public String getJavadocUrl() 108 { 109 return javadocUrl; 110 } 111 112 /** 113 * Returns the component library's group id for dependency management tools like Maven and Gradle. 114 * For example, "org.apache.tapestry". 115 * @see #artifactId 116 * @see #version 117 */ 118 public String getGroupId() 119 { 120 return groupId; 121 } 122 123 /** 124 * Returns the component library's group id for dependency management tools like Maven and Gradle. 125 * For example, "tapestry-core". 126 * @see #groupId 127 * @see #version 128 */ 129 public String getArtifactId() 130 { 131 return artifactId; 132 } 133 134 /** 135 * Return the component library version. For example, "5.4.0". 136 * @see #artifactId 137 * @see #groupId 138 */ 139 public String getVersion() 140 { 141 return version; 142 } 143 144 /** 145 * Returns the tags associated which describe this component library. 146 * Use just lowercase letters, numbers and dashes. 147 */ 148 public List<String> getTags() 149 { 150 return tags; 151 } 152 153 /** 154 * Returns an URL decribing the dependency management information for this component library. 155 */ 156 public String getDependencyManagementInfoUrl() 157 { 158 String url = null; 159 if (isDependencyManagementInfoPresent()) 160 { 161 url = String.format( 162 "http://search.maven.org/#artifactdetails|%s|%s|version=%s|jar", 163 getGroupId(), getArtifactId(), getVersion()); 164 } 165 return url; 166 } 167 168 public void setName(String name) 169 { 170 if (this.name != null) throwExceptionIfAlreadySet("name", name); 171 this.name = name; 172 } 173 174 public void setDescription(String description) 175 { 176 if (this.description != null) throwExceptionIfAlreadySet("description", description); 177 this.description = description; 178 } 179 180 public void setHomepageUrl(String homepageUrl) 181 { 182 if (this.homepageUrl != null) throwExceptionIfAlreadySet("homepageUrl", homepageUrl); 183 this.homepageUrl = homepageUrl; 184 } 185 186 public void setDocumentationUrl(String documentationUrl) 187 { 188 if (this.documentationUrl != null) throwExceptionIfAlreadySet("documentationUrl", documentationUrl); 189 this.documentationUrl = documentationUrl; 190 } 191 192 public void setSourceBrowseUrl(String sourceBrowseUrl) 193 { 194 if (this.sourceBrowseUrl != null) throwExceptionIfAlreadySet("sourceBrowseUrl", sourceBrowseUrl); 195 this.sourceBrowseUrl = sourceBrowseUrl; 196 } 197 198 public void setSourceRootUrl(String sourceRootUrl) 199 { 200 if (this.sourceRootUrl != null) throwExceptionIfAlreadySet("sourceRootUrl", sourceRootUrl); 201 this.sourceRootUrl = sourceRootUrl; 202 } 203 204 public void setJavadocUrl(String javadocUrl) 205 { 206 if (this.javadocUrl != null) throwExceptionIfAlreadySet("javadocUrl", javadocUrl); 207 this.javadocUrl = javadocUrl; 208 } 209 210 public void setVersion(String version) 211 { 212 if (this.version != null) throwExceptionIfAlreadySet("version", version); 213 this.version = version; 214 } 215 216 public void setGroupId(String groupId) 217 { 218 if (this.groupId != null) throwExceptionIfAlreadySet("groupId", artifactId); 219 this.groupId = groupId; 220 } 221 222 public void setArtifactId(String artifactId) 223 { 224 if (this.artifactId != null) throwExceptionIfAlreadySet("artifactId", artifactId); 225 this.artifactId = artifactId; 226 } 227 228 public void setIssueTrackerUrl(String issueTrackingUrl) 229 { 230 if (this.issueTrackerUrl != null) throwExceptionIfAlreadySet("issueTrackingUrl", issueTrackingUrl); 231 this.issueTrackerUrl = issueTrackingUrl; 232 } 233 234 public void setTags(List<String> tags) 235 { 236 if (this.tags != null) throwExceptionIfAlreadySet("tags", tags); 237 this.tags = tags; 238 } 239 240 public void setLibraryMapping(LibraryMapping libraryMapping) 241 { 242 if (this.libraryMapping != null) throwExceptionIfAlreadySet("libraryMapping", libraryMapping); 243 this.libraryMapping = libraryMapping; 244 } 245 246 public void setSourceUrlResolver(SourceUrlResolver sourceUrlResolver) 247 { 248 if (this.sourceUrlResolver != null) throwExceptionIfAlreadySet("sourceUrlResolver", sourceUrlResolver); 249 this.sourceUrlResolver = sourceUrlResolver; 250 if (sourceUrlResolver != null) 251 { 252 sourceUrlResolver.setRootUrl(getSourceRootUrl()); 253 } 254 } 255 256 /** 257 * Tells whether full dependency management info (group id, artifact id and version) are present. 258 */ 259 public boolean isDependencyManagementInfoPresent() 260 { 261 return groupId != null && artifactId != null && version != null; 262 } 263 264 /** 265 * Given a logical name, tells whether a given component, page or mixin is part of this 266 * component library. 267 */ 268 public boolean isPart(String logicalName) 269 { 270 return logicalName.startsWith(libraryMapping.libraryName + "/") || 271 (libraryMapping.libraryName.equals("") && logicalName.indexOf("/") < 0); 272 } 273 274 /** 275 * Returns the JavaDoc URL for a given class or <code>null</code> if the root JavaDoc URL was 276 * not provided. 277 * @param className the fully qualified class name. 278 */ 279 public String getJavadocUrl(String className) 280 { 281 String url = null; 282 String baseUrl = getJavadocUrl(); 283 if (baseUrl != null) 284 { 285 if (!baseUrl.endsWith("/")) 286 { 287 baseUrl = baseUrl + "/"; 288 } 289 url = baseUrl + className.replace('.', '/') + ".html"; 290 } 291 return url; 292 } 293 294 /** 295 * Returns the URL where the source of this class can be found or <code>null</code> if 296 * not available. This implementation delegates to {@link SourceUrlResolver} if set. 297 * @param className the fully qualified class name. 298 */ 299 public String getSourceUrl(String className) 300 { 301 String url = null; 302 if (sourceUrlResolver != null) 303 { 304 url = sourceUrlResolver.resolve(className); 305 } 306 return url; 307 } 308 309 private void throwExceptionIfAlreadySet(String propertyName, Object propertyValue) 310 { 311 if (propertyValue != null) 312 { 313 throw new RuntimeException(String.format("%s already has a value of \"%s\"", propertyName, propertyValue)); 314 } 315 } 316 317 /** 318 * Interface that provides the source URL for a given {@link ComponentLibraryInfo}. 319 */ 320 public static interface SourceUrlResolver 321 { 322 /** 323 * Returns the source URL for a given class. 324 * @param className the fully qualified class name. 325 */ 326 String resolve(String className); 327 328 /** 329 * Sets the source root URL. This method will be invoked by {@link ComponentLibraryInfo#setSourceBrowseUrl(String)}. 330 */ 331 void setRootUrl(String url); 332 } 333 334 /** 335 * {@link SourceUrlResolver} implementation based on Maven Java project conventions and 336 * GitWeb as online Git repository viewer, which Tapestry itself uses. 337 */ 338 public static class GitWebMavenSourceUrlResolver implements SourceUrlResolver 339 { 340 341 private String sourceRootUrl; 342 343 @Override 344 public String resolve(String className) 345 { 346 return sourceRootUrl + "/" + className.replace('.', '/') + ".java"; 347 } 348 349 @Override 350 public void setRootUrl(String url) 351 { 352 this.sourceRootUrl = url; 353 } 354 355 } 356 357}