Repository: tapestry-5 Updated Branches: refs/heads/master adf7e8bd4 -> b1062f538
First complete implementation of TAP5-2192 Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/b1062f53 Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/b1062f53 Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/b1062f53 Branch: refs/heads/master Commit: b1062f538846cdca943d0d4615d888b2e70a1b87 Parents: adf7e8b Author: Thiago H. de Paula Figueiredo <[email protected]> Authored: Sun Aug 24 20:38:13 2014 -0300 Committer: Thiago H. de Paula Figueiredo <[email protected]> Committed: Sun Aug 24 20:38:13 2014 -0300 ---------------------------------------------------------------------- .../MavenComponentLibraryInfoSource.java | 184 +++++++++++++++++-- .../tapestry5/modules/TapestryModule.java | 40 +++- .../services/ComponentLibraryInfo.java | 14 +- 3 files changed, 215 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1062f53/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MavenComponentLibraryInfoSource.java ---------------------------------------------------------------------- diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MavenComponentLibraryInfoSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MavenComponentLibraryInfoSource.java index 3a985b6..f80dec2 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MavenComponentLibraryInfoSource.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/MavenComponentLibraryInfoSource.java @@ -13,17 +13,31 @@ // limitations under the License. package org.apache.tapestry5.internal.services; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.URISyntaxException; import java.net.URL; -import java.util.Properties; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.apache.tapestry5.ioc.services.ClasspathMatcher; +import org.apache.tapestry5.ioc.services.ClasspathScanner; import org.apache.tapestry5.services.ComponentLibraryInfo; import org.apache.tapestry5.services.ComponentLibraryInfoSource; import org.apache.tapestry5.services.LibraryMapping; import org.slf4j.Logger; +import org.w3c.dom.Document; /** * {@link ComponentLibraryInfoSource} implementation based on the pom.xml and pom.properties files @@ -33,36 +47,170 @@ public class MavenComponentLibraryInfoSource implements ComponentLibraryInfoSour { final private Logger logger; + + final private Set<String> pomPaths; + + final private Map<String, ComponentLibraryInfo> cache = new HashMap<String, ComponentLibraryInfo>(); + + final private Map<String, String> pomPathToRootUrl; + + final private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - public MavenComponentLibraryInfoSource(Logger logger) + public MavenComponentLibraryInfoSource(Logger logger, ClasspathScanner classpathScanner) { super(); this.logger = logger; + this.pomPaths = Collections.unmodifiableSet(findPomPaths(classpathScanner)); + pomPathToRootUrl = new WeakHashMap<String, String>(pomPaths.size()); } @Override public ComponentLibraryInfo find(LibraryMapping libraryMapping) { + ComponentLibraryInfo info = null; + if (cache.containsKey(libraryMapping.libraryName)) + { + info = cache.get(libraryMapping.libraryName); + } + else + { + final String pomPath = getPomPath(libraryMapping); + if (pomPath != null) + { + InputStream inputStream = getClass().getResourceAsStream("/" + pomPath); + info = parse(inputStream); + cache.put(libraryMapping.libraryName, info); + } + else + { + cache.put(libraryMapping.libraryName, null); + } + } + return info; + } + + /** + * @param inputStream + * @return + */ + private ComponentLibraryInfo parse(InputStream inputStream) + { + ComponentLibraryInfo info = null; + if (inputStream != null) + { + + Document document; + + try + { + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + document = documentBuilder.parse(inputStream); + } + catch (Exception e) + { + logger.warn("Exception while parsing pom.xml", e); + return null; + } + + info = new ComponentLibraryInfo(); + info.setGroupId(extractText(document, "(/project/groupId | /project/parent/groupId)[1]")); + info.setArtifactId(extractText(document, "/project/artifactId")); + info.setVersion(extractText(document, "/project/version")); + info.setName(extractText(document, "/project/name")); + info.setDescription(extractText(document, "/project/description")); + info.setDocumentationUrl(extractText(document, "/project/properties/documentationUrl")); + info.setHomepageUrl(extractText(document, "/project/properties/homepageUrl")); + info.setIssueTrackerUrl(extractText(document, "/project/issueManagement/url")); + info.setJavadocUrl(extractText(document, "/project/properties/javadocUrl")); + info.setSourceBrowseUrl(extractText(document, "/project/scm/url")); + info.setSourceRootUrl(extractText(document, "/project/scm/connection")); + String tags = extractText(document, "/project/properties/tags"); + if (tags != null && tags.length() > 0) + { + info.setTags(Arrays.asList(tags.split(","))); + } + + } -// final File root = getRoot(libraryMapping); -// -// System.out.println(root); + return info; - return null; } -// private File getRoot(LibraryMapping libraryMapping) -// { -// final String rootPackageConverted = libraryMapping.getRootPackage().replace('.', '/'); -// final URL rootPackageUrl = getClass().getClassLoader().getResource(rootPackageConverted); -// final String rootPath = "jar:" + rootPackageUrl.getPath().replace(rootPackageConverted, "") + "META-INF/maven/"; -// final URL rootUrl = getClass().getClassLoader().getResource(rootPath); -// return root; -// } + private String extractText(Document document, String xpathExpression) + { + XPath xpath = XPathFactory.newInstance().newXPath(); + String text; + try + { + XPathExpression expression = xpath.compile(xpathExpression); + text = (String) expression.evaluate(document, XPathConstants.STRING); + } + catch (XPathExpressionException e) + { + throw new RuntimeException(e); + } + return text; + } + + private String getPomPath(LibraryMapping libraryMapping) + { + final String rootPackageConverted = libraryMapping.getRootPackage().replace('.', '/'); + final URL rootPackageUrl = getClass().getClassLoader().getResource(rootPackageConverted); + String path = rootPackageUrl.toString(); + String url = null; + if (path.contains("!/")) + { + path = path.substring(0, path.indexOf("!/")); + } + for (String pomPath : pomPaths) + { + if (path.equals(getPomPathUrl(pomPath))) { + url = pomPath; + break; + } + } + return url; + } - private static InputStream open(String path) + private String getPomPathUrl(String pomPath) + { + String url = pomPathToRootUrl.get(pomPath); + if (url == null) + { + for (String path : pomPaths) + { + final URL resource = getClass().getResource("/" + path); + String resourcePath = null; + if (resource != null && resource.toString().contains("!/")) + { + resourcePath = resource.toString(); + resourcePath = resourcePath.substring(0, resourcePath.indexOf("!/")); + } + pomPathToRootUrl.put(path, resourcePath); + url = resourcePath; + } + } + return url; + } + + private static Set<String> findPomPaths(ClasspathScanner classpathScanner) { - return MavenComponentLibraryInfoSource.class.getClassLoader().getResourceAsStream(path); + final ClasspathMatcher classpathMatcher = new ClasspathMatcher() + { + @Override + public boolean matches(String packagePath, String fileName) + { + return fileName.equals("pom.xml"); + } + }; + try + { + return classpathScanner.scan("META-INF/maven", classpathMatcher); + } + catch (IOException e) + { + throw new RuntimeException("Exception while finding pom.xml files in the classpath", e); + } } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1062f53/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 195b617..bb71643 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 @@ -97,7 +97,9 @@ import org.slf4j.Logger; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; +import java.io.InputStream; import java.lang.annotation.Annotation; import java.math.BigDecimal; import java.math.BigInteger; @@ -2718,9 +2720,45 @@ public final class TapestryModule } @Contribute(ComponentLibraryInfoSource.class) - public static void addMavenComponentLibraryInfoSource(OrderedConfiguration<ComponentLibraryInfoSource> configuration) + public static void addBuiltInComponentLibraryInfoSources(OrderedConfiguration<ComponentLibraryInfoSource> configuration) { configuration.addInstance("Maven", MavenComponentLibraryInfoSource.class); + configuration.add("TapestryCore", new TapestryCoreComponentLibraryInfoSource()); + } + + private static final class TapestryCoreComponentLibraryInfoSource implements + ComponentLibraryInfoSource + { + @Override + public ComponentLibraryInfo find(LibraryMapping libraryMapping) + { + ComponentLibraryInfo info = null; + if (libraryMapping.libraryName.equals("core")) + { + + final InputStream inputStream = TapestryModule.class + .getResourceAsStream("/META-INF/gradle/org.apache.tapestry/tapestry-core/project.properties"); + + if (inputStream != null) + { + Properties properties = new Properties(); + try + { + properties.load(inputStream); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + info = new ComponentLibraryInfo(); + info.setArtifactId("tapestry-core"); + info.setGroupId("org.apache.tapestry"); + info.setVersion(properties.getProperty("version")); + info.setDescription("Tapestry 5 core component library"); + } + } + return info; + } } } http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b1062f53/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 index 92323af..e752e2a 100644 --- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java +++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentLibraryInfo.java @@ -14,6 +14,7 @@ package org.apache.tapestry5.services; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; /** @@ -35,7 +36,7 @@ public final class ComponentLibraryInfo implements Serializable private String name, description, homepageUrl, documentationUrl, sourceBrowseUrl, issueTrackerUrl, sourceRootUrl, javadocUrl, groupId, artifactId, version; - private List<String> tags; + private List<String> tags = new ArrayList<String>(); /** * Returns the actual name of the component library (not the identifier). @@ -199,6 +200,11 @@ public final class ComponentLibraryInfo implements Serializable { if (this.sourceRootUrl != null) throwExceptionIfAlreadySet("sourceRootUrl", sourceRootUrl); this.sourceRootUrl = sourceRootUrl; + if (sourceUrlResolver == null) + { + sourceUrlResolver = new DefaultSourceUrlResolver(); + sourceUrlResolver.setRootUrl(sourceRootUrl); + } } public void setJavadocUrl(String javadocUrl) @@ -329,13 +335,13 @@ public final class ComponentLibraryInfo implements Serializable * 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. + * Default {@link SourceUrlResolver} implementation. */ - public static class GitWebMavenSourceUrlResolver implements SourceUrlResolver + public static class DefaultSourceUrlResolver implements SourceUrlResolver { private String sourceRootUrl;
