View Javadoc

1   package org.apache.maven.plugin;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.util.HashSet;
25  import java.util.Set;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.maven.MavenException;
30  import org.codehaus.plexus.util.StringUtils;
31  import org.xml.sax.Attributes;
32  import org.xml.sax.SAXParseException;
33  import org.xml.sax.helpers.DefaultHandler;
34  
35  /**
36   * Class to parse plugin XML scripts to find goals and tag libraries.
37   *
38   * @author Brett Porter <a href="mailto:brett@apache.org">brett@apache.org</a>
39   */
40  final class PluginScriptParser
41      extends DefaultHandler
42  {
43      /** The plugin housing. */
44      private final JellyScriptHousing jellyScriptHousing;
45  
46      /** The goal mapper. */
47      private final PluginDefinitionHandler handler;
48  
49      /** Logging instance. */
50      private static final Log LOGGER = LogFactory.getLog( PluginScriptParser.class );
51  
52      /** Storage of defined dynamic tag libraries. */
53      private final Set dynaTagLibDecls = new HashSet();
54  
55      /**
56       * Constructor.
57       */
58      PluginScriptParser( PluginDefinitionHandler handler, JellyScriptHousing jellyScriptHousing )
59      {
60          this.handler = handler;
61          this.jellyScriptHousing = jellyScriptHousing;
62      }
63  
64      /**
65       * We are looking for namespace declarations like the following:
66       *
67       * xmlns:doc="doc"
68       *
69       * Here we know that the given plugin.jelly script (or any jelly script used
70       * within Maven) has a dependency on the dyna tag lib named 'doc'. We need to
71       * make sure that this dyna tag lib is ready for use when the plugin.jelly
72       * script is run.
73       *
74       * @param prefix Prefix to be used in the jelly script.
75       * @param uri Uri of the dyna tag lib.
76       * @todo check this works for multiple plugin versions
77       */
78      public void startPrefixMapping( String prefix, String uri )
79      {
80          if ( !"".equals( prefix ) && !uri.startsWith( "jelly:" ) && !uri.startsWith( "dummy" ) && !"".equals( uri ) )
81          {
82              dynaTagLibDecls.add( uri );
83              handler.addPluginDynaTagDep( jellyScriptHousing, uri );
84  
85              if ( LOGGER.isDebugEnabled() )
86              {
87                  LOGGER.debug( "Caching Taglib Uri --> " + uri );
88              }
89          }
90      }
91  
92      /**
93       * Handles opening elements of the xml file.
94       */
95      public void startElement( String uri, String localName, String rawName, Attributes attributes )
96      {
97          if ( "jelly:core".equals( uri ) && "import".equals( localName ) )
98          {
99              String importUri = attributes.getValue( "uri" );
100             if ( importUri == null )
101             {
102                 importUri = attributes.getValue( "file" );
103             }
104             /*
105             if ( importUri != null )
106             {
107                 // We -could- evaluate this as an expression, but the only thing set at this point is ${basedir}
108                 // and some expressions will spit out exceptions (eg ${context.getVariable('blah')})
109                 // TODO: maybe sub in basedir, plugin.resources and plugin.dir?
110             }
111             */
112 
113             if ( importUri == null )
114             {
115                 LOGGER.debug( rawName + " does not have a uri in " + jellyScriptHousing.getName() );
116             }
117             else
118             {
119                 LOGGER.debug( rawName + " importing from uri " + importUri );
120                 FileInputStream fis = null;
121                 try
122                 {
123                     File f = new File( importUri );
124                     fis = new FileInputStream( new File( importUri ) );
125                     jellyScriptHousing.parse( handler, f.getAbsolutePath(), fis );
126                 }
127                 catch ( MavenException e )
128                 {
129                     LOGGER.warn( "Error parsing content from uri " + importUri, e );
130                 }
131                 catch ( IOException e )
132                 {
133                     LOGGER.debug( "Skipping: error reading from uri " + importUri );
134                 }
135                 finally
136                 {
137                     if ( fis != null )
138                     {
139                         try
140                         {
141                             fis.close();
142                         }
143                         catch ( IOException e )
144                         {
145                             LOGGER.debug( "WARNING: Cannot close stream!", e );
146                         }
147                     }
148                 }
149             }
150         }
151         if ( "project".equals( rawName ) )
152         {
153             String defaultGoal = attributes.getValue( "default" );
154 
155             if ( defaultGoal != null )
156             {
157                 LOGGER
158                     .warn( "DEPRECATED: the default goal should be specified in the <build> section of project.xml instead of maven.xml" );
159                 handler.setDefaultGoalName( defaultGoal );
160             }
161         }
162         else if ( "goal".equals( rawName ) )
163         {
164             String name = StringUtils.deleteWhitespace( attributes.getValue( "name" ) );
165             String prereqs = attributes.getValue( "prereqs" );
166             String description = attributes.getValue( "description" );
167 
168             handler.addGoal( name, prereqs, description, jellyScriptHousing );
169         }
170         else if ( "preGoal".equals( rawName ) )
171         {
172             String name = attributes.getValue( "name" );
173             handler.addPreGoal( name, jellyScriptHousing );
174         }
175         else if ( "postGoal".equals( rawName ) )
176         {
177             String name = attributes.getValue( "name" );
178             handler.addPostGoal( name, jellyScriptHousing );
179         }
180         /*
181         else if ( "attainGoal".equals( rawName ) )
182         {
183             // Use lazy version
184         }
185         */
186         else if ( "taglib".equals( localName ) && "jelly:define".equals( uri ) )
187         {
188             String tagLibUri = attributes.getValue( "uri" );
189 
190             if ( dynaTagLibDecls.contains( tagLibUri ) )
191             {
192                 handler.removePluginDynaTagDep( jellyScriptHousing, tagLibUri );
193             }
194             handler.addDynaTagLib( tagLibUri, jellyScriptHousing );
195         }
196     }
197 
198     /**
199      * Warning callback.
200      *
201      * @param spe The parse exception that caused the callback to be invoked.
202      */
203     public void warning( SAXParseException spe )
204     {
205         printParseError( "Warning", spe );
206     }
207 
208     /**
209      * Error callback.
210      *
211      * @param spe The parse exception that caused the callback to be invoked.
212      */
213     public void error( SAXParseException spe )
214     {
215         printParseError( "Error", spe );
216     }
217 
218     /**
219      * Fatal error callback.
220      *
221      * @param spe The parse exception that caused the callback to be invoked.
222      */
223     public void fatalError( SAXParseException spe )
224     {
225         printParseError( "Fatal Error", spe );
226     }
227 
228     /**
229      * Print parse error to Sytem.err
230      */
231     private void printParseError( String type, SAXParseException spe )
232     {
233         LOGGER
234             .error( type + " [line " + spe.getLineNumber() + ", row " + spe.getColumnNumber() + "]: "
235                 + spe.getMessage() );
236     }
237 }