1 package org.apache.maven.scm.provider.accurev.cli;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.io.Writer;
25 import java.nio.channels.Channels;
26 import java.nio.channels.Pipe;
27 import java.nio.channels.Pipe.SinkChannel;
28 import java.nio.channels.Pipe.SourceChannel;
29 import java.nio.charset.Charset;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35
36 import org.apache.maven.scm.log.ScmLogger;
37 import org.codehaus.plexus.util.cli.StreamConsumer;
38 import org.codehaus.plexus.util.xml.pull.MXParser;
39 import org.codehaus.plexus.util.xml.pull.XmlPullParser;
40 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
41
42
43
44
45
46
47 public abstract class XppStreamConsumer
48 extends Thread
49 implements StreamConsumer
50
51 {
52 public ScmLogger getLogger()
53 {
54 return logger;
55 }
56
57 private Writer writer;
58
59 private XmlPullParser parser = new MXParser();
60
61 private volatile boolean complete = false;
62
63 private ScmLogger logger;
64
65 private int lineCount = 0;
66
67 private Reader reader;
68
69 public XppStreamConsumer( ScmLogger logger )
70 {
71
72 super();
73 this.logger = logger;
74 try
75 {
76 Pipe p = Pipe.open();
77 SinkChannel sink = p.sink();
78 SourceChannel source = p.source();
79 writer = Channels.newWriter( sink, Charset.defaultCharset().name() );
80 reader = Channels.newReader( source, Charset.defaultCharset().name() );
81 parser.setInput( reader );
82
83 }
84 catch ( Exception e )
85 {
86 logger.error( "Exception initialising pipe", e );
87 }
88
89 }
90
91 public final void consumeLine( String line )
92 {
93
94
95 try
96 {
97 writer.append( line );
98 if ( lineCount == 0 )
99 {
100 this.start();
101 }
102 lineCount++;
103 writer.flush();
104 }
105 catch ( IOException e )
106 {
107 throw new RuntimeException( "error pumping line to pipe", e );
108 }
109
110 }
111
112 @Override
113 public void run()
114 {
115
116 try
117 {
118 parse( parser );
119 }
120 catch ( Exception e )
121 {
122 caughtParseException( e );
123 }
124 finally
125 {
126 synchronized ( this )
127 {
128
129 try
130 {
131 reader.close();
132 }
133 catch ( IOException e )
134 {
135 getLogger().warn( "Error closing pipe reader", e );
136 }
137
138 complete = true;
139 this.notifyAll();
140 }
141 }
142 }
143
144 protected void caughtParseException( Exception e )
145 {
146 logger.warn( "Exception parsing input", e );
147
148 }
149
150 protected void parse( XmlPullParser p )
151 throws XmlPullParserException, IOException
152 {
153 List<String> tagPath = new ArrayList<String>();
154 int eventType = p.getEventType();
155 if ( logger.isDebugEnabled() )
156 {
157 logger.debug( "Event " + eventType );
158 }
159
160 while ( eventType != XmlPullParser.END_DOCUMENT )
161 {
162 int lastIndex = tagPath.size() - 1;
163 String tagName;
164 switch ( eventType )
165 {
166 case XmlPullParser.START_DOCUMENT:
167
168 break;
169
170 case XmlPullParser.START_TAG:
171 tagName = p.getName();
172 if ( tagName != null )
173 {
174 tagPath.add( tagName );
175 int attributeCount = p.getAttributeCount();
176 Map<String, String> attributes = new HashMap<String, String>( Math.max( attributeCount, 0 ) );
177 for ( int i = 0; i < attributeCount; i++ )
178 {
179 attributes.put( p.getAttributeName( i ), p.getAttributeValue( i ) );
180 }
181
182 startTag( tagPath, attributes );
183 }
184 break;
185
186 case XmlPullParser.TEXT:
187 if ( !p.isWhitespace() )
188 {
189 String text = p.getText();
190 text( tagPath, text );
191 }
192 break;
193
194 case XmlPullParser.END_TAG:
195 tagName = p.getName();
196
197 if ( lastIndex < 0 || !tagName.equals( tagPath.get( lastIndex ) ) )
198 {
199 logger.warn( "Bad tag path: " + Arrays.toString( tagPath.toArray() ) );
200 }
201 endTag( tagPath );
202 tagPath.remove( lastIndex );
203 break;
204
205 default:
206 logger.warn( "Unexpected event type " + eventType );
207 break;
208 }
209 p.next();
210 eventType = p.getEventType();
211 if ( logger.isDebugEnabled() )
212 {
213 logger.debug( "Event " + eventType );
214 }
215 }
216 }
217
218
219
220
221 public void waitComplete()
222 {
223 Thread.yield();
224 try
225 {
226 writer.close();
227 }
228 catch ( IOException e1 )
229 {
230 logger.warn( "Exception flushing output", e1 );
231 }
232
233 while ( !isComplete() )
234 {
235
236 synchronized ( this )
237 {
238 try
239 {
240 if ( !isComplete() )
241 {
242 this.wait( 1000 );
243 }
244 }
245 catch ( Exception e )
246 {
247 logger.warn( e );
248
249 }
250 }
251 }
252
253 }
254
255 private boolean isComplete()
256 {
257 return complete || lineCount == 0;
258 }
259
260 protected void startTag( List<String> tagPath, Map<String, String> attributes )
261 {
262 if ( logger.isDebugEnabled() )
263 {
264 String tagName = getTagName( tagPath );
265 logger.debug( "START_TAG: " + tagName + "(" + attributes.size() + ")" );
266 }
267 }
268
269 protected static String getTagName( List<String> tagPath )
270 {
271 return tagPath.size() == 0 ? null : tagPath.get( tagPath.size() - 1 );
272
273 }
274
275 protected void endTag( List<String> tagPath )
276 {
277 if ( logger.isDebugEnabled() )
278 {
279 logger.debug( "END_TAG: " + getTagName( tagPath ) );
280 }
281
282 }
283
284 protected void text( List<String> tagPath, String text )
285 {
286 if ( logger.isDebugEnabled() )
287 {
288 logger.debug( "TEXT: " + text );
289 }
290
291 }
292
293 }