1 package org.apache.maven.plugin;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
106
107
108
109
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
182
183
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 }