001package org.apache.maven.usability.plugin; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.maven.usability.plugin.io.xpp3.ParamdocXpp3Reader; 023import org.codehaus.plexus.util.ReaderFactory; 024import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 025 026import java.io.BufferedReader; 027import java.io.File; 028import java.io.IOException; 029import java.io.InputStream; 030import java.io.Reader; 031import java.net.MalformedURLException; 032import java.net.URL; 033import java.net.URLClassLoader; 034import java.util.HashMap; 035import java.util.List; 036import java.util.Map; 037 038public class ExpressionDocumenter 039{ 040 041 private static final String[] EXPRESSION_ROOTS = { "project", "settings", "session", "plugin", "rootless" }; 042 043 private static final String EXPRESSION_DOCO_ROOTPATH = "META-INF/maven/plugin-expressions/"; 044 045 private static Map<String, Expression> expressionDocumentation; 046 047 public static Map<String, Expression> load() 048 throws ExpressionDocumentationException 049 { 050 if ( expressionDocumentation == null ) 051 { 052 expressionDocumentation = new HashMap<>(); 053 054 ClassLoader docLoader = initializeDocLoader(); 055 056 for ( String EXPRESSION_ROOT : EXPRESSION_ROOTS ) 057 { 058 try ( InputStream docStream = docLoader.getResourceAsStream( 059 EXPRESSION_DOCO_ROOTPATH + EXPRESSION_ROOT + ".paramdoc.xml" ) ) 060 { 061 if ( docStream != null ) 062 { 063 Map<String, Expression> doco = parseExpressionDocumentation( docStream ); 064 065 expressionDocumentation.putAll( doco ); 066 } 067 } 068 catch ( IOException e ) 069 { 070 throw new ExpressionDocumentationException( 071 "Failed to read documentation for expression root: " + EXPRESSION_ROOT, e ); 072 } 073 catch ( XmlPullParserException e ) 074 { 075 throw new ExpressionDocumentationException( 076 "Failed to parse documentation for expression root: " + EXPRESSION_ROOT, e ); 077 } 078 079 } 080 } 081 082 return expressionDocumentation; 083 } 084 085 /** 086 * <expressions> 087 * <expression> 088 * <syntax>project.distributionManagementArtifactRepository</syntax> 089 * <origin><![CDATA[ 090 * <distributionManagement> 091 * <repository> 092 * <id>some-repo</id> 093 * <url>scp://host/path</url> 094 * </repository> 095 * <snapshotRepository> 096 * <id>some-snap-repo</id> 097 * <url>scp://host/snapshot-path</url> 098 * </snapshotRepository> 099 * </distributionManagement> 100 * ]]></origin> 101 * <usage><![CDATA[ 102 * The repositories onto which artifacts should be deployed. 103 * One is for releases, the other for snapshots. 104 * ]]></usage> 105 * </expression> 106 * <expressions> 107 * 108 * @throws IOException 109 * @throws XmlPullParserException 110 */ 111 private static Map<String, Expression> parseExpressionDocumentation( InputStream docStream ) 112 throws IOException, XmlPullParserException 113 { 114 Reader reader = new BufferedReader( ReaderFactory.newXmlReader( docStream ) ); 115 116 ParamdocXpp3Reader paramdocReader = new ParamdocXpp3Reader(); 117 118 ExpressionDocumentation documentation = paramdocReader.read( reader, true ); 119 120 List<Expression> expressions = documentation.getExpressions(); 121 122 Map<String, Expression> bySyntax = new HashMap<>(); 123 124 if ( expressions != null && !expressions.isEmpty() ) 125 { 126 for ( Expression expression : expressions ) 127 { 128 bySyntax.put( expression.getSyntax(), expression ); 129 } 130 } 131 132 return bySyntax; 133 } 134 135 private static ClassLoader initializeDocLoader() 136 throws ExpressionDocumentationException 137 { 138 String myResourcePath = ExpressionDocumenter.class.getName().replace( '.', '/' ) + ".class"; 139 140 URL myResource = ExpressionDocumenter.class.getClassLoader().getResource( myResourcePath ); 141 142 assert myResource != null : "The resource is this class itself loaded by its own classloader and must exist"; 143 144 String myClasspathEntry = myResource.getPath(); 145 146 myClasspathEntry = myClasspathEntry.substring( 0, myClasspathEntry.length() - ( myResourcePath.length() + 2 ) ); 147 148 if ( myClasspathEntry.startsWith( "file:" ) ) 149 { 150 myClasspathEntry = myClasspathEntry.substring( "file:".length() ); 151 } 152 153 URL docResource; 154 try 155 { 156 docResource = new File( myClasspathEntry ).toURL(); 157 } 158 catch ( MalformedURLException e ) 159 { 160 throw new ExpressionDocumentationException( 161 "Cannot construct expression documentation classpath" + " resource base.", e ); 162 } 163 164 return new URLClassLoader( new URL[]{ docResource } ); 165 } 166 167}