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.IOUtil;
024import org.codehaus.plexus.util.ReaderFactory;
025import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
026
027import java.io.BufferedReader;
028import java.io.File;
029import java.io.IOException;
030import java.io.InputStream;
031import java.io.Reader;
032import java.net.MalformedURLException;
033import java.net.URL;
034import java.net.URLClassLoader;
035import java.util.HashMap;
036import java.util.List;
037import java.util.Map;
038
039public class ExpressionDocumenter
040{
041
042    private static final String[] EXPRESSION_ROOTS = { "project", "settings", "session", "plugin", "rootless" };
043
044    private static final String EXPRESSION_DOCO_ROOTPATH = "META-INF/maven/plugin-expressions/";
045
046    private static Map expressionDocumentation;
047
048    public static Map load()
049        throws ExpressionDocumentationException
050    {
051        if ( expressionDocumentation == null )
052        {
053            expressionDocumentation = new HashMap();
054
055            ClassLoader docLoader = initializeDocLoader();
056
057            for ( String EXPRESSION_ROOT : EXPRESSION_ROOTS )
058            {
059                InputStream docStream = null;
060                try
061                {
062                    docStream =
063                        docLoader.getResourceAsStream( EXPRESSION_DOCO_ROOTPATH + EXPRESSION_ROOT + ".paramdoc.xml" );
064
065                    if ( docStream != null )
066                    {
067                        Map doco = parseExpressionDocumentation( docStream );
068
069                        expressionDocumentation.putAll( doco );
070                    }
071                }
072                catch ( IOException e )
073                {
074                    throw new ExpressionDocumentationException(
075                        "Failed to read documentation for expression root: " + EXPRESSION_ROOT, e );
076                }
077                catch ( XmlPullParserException e )
078                {
079                    throw new ExpressionDocumentationException(
080                        "Failed to parse documentation for expression root: " + EXPRESSION_ROOT, e );
081                }
082                finally
083                {
084                    IOUtil.close( docStream );
085                }
086            }
087        }
088
089        return expressionDocumentation;
090    }
091
092    /**
093     * <expressions>
094     *   <expression>
095     *     <syntax>project.distributionManagementArtifactRepository</syntax>
096     *     <origin><![CDATA[
097     *   <distributionManagement>
098     *     <repository>
099     *       <id>some-repo</id>
100     *       <url>scp://host/path</url>
101     *     </repository>
102     *     <snapshotRepository>
103     *       <id>some-snap-repo</id>
104     *       <url>scp://host/snapshot-path</url>
105     *     </snapshotRepository>
106     *   </distributionManagement>
107     *   ]]></origin>
108     *     <usage><![CDATA[
109     *   The repositories onto which artifacts should be deployed.
110     *   One is for releases, the other for snapshots.
111     *   ]]></usage>
112     *   </expression>
113     * <expressions>
114     * @throws IOException
115     * @throws XmlPullParserException
116     */
117    private static Map parseExpressionDocumentation( InputStream docStream )
118        throws IOException, XmlPullParserException
119    {
120        Reader reader = new BufferedReader( ReaderFactory.newXmlReader( docStream ) );
121
122        ParamdocXpp3Reader paramdocReader = new ParamdocXpp3Reader();
123
124        ExpressionDocumentation documentation = paramdocReader.read( reader, true );
125
126        List expressions = documentation.getExpressions();
127
128        Map bySyntax = new HashMap();
129
130        if ( expressions != null && !expressions.isEmpty() )
131        {
132            for ( Object expression : expressions )
133            {
134                Expression expr = (Expression) expression;
135
136                bySyntax.put( expr.getSyntax(), expr );
137            }
138        }
139
140        return bySyntax;
141    }
142
143    private static ClassLoader initializeDocLoader()
144        throws ExpressionDocumentationException
145    {
146        String myResourcePath = ExpressionDocumenter.class.getName().replace( '.', '/' ) + ".class";
147
148        URL myResource = ExpressionDocumenter.class.getClassLoader().getResource( myResourcePath );
149
150        assert myResource != null : "The resource is this class itself loaded by its own classloader and must exist";
151
152        String myClasspathEntry = myResource.getPath();
153
154        myClasspathEntry = myClasspathEntry.substring( 0, myClasspathEntry.length() - ( myResourcePath.length() + 2 ) );
155
156        if ( myClasspathEntry.startsWith( "file:" ) )
157        {
158            myClasspathEntry = myClasspathEntry.substring( "file:".length() );
159        }
160
161        URL docResource;
162        try
163        {
164            docResource = new File( myClasspathEntry ).toURL();
165        }
166        catch ( MalformedURLException e )
167        {
168            throw new ExpressionDocumentationException( "Cannot construct expression documentation classpath"
169                + " resource base.", e );
170        }
171
172        return new URLClassLoader( new URL[] { docResource } );
173    }
174
175}