You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2014/07/04 21:49:03 UTC
git commit: Partial implementation of TAP5-2192 : a new Component
Libraries tab was added to the T5Dashboard,
presenting information and the list of components,
pages and mixins from each one.
Repository: tapestry-5
Updated Branches:
refs/heads/master ee0220c64 -> 6843db06f
Partial implementation of TAP5-2192 : a new Component Libraries tab was
added to the T5Dashboard, presenting information and the list of
components, pages and mixins from each one.
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/6843db06
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/6843db06
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/6843db06
Branch: refs/heads/master
Commit: 6843db06f07427cdc00e2b556dcb1077269a134b
Parents: ee0220c
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Fri Jul 4 16:48:43 2014 -0300
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Fri Jul 4 16:48:43 2014 -0300
----------------------------------------------------------------------
.../corelib/pages/ComponentLibraries.java | 152 +++++++++
.../tapestry5/corelib/pages/ServiceStatus.java | 2 +-
.../services/ComponentClassResolverImpl.java | 34 ++
.../tapestry5/modules/DashboardModule.java | 3 +-
.../tapestry5/modules/TapestryModule.java | 18 +-
.../services/ComponentClassResolver.java | 24 +-
.../services/ComponentLibraryInfo.java | 324 +++++++++++++++++++
.../tapestry5/services/LibraryMapping.java | 37 ++-
.../org/apache/tapestry5/core.properties | 7 +-
.../corelib/pages/ComponentLibraries.tml | 126 ++++++++
10 files changed, 717 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ComponentLibraries.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ComponentLibraries.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ComponentLibraries.java
new file mode 100644
index 0000000..6e27f6c
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ComponentLibraries.java
@@ -0,0 +1,152 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.corelib.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tapestry5.Block;
+import org.apache.tapestry5.annotations.Cached;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
+import org.apache.tapestry5.annotations.WhitelistAccessOnly;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.services.ComponentClassResolver;
+import org.apache.tapestry5.services.ComponentLibraryInfo;
+
+/**
+ * Page used to describe the component libraries being used in the application.
+ * Notice: the implementation of this page was done to avoid creating components, so the
+ * Tapestry 5 Core Library didn't get polluted with internal-only components.
+ */
+@UnknownActivationContextCheck(false)
+@WhitelistAccessOnly
+public class ComponentLibraries
+{
+
+ private static enum Type { PAGE, COMPONENT, MIXIN }
+
+ @Inject
+ private ComponentClassResolver componentClassResolver;
+
+ @Property
+ private String libraryName;
+
+ @Property
+ private String logicalName;
+
+ @Property
+ private List<String> logicalNames;
+
+ @Property
+ private String headerName;
+
+ @Property
+ private List<String> pages;
+
+ @Property
+ private List<String> components;
+
+ @Property
+ private List<String> mixins;
+
+ private Type type;
+
+ @Inject
+ private Block classesTable;
+
+ @Cached(watch="libraryName")
+ public ComponentLibraryInfo getInfo()
+ {
+ return componentClassResolver.getComponentLibraryInfo(libraryName);
+ }
+
+ public List<String> getLibraryNames() {
+ return componentClassResolver.getLibraryNames();
+ }
+
+ public String getLibraryClientId()
+ {
+ return libraryName.replace("/", "-");
+ }
+
+ private List<String> filter(final List<String> allNames)
+ {
+ List<String> logicalNames = new ArrayList<String>();
+ for (String name : allNames)
+ {
+
+ if (name.startsWith(libraryName + "/") && !(libraryName.equals("core") && name.endsWith("Test")))
+ {
+ logicalNames.add(name);
+ }
+ }
+
+ return logicalNames;
+ }
+
+ public Block getComponentsTable()
+ {
+ logicalNames = filter(componentClassResolver.getComponentNames());
+ type = Type.COMPONENT;
+ headerName = "Components";
+ return classesTable;
+ }
+
+ public Block getPagesTable()
+ {
+ logicalNames = filter(componentClassResolver.getPageNames());
+ type = Type.PAGE;
+ headerName = "Pages";
+ return classesTable;
+ }
+
+ public Block getMixinsTable()
+ {
+ logicalNames = filter(componentClassResolver.getMixinNames());
+ type = Type.MIXIN;
+ headerName = "Mixins";
+ return classesTable;
+ }
+
+ public String getSourceUrl()
+ {
+ return getInfo() != null ? getInfo().getSourceUrl(getClassName()) : null;
+ }
+
+ public String getJavaDocUrl()
+ {
+ return getInfo() != null ? getInfo().getJavadocUrl(getClassName()) : null;
+ }
+
+ private String getClassName()
+ {
+ final String className;
+ switch (type)
+ {
+ case PAGE: className = componentClassResolver.resolvePageNameToClassName(logicalName); break;
+ case COMPONENT: className = componentClassResolver.resolveComponentTypeToClassName(logicalName); break;
+ case MIXIN: className = componentClassResolver.resolveMixinTypeToClassName(logicalName); break;
+ default: className = null; // should never happen
+ }
+ return className;
+ }
+
+ public String getSimpleLogicalName()
+ {
+ return logicalName.replace("core/", "");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ServiceStatus.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ServiceStatus.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ServiceStatus.java
index 4c99023..55a3b62 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ServiceStatus.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/ServiceStatus.java
@@ -62,7 +62,7 @@ public class ServiceStatus
model.addEmpty("serviceInterface");
// There's no line number information for interfaces, so we'll reorder the
- // proprieties manually.
+ // properties manually.
model.reorder("serviceId", "serviceInterface", "scope", "status");
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassResolverImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassResolverImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassResolverImpl.java
index cad9404..ba027e4 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassResolverImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentClassResolverImpl.java
@@ -24,6 +24,7 @@ import org.apache.tapestry5.ioc.services.ClassNameLocator;
import org.apache.tapestry5.ioc.util.AvailableValues;
import org.apache.tapestry5.ioc.util.UnknownValueException;
import org.apache.tapestry5.services.ComponentClassResolver;
+import org.apache.tapestry5.services.ComponentLibraryInfo;
import org.apache.tapestry5.services.InvalidationListener;
import org.apache.tapestry5.services.LibraryMapping;
import org.apache.tapestry5.services.transform.ControlledPackageType;
@@ -51,6 +52,9 @@ public class ComponentClassResolverImpl implements ComponentClassResolver, Inval
// Map from library name to a list of root package names (usuallly just one).
private final Map<String, List<String>> libraryNameToPackageNames = CollectionFactory.newCaseInsensitiveMap();
+ // Map from library name to a ComponentLibraryInfo
+ private final Map<String, ComponentLibraryInfo> libraryNameToInfo = CollectionFactory.newCaseInsensitiveMap();
+
private final Map<String, ControlledPackageType> packageNameToType = CollectionFactory.newMap();
/**
@@ -255,6 +259,8 @@ public class ComponentClassResolverImpl implements ComponentClassResolver, Inval
for (LibraryMapping mapping : mappings)
{
String libraryName = mapping.libraryName;
+
+ libraryNameToInfo.put(libraryName, mapping.getComponentLibraryInfo());
List<String> packages = this.libraryNameToPackageNames.get(libraryName);
@@ -453,6 +459,28 @@ public class ComponentClassResolverImpl implements ComponentClassResolver, Inval
return result;
}
+ public List<String> getComponentNames()
+ {
+ Data data = getData();
+
+ List<String> result = CollectionFactory.newList(data.componentToClassName.keySet());
+
+ Collections.sort(result);
+
+ return result;
+ }
+
+ public List<String> getMixinNames()
+ {
+ Data data = getData();
+
+ List<String> result = CollectionFactory.newList(data.mixinToClassName.keySet());
+
+ Collections.sort(result);
+
+ return result;
+ }
+
public String resolveComponentTypeToClassName(final String componentType)
{
Data data = getData();
@@ -669,4 +697,10 @@ public class ComponentClassResolverImpl implements ComponentClassResolver, Inval
}
}
}
+
+ public ComponentLibraryInfo getComponentLibraryInfo(String libraryName)
+ {
+ return libraryNameToInfo.get(libraryName);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
index 22abd21..9eccdc1 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
@@ -1,4 +1,4 @@
-// Copyright 2013 The Apache Software Foundation
+// Copyright 2013, 2014 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -33,5 +33,6 @@ public class DashboardModule
{
configuration.add("Pages", new DashboardTab("Pages", "core/PageCatalog"));
configuration.add("Services", new DashboardTab("Services", "core/ServiceStatus"));
+ configuration.add("Libraries", new DashboardTab("ComponentLibraries", "core/ComponentLibraries"));
}
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index 50d03b4..8e3e070 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -443,8 +443,24 @@ public final class TapestryModule
@Symbol(InternalConstants.TAPESTRY_APP_PACKAGE_PARAM)
String appRootPackage)
{
- configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.corelib"));
+
+ ComponentLibraryInfo info = new ComponentLibraryInfo();
+ info.setName("Tapestry 5 Core Library");
+ info.setDescription("The set of components, pages and mixins provided by Tapestry out-of-the-box.");
+ info.setHomepageUrl("http://tapestry.apache.org");
+ info.setDocumentationUrl("http://tapestry.apache.org/documentation.html");
+ info.setSourceBrowseUrl("https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary");
+ info.setSourceRootUrl("https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=blob;f=tapestry-core/src/main/java");
+ info.setJavadocUrl("http://tapestry.apache.org/current/apidocs/");
+ info.setIssueTrackerUrl("https://issues.apache.org/jira/browse/TAP5");
+ info.setGroupId("org.apache.tapestry");
+ info.setArtifactId("tapestry-core");
+ info.setVersion("5.4.0");
+ info.setSourceUrlResolver(new ComponentLibraryInfo.GitWebMavenSourceUrlResolver());
+
+ configuration.add(new LibraryMapping(InternalConstants.CORE_LIBRARY, "org.apache.tapestry5.corelib", info));
configuration.add(new LibraryMapping("", appRootPackage));
+
}
/**
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
index f6e8a1f..d6e3049 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
@@ -15,6 +15,7 @@
package org.apache.tapestry5.services;
import org.apache.tapestry5.Asset;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
import org.apache.tapestry5.ioc.annotations.UsesConfiguration;
import org.apache.tapestry5.ioc.services.ClassNameLocator;
import org.apache.tapestry5.services.transform.ControlledPackageType;
@@ -67,6 +68,20 @@ public interface ComponentClassResolver
List<String> getPageNames();
/**
+ * Returns a list of all component names, in sorted order. These are the "canonical" component names.
+ * @since 5.4
+ */
+ @IncompatibleChange(release = "5.4", details = "added method")
+ List<String> getComponentNames();
+
+ /**
+ * Returns a list of all mixin names, in sorted order. These are the "canonical" mixin names.
+ * @since 5.4
+ */
+ @IncompatibleChange(release = "5.4", details = "added method")
+ List<String> getMixinNames();
+
+ /**
* Converts a fully qualified page class name into a page name (often, for inclusion as part of the URI). This value
* may later be passed to {@link #resolvePageNameToClassName(String)}.
*
@@ -132,7 +147,14 @@ public interface ComponentClassResolver
* @since 5.4
*/
List<String> getLibraryNames();
-
+
+ /**
+ * Returns an object encapsulating information about a component library, if provided.
+ * @param libraryName the library name (prefix).
+ * @return a {@link ComponentLibraryInfo} or <code>null</code>
+ */
+ ComponentLibraryInfo getComponentLibraryInfo(String libraryName);
+
/**
* Used to identify which packages are controlled packages (from which components are loaded). Future expansion
* may allow for additional packages which are live reloaded but not components (or perhaps are transformed, but not
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java
new file mode 100644
index 0000000..78d2cae
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java
@@ -0,0 +1,324 @@
+// Copyright 2014 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.services;
+
+import java.io.Serializable;
+
+/**
+ * Class that encapsulates information about a component library, going beyond what a library mapping
+ * provides.
+ *
+ * @see LibraryMapping
+ * @see SourceUrlResolver
+ * @since 5.4
+ */
+public final class ComponentLibraryInfo implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ private LibraryMapping libraryMapping;
+
+ private SourceUrlResolver sourceUrlResolver;
+
+ private String name, description, homepageUrl, documentationUrl, sourceBrowseUrl, issueTrackerUrl, sourceRootUrl,
+ javadocUrl, groupId, artifactId, version;
+
+ /**
+ * Returns the actual name of the component library (not the identifier).
+ * For example, "Tapestry 5 Core Library".
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns a description of the component library.
+ * For example, "The set of components, pages and mixins provided by Tapestry out-of-the-box.".
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /**
+ * Returns the URL of the homepage of the component library.
+ * For example, "http://tapestry.apache.org".
+ */
+ public String getHomepageUrl()
+ {
+ return homepageUrl;
+ }
+
+ /**
+ * Returns the URL of the component library's documentation.
+ * For example, "http://tapestry.apache.org/documentation.html".
+ */
+ public String getDocumentationUrl()
+ {
+ return documentationUrl;
+ }
+
+ /**
+ * Returns the URL where the component library's source can be browsed.
+ * For example, "https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=summary".
+ */
+ public String getSourceBrowseUrl()
+ {
+ return sourceBrowseUrl;
+ }
+
+ /**
+ * Returns the URL where the root folder of component library's source can be found.
+ * For example, "https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree".
+ */
+ public String getSourceRootUrl()
+ {
+ return sourceRootUrl;
+ }
+
+ /**
+ * Returns the URL of the component's library issue tracker.
+ * For example, "https://issues.apache.org/jira/browse/TAP5".
+ */
+ public String getIssueTrackerUrl()
+ {
+ return issueTrackerUrl;
+ }
+
+ /**
+ * Returns the URL of the component library's JavaDoc URL.
+ * For example, "http://tapestry.apache.org/current/apidocs/"
+ */
+ public String getJavadocUrl()
+ {
+ return javadocUrl;
+ }
+
+ /**
+ * Returns the component library's group id for dependency management tools like Maven and Gradle.
+ * For example, "org.apache.tapestry".
+ * @see #artifactId
+ * @see #version
+ */
+ public String getGroupId()
+ {
+ return groupId;
+ }
+
+ /**
+ * Returns the component library's group id for dependency management tools like Maven and Gradle.
+ * For example, "tapestry-core".
+ * @see #groupId
+ * @see #version
+ */
+ public String getArtifactId()
+ {
+ return artifactId;
+ }
+
+ /**
+ * Return the component library version. For example, "5.4.0".
+ * @see #artifactId
+ * @see #groupId
+ */
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public void setName(String name)
+ {
+ if (this.name != null) throwExceptionIfAlreadySet("name", name);
+ this.name = name;
+ }
+
+ public void setDescription(String description)
+ {
+ if (this.description != null) throwExceptionIfAlreadySet("description", description);
+ this.description = description;
+ }
+
+ public void setHomepageUrl(String homepageUrl)
+ {
+ if (this.homepageUrl != null) throwExceptionIfAlreadySet("homepageUrl", homepageUrl);
+ this.homepageUrl = homepageUrl;
+ }
+
+ public void setDocumentationUrl(String documentationUrl)
+ {
+ if (this.documentationUrl != null) throwExceptionIfAlreadySet("documentationUrl", documentationUrl);
+ this.documentationUrl = documentationUrl;
+ }
+
+ public void setSourceBrowseUrl(String sourceBrowseUrl)
+ {
+ if (this.sourceBrowseUrl != null) throwExceptionIfAlreadySet("sourceBrowseUrl", sourceBrowseUrl);
+ this.sourceBrowseUrl = sourceBrowseUrl;
+ }
+
+ public void setSourceRootUrl(String sourceRootUrl)
+ {
+ if (this.sourceRootUrl != null) throwExceptionIfAlreadySet("sourceRootUrl", sourceRootUrl);
+ this.sourceRootUrl = sourceRootUrl;
+ }
+
+ public void setJavadocUrl(String javadocUrl)
+ {
+ if (this.javadocUrl != null) throwExceptionIfAlreadySet("javadocUrl", javadocUrl);
+ this.javadocUrl = javadocUrl;
+ }
+
+ public void setVersion(String version)
+ {
+ if (this.version != null) throwExceptionIfAlreadySet("version", version);
+ this.version = version;
+ }
+
+ public void setGroupId(String groupId)
+ {
+ if (this.groupId != null) throwExceptionIfAlreadySet("groupId", artifactId);
+ this.groupId = groupId;
+ }
+
+ public void setArtifactId(String artifactId)
+ {
+ if (this.artifactId != null) throwExceptionIfAlreadySet("artifactId", artifactId);
+ this.artifactId = artifactId;
+ }
+
+ public void setIssueTrackerUrl(String issueTrackingUrl)
+ {
+ if (this.issueTrackerUrl != null) throwExceptionIfAlreadySet("issueTrackingUrl", issueTrackingUrl);
+ this.issueTrackerUrl = issueTrackingUrl;
+ }
+
+ public void setLibraryMapping(LibraryMapping libraryMapping)
+ {
+ if (this.libraryMapping != null) throwExceptionIfAlreadySet("libraryMapping", libraryMapping);
+ this.libraryMapping = libraryMapping;
+ }
+
+ public void setSourceUrlResolver(SourceUrlResolver sourceUrlResolver)
+ {
+ if (this.sourceUrlResolver != null) throwExceptionIfAlreadySet("sourceUrlResolver", sourceUrlResolver);
+ this.sourceUrlResolver = sourceUrlResolver;
+ if (sourceUrlResolver != null)
+ {
+ sourceUrlResolver.setRootUrl(getSourceRootUrl());
+ }
+ }
+
+ /**
+ * Tells whether full dependency management info (group id, artifact id and version) are present.
+ */
+ public boolean isDependencyManagementInfoPresent()
+ {
+ return groupId != null && artifactId != null && version != null;
+ }
+
+ /**
+ * Given a logical name, tells whether a given component, page or mixin is part of this
+ * component library.
+ */
+ public boolean isPart(String logicalName)
+ {
+ return logicalName.startsWith(libraryMapping.libraryName + "/") ||
+ (libraryMapping.libraryName.equals("") && logicalName.indexOf("/") < 0);
+ }
+
+ /**
+ * Returns the JavaDoc URL for a given class or <code>null</code> if the root JavaDoc URL was
+ * not provided.
+ * @param className the fully qualified class name.
+ */
+ public String getJavadocUrl(String className)
+ {
+ String url = null;
+ String baseUrl = getJavadocUrl();
+ if (baseUrl != null)
+ {
+ if (!baseUrl.endsWith("/"))
+ {
+ baseUrl = baseUrl + "/";
+ }
+ url = baseUrl + className.replace('.', '/') + ".html";
+ }
+ return url;
+ }
+
+ /**
+ * Returns the URL where the source of this class can be found or <code>null</code> if
+ * not available. This implementation delegates to {@link SourceUrlResolver} if set.
+ * @param className the fully qualified class name.
+ */
+ public String getSourceUrl(String className)
+ {
+ String url = null;
+ if (sourceUrlResolver != null)
+ {
+ url = sourceUrlResolver.resolve(className);
+ }
+ return url;
+ }
+
+ private void throwExceptionIfAlreadySet(String propertyName, Object propertyValue)
+ {
+ if (propertyValue != null)
+ {
+ throw new RuntimeException(String.format("%s already has a value of \"%s\"", propertyName, propertyValue));
+ }
+ }
+
+ /**
+ * Interface that provides the source URL for a given {@link ComponentLibraryInfo}.
+ */
+ public static interface SourceUrlResolver
+ {
+ /**
+ * Returns the source URL for a given class.
+ * @param className the fully qualified class name.
+ */
+ String resolve(String className);
+
+ /**
+ * Sets the source root URL. This method will be invoked by {@link ComponentLibraryInfo#setSourceBrowseUrl(String)}.
+ */
+ void setRootUrl(String url);
+ }
+
+ /**
+ * {@link SourceUrlResolver} implementation based on Maven Java project conventions and
+ * GitWeb as online Git repository viewer, which Tapestry itself uses.
+ */
+ public static class GitWebMavenSourceUrlResolver implements SourceUrlResolver
+ {
+
+ private String sourceRootUrl;
+
+ @Override
+ public String resolve(String className)
+ {
+ return sourceRootUrl + "/" + className.replace('.', '/') + ".java";
+ }
+
+ @Override
+ public void setRootUrl(String url)
+ {
+ this.sourceRootUrl = url;
+ }
+
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java
index 476c187..69e4f12 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java
@@ -1,4 +1,4 @@
-// Copyright 2006, 2010, 2011, 2012 The Apache Software Foundation
+// Copyright 2006, 2010, 2011, 2012, 2014 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -11,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-
package org.apache.tapestry5.services;
import org.apache.tapestry5.ioc.internal.util.InternalUtils;
@@ -31,11 +30,18 @@ import org.apache.tapestry5.ioc.internal.util.InternalUtils;
* <dt>base</dt>
* <dd>contains base classes</dd>
* </dl>
+ * <p>
+ * Since 5.4 on, a library mapping can also have a {@link ComponentLibraryInfo} to provide more
+ * information about itself, such as URLs (project, documentation, JavaDoc, sources) and
+ * coordinates for dependency management tools (group id, artifact id, version).
+ * </p>
*/
public final class LibraryMapping
{
public final String libraryName, rootPackage;
-
+
+ private ComponentLibraryInfo componentLibraryInfo;
+
/**
* Identifies the root package of a library. The application has uses the library name "" (the empty string).
* The special library "core" is all the built-in components.
@@ -53,7 +59,7 @@ public final class LibraryMapping
* @param libraryName
* the unique identifier for the library.
* @param rootPackage
- * The root package to search for classes; sub-packages will include ".pages", ".components", etc.
+ * the root package to search for classes; sub-packages will include ".pages", ".components", etc.
*/
public LibraryMapping(String libraryName, String rootPackage)
{
@@ -68,6 +74,18 @@ public final class LibraryMapping
this.libraryName = libraryName;
this.rootPackage = rootPackage;
+ this.componentLibraryInfo = null;
+ }
+
+ /**
+ * Same as {@link #LibraryMapping(String, String)}, with with an additional {@link ComponentLibraryInfo} parameter.
+ * @since 5.4
+ */
+ public LibraryMapping(String libraryName, String rootPackage, ComponentLibraryInfo componentLibraryInfo)
+ {
+ this(libraryName, rootPackage);
+ this.componentLibraryInfo = componentLibraryInfo;
+ componentLibraryInfo.setLibraryMapping(this);
}
/**
@@ -85,10 +103,21 @@ public final class LibraryMapping
{
return rootPackage;
}
+
+ /**
+ * Returns the component library information for this library mapping.
+ * @return a {@link ComponentLibraryInfo}.
+ * @since 5.4
+ */
+ public ComponentLibraryInfo getComponentLibraryInfo()
+ {
+ return componentLibraryInfo;
+ }
@Override
public String toString()
{
return String.format("LibraryMapping[%s, %s]", libraryName, rootPackage);
}
+
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
index bda03c8..2601000 100644
--- a/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/core.properties
@@ -1,4 +1,4 @@
-# Copyright 2013 The Apache Software Foundation
+# Copyright 2013-2014 The Apache Software Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -127,4 +127,7 @@ private-default-confirm-message=Are you sure you want to continue?
private-default-confirm-title=Confirm
# See the LocalDate component
-private-default-localdate-format=lll
\ No newline at end of file
+private-default-localdate-format=lll
+
+# see ComponentLibraries page
+not-informed=Not informed
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6843db06/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ComponentLibraries.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ComponentLibraries.tml b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ComponentLibraries.tml
new file mode 100644
index 0000000..147912c
--- /dev/null
+++ b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/ComponentLibraries.tml
@@ -0,0 +1,126 @@
+<t:block id="content"
+ xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
+
+ <h1><strong>${libraryNames.size()}</strong> component libraries found</h1>
+
+ <ul id="libraryList" class="list-group">
+ <li t:type="Loop" t:source="libraryNames" t:value="libraryName" class="list-group-item">
+ <a href="#${libraryClientId}">
+ <code>${libraryName}</code> <t:if test="info">: ${info.name}</t:if>
+ </a>
+ <p t:type="If" t:test="info?.description">
+ ${info.description}
+ </p>
+ </li>
+ </ul>
+
+ <div id="libraries">
+
+ <div class="libraryInfo" t:type="Loop" t:source="libraryNames" t:value="libraryName" id="${libraryClientId}">
+
+ <h2><code>${libraryName}</code> <t:if test="info">: ${info.name}</t:if></h2>
+
+ <t:if test="info">
+
+ <dl class="dl-horizontal">
+
+ <dt>Homepage</dt>
+ <dd>
+ <t:if test="info.homepageUrl" else="message:not-informed">
+ <a href="${info.homepageUrl}">${info.homepageUrl}</a>
+ </t:if>
+ </dd>
+
+ <dt>Documentation URL</dt>
+ <dd>
+ <t:if test="info.documentationUrl" else="message:not-informed">
+ <a href="${info.documentationUrl}">${info.documentationUrl}</a>
+ </t:if>
+ </dd>
+
+ <dt>Source JavaDoc URL</dt>
+ <dd>
+ <t:if test="info.javadocUrl" else="message:not-informed">
+ <a href="${info.javadocUrl}">${info.javadocUrl}</a>
+ </t:if>
+ </dd>
+
+ <t:if test="info.dependencyManagementInfoPresent">
+ <dt>Dependency information</dt>
+ <dd>
+ Group id <code class="groupId">${info.groupId}</code>,
+ artifact id <code class="groupId">${info.artifactId}</code>,
+ version. <code class="groupId">${info.version}</code>
+ <br/>
+ <a href="http://search.maven.org/#artifactdetails|${info.groupId}|${info.artifactId}|version=${info.version}|jar"
+ target="_blank">
+ <em>More information at Maven Central Respository</em>
+ </a>
+ </dd>
+ </t:if>
+
+ <dt>Source browse URL</dt>
+ <dd>
+ <t:if test="info.sourceBrowseUrl" else="message:not-informed">
+ <a href="${info.sourceBrowseUrl}">${info.sourceBrowseUrl}</a>
+ </t:if>
+ </dd>
+
+ <dt>Source root URL</dt>
+ <dd>
+ <t:if test="info.sourceRootUrl" else="message:not-informed">
+ <a href="${info.sourceRootUrl}">${info.sourceRootUrl}</a>
+ </t:if>
+ </dd>
+
+ <dt>Issue tracker URL</dt>
+ <dd>
+ <t:if test="info.issueTrackerUrl" else="message:not-informed">
+ <a href="${info.issueTrackerUrl}">${info.issueTrackerUrl}</a>
+ </t:if>
+ </dd>
+
+ </dl>
+
+ </t:if>
+
+ <p t:type="If" t:test="!info">No additional information provided for <code>${libraryName}</code>.</p>
+
+<!-- <div t:type="Zone" t:id="pages" id="prop:libraryClientZoneClientId"> -->
+<!-- </div> -->
+
+ <div t:type="Delegate" to="componentsTable"></div>
+ <div t:type="Delegate" to="pagesTable"></div>
+ <div t:type="Delegate" to="mixinsTable"></div>
+
+ </div>
+
+ </div>
+
+ <t:block id="classesTable">
+ <div t:type="If" t:test="!logicalNames.empty">
+ <h3>${headerName}</h3>
+ <table class="table table-striped table-hover table-condensed">
+ <thead>
+ <tr>
+ <td>Name</td>
+ <td>JavaDoc URL</td>
+ <td>Source URL</td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr t:type="Loop" t:source="logicalNames" t:value="logicalName">
+ <td><code>${simpleLogicalName}</code></td>
+ <td><t:if test="javadocUrl" else="message:not-informed" target="_blank">
+ <a href="${javadocUrl}">JavaDoc</a></t:if>
+ </td>
+ <td><t:if test="sourceUrl" else="message:not-informed" target="_blank">
+ <a href="${sourceUrl}">Source</a></t:if>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </t:block>
+
+</t:block>