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