View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.usability.plugin;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Reader;
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.net.URLClassLoader;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.apache.maven.usability.plugin.io.xpp3.ParamdocXpp3Reader;
34  import org.codehaus.plexus.util.ReaderFactory;
35  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
36  
37  /**
38   * ExpressionDocumenter
39   */
40  public class ExpressionDocumenter {
41  
42      private static final String[] EXPRESSION_ROOTS = {"project", "settings", "session", "plugin", "rootless"};
43  
44      private static final String EXPRESSION_DOCO_ROOTPATH = "META-INF/maven/plugin-expressions/";
45  
46      private static Map<String, Expression> expressionDocumentation;
47  
48      public static Map<String, Expression> load() throws ExpressionDocumentationException {
49          if (expressionDocumentation == null) {
50              expressionDocumentation = new HashMap<>();
51  
52              ClassLoader docLoader = initializeDocLoader();
53  
54              for (String root : EXPRESSION_ROOTS) {
55                  try (InputStream docStream =
56                          docLoader.getResourceAsStream(EXPRESSION_DOCO_ROOTPATH + root + ".paramdoc.xml")) {
57                      if (docStream != null) {
58                          Map<String, Expression> doco = parseExpressionDocumentation(docStream);
59  
60                          expressionDocumentation.putAll(doco);
61                      }
62                  } catch (IOException e) {
63                      throw new ExpressionDocumentationException(
64                              "Failed to read documentation for expression root: " + root, e);
65                  } catch (XmlPullParserException e) {
66                      throw new ExpressionDocumentationException(
67                              "Failed to parse documentation for expression root: " + root, e);
68                  }
69              }
70          }
71  
72          return expressionDocumentation;
73      }
74  
75      /**
76       * <expressions>
77       * <expression>
78       * <syntax>project.distributionManagementArtifactRepository</syntax>
79       * <origin><![CDATA[
80       * <distributionManagement>
81       * <repository>
82       * <id>some-repo</id>
83       * <url>scp://host/path</url>
84       * </repository>
85       * <snapshotRepository>
86       * <id>some-snap-repo</id>
87       * <url>scp://host/snapshot-path</url>
88       * </snapshotRepository>
89       * </distributionManagement>
90       * ]]></origin>
91       * <usage><![CDATA[
92       * The repositories onto which artifacts should be deployed.
93       * One is for releases, the other for snapshots.
94       * ]]></usage>
95       * </expression>
96       * <expressions>
97       *
98       * @throws IOException
99       * @throws XmlPullParserException
100      */
101     private static Map<String, Expression> parseExpressionDocumentation(InputStream docStream)
102             throws IOException, XmlPullParserException {
103         Reader reader = new BufferedReader(ReaderFactory.newXmlReader(docStream));
104 
105         ParamdocXpp3Reader paramdocReader = new ParamdocXpp3Reader();
106 
107         ExpressionDocumentation documentation = paramdocReader.read(reader, true);
108 
109         List<Expression> expressions = documentation.getExpressions();
110 
111         Map<String, Expression> bySyntax = new HashMap<>();
112 
113         if (expressions != null && !expressions.isEmpty()) {
114             for (Expression expression : expressions) {
115                 bySyntax.put(expression.getSyntax(), expression);
116             }
117         }
118 
119         return bySyntax;
120     }
121 
122     private static ClassLoader initializeDocLoader() throws ExpressionDocumentationException {
123         String myResourcePath = ExpressionDocumenter.class.getName().replace('.', '/') + ".class";
124 
125         URL myResource = ExpressionDocumenter.class.getClassLoader().getResource(myResourcePath);
126 
127         assert myResource != null : "The resource is this class itself loaded by its own classloader and must exist";
128 
129         String myClasspathEntry = myResource.getPath();
130 
131         myClasspathEntry = myClasspathEntry.substring(0, myClasspathEntry.length() - (myResourcePath.length() + 2));
132 
133         if (myClasspathEntry.startsWith("file:")) {
134             myClasspathEntry = myClasspathEntry.substring("file:".length());
135         }
136 
137         URL docResource;
138         try {
139             docResource = new File(myClasspathEntry).toURL();
140         } catch (MalformedURLException e) {
141             throw new ExpressionDocumentationException(
142                     "Cannot construct expression documentation classpath" + " resource base.", e);
143         }
144 
145         return new URLClassLoader(new URL[] {docResource});
146     }
147 }