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  import org.apache.maven.usability.plugin.io.xpp3.ParamdocXpp3Reader;
33  import org.codehaus.plexus.util.ReaderFactory;
34  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
35  
36  /**
37   * ExpressionDocumenter
38   */
39  public class ExpressionDocumenter {
40  
41      private static final String[] EXPRESSION_ROOTS = {"project", "settings", "session", "plugin", "rootless"};
42  
43      private static final String EXPRESSION_DOCO_ROOTPATH = "META-INF/maven/plugin-expressions/";
44  
45      private static Map<String, Expression> expressionDocumentation;
46  
47      public static Map<String, Expression> load() throws ExpressionDocumentationException {
48          if (expressionDocumentation == null) {
49              expressionDocumentation = new HashMap<>();
50  
51              ClassLoader docLoader = initializeDocLoader();
52  
53              for (String root : EXPRESSION_ROOTS) {
54                  try (InputStream docStream =
55                          docLoader.getResourceAsStream(EXPRESSION_DOCO_ROOTPATH + root + ".paramdoc.xml")) {
56                      if (docStream != null) {
57                          Map<String, Expression> doco = parseExpressionDocumentation(docStream);
58  
59                          expressionDocumentation.putAll(doco);
60                      }
61                  } catch (IOException e) {
62                      throw new ExpressionDocumentationException(
63                              "Failed to read documentation for expression root: " + root, e);
64                  } catch (XmlPullParserException e) {
65                      throw new ExpressionDocumentationException(
66                              "Failed to parse documentation for expression root: " + root, e);
67                  }
68              }
69          }
70  
71          return expressionDocumentation;
72      }
73  
74      /**
75       * <expressions>
76       * <expression>
77       * <syntax>project.distributionManagementArtifactRepository</syntax>
78       * <origin><![CDATA[
79       * <distributionManagement>
80       * <repository>
81       * <id>some-repo</id>
82       * <url>scp://host/path</url>
83       * </repository>
84       * <snapshotRepository>
85       * <id>some-snap-repo</id>
86       * <url>scp://host/snapshot-path</url>
87       * </snapshotRepository>
88       * </distributionManagement>
89       * ]]></origin>
90       * <usage><![CDATA[
91       * The repositories onto which artifacts should be deployed.
92       * One is for releases, the other for snapshots.
93       * ]]></usage>
94       * </expression>
95       * <expressions>
96       *
97       * @throws IOException
98       * @throws XmlPullParserException
99       */
100     private static Map<String, Expression> parseExpressionDocumentation(InputStream docStream)
101             throws IOException, XmlPullParserException {
102         Reader reader = new BufferedReader(ReaderFactory.newXmlReader(docStream));
103 
104         ParamdocXpp3Reader paramdocReader = new ParamdocXpp3Reader();
105 
106         ExpressionDocumentation documentation = paramdocReader.read(reader, true);
107 
108         List<Expression> expressions = documentation.getExpressions();
109 
110         Map<String, Expression> bySyntax = new HashMap<>();
111 
112         if (expressions != null && !expressions.isEmpty()) {
113             for (Expression expression : expressions) {
114                 bySyntax.put(expression.getSyntax(), expression);
115             }
116         }
117 
118         return bySyntax;
119     }
120 
121     private static ClassLoader initializeDocLoader() throws ExpressionDocumentationException {
122         String myResourcePath = ExpressionDocumenter.class.getName().replace('.', '/') + ".class";
123 
124         URL myResource = ExpressionDocumenter.class.getClassLoader().getResource(myResourcePath);
125 
126         assert myResource != null : "The resource is this class itself loaded by its own classloader and must exist";
127 
128         String myClasspathEntry = myResource.getPath();
129 
130         myClasspathEntry = myClasspathEntry.substring(0, myClasspathEntry.length() - (myResourcePath.length() + 2));
131 
132         if (myClasspathEntry.startsWith("file:")) {
133             myClasspathEntry = myClasspathEntry.substring("file:".length());
134         }
135 
136         URL docResource;
137         try {
138             docResource = new File(myClasspathEntry).toURL();
139         } catch (MalformedURLException e) {
140             throw new ExpressionDocumentationException(
141                     "Cannot construct expression documentation classpath" + " resource base.", e);
142         }
143 
144         return new URLClassLoader(new URL[] {docResource});
145     }
146 }