blob: f8235d80c1ac3f5d6e9c4fc604e438dc0ddbd4fa [file] [log] [blame]
package org.apache.maven.model.transform.pull;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Objects;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
* An xml pull parser filter base implementation.
*
* @author Guillaume Nodet
* @since 4.0.0
*/
public class BufferingParser implements XmlPullParser
{
protected XmlPullParser xmlPullParser;
protected Deque<Event> events;
protected Event current;
protected boolean disabled;
@SuppressWarnings( "checkstyle:VisibilityModifier" )
public static class Event
{
public int event;
public String name;
public String prefix;
public String namespace;
public boolean empty;
public String text;
public Attribute[] attributes;
public Namespace[] namespaces;
}
@SuppressWarnings( "checkstyle:VisibilityModifier" )
public static class Namespace
{
public String prefix;
public String uri;
}
@SuppressWarnings( "checkstyle:VisibilityModifier" )
public static class Attribute
{
public String name;
public String prefix;
public String namespace;
public String type;
public String value;
public boolean isDefault;
}
public BufferingParser( XmlPullParser xmlPullParser )
{
this.xmlPullParser = xmlPullParser;
}
@Override
public void setFeature( String name, boolean state ) throws XmlPullParserException
{
xmlPullParser.setFeature( name, state );
}
@Override
public boolean getFeature( String name )
{
return xmlPullParser.getFeature( name );
}
@Override
public void setProperty( String name, Object value ) throws XmlPullParserException
{
xmlPullParser.setProperty( name, value );
}
@Override
public Object getProperty( String name )
{
return xmlPullParser.getProperty( name );
}
@Override
public void setInput( Reader in ) throws XmlPullParserException
{
xmlPullParser.setInput( in );
}
@Override
public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
{
xmlPullParser.setInput( inputStream, inputEncoding );
}
@Override
public String getInputEncoding()
{
return xmlPullParser.getInputEncoding();
}
@Override
public void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException
{
xmlPullParser.defineEntityReplacementText( entityName, replacementText );
}
@Override
public int getNamespaceCount( int depth ) throws XmlPullParserException
{
// TODO: if (current != null) throw new IllegalStateException("Not supported during events replay");
return xmlPullParser.getNamespaceCount( depth );
}
@Override
public String getNamespacePrefix( int pos ) throws XmlPullParserException
{
// TODO: if (current != null) throw new IllegalStateException("Not supported during events replay");
return xmlPullParser.getNamespacePrefix( pos );
}
@Override
public String getNamespaceUri( int pos ) throws XmlPullParserException
{
// TODO: if (current != null) throw new IllegalStateException("Not supported during events replay");
return xmlPullParser.getNamespaceUri( pos );
}
@Override
public String getNamespace( String prefix )
{
// TODO: if (current != null) throw new IllegalStateException("Not supported during events replay");
return xmlPullParser.getNamespace( prefix );
}
@Override
public int getDepth()
{
// TODO: if (current != null) throw new IllegalStateException("Not supported during events replay");
return xmlPullParser.getDepth();
}
@Override
public String getPositionDescription()
{
if ( current != null )
{
throw new IllegalStateException( "Not supported during events replay" );
}
return xmlPullParser.getPositionDescription();
}
@Override
public int getLineNumber()
{
if ( current != null )
{
throw new IllegalStateException( "Not supported during events replay" );
}
return xmlPullParser.getLineNumber();
}
@Override
public int getColumnNumber()
{
if ( current != null )
{
throw new IllegalStateException( "Not supported during events replay" );
}
return xmlPullParser.getColumnNumber();
}
@Override
public boolean isWhitespace() throws XmlPullParserException
{
if ( current != null )
{
if ( current.event == TEXT || current.event == CDSECT )
{
return current.text.matches( "[ \r\t\n]+" );
}
else if ( current.event == IGNORABLE_WHITESPACE )
{
return true;
}
else
{
throw new XmlPullParserException( "no content available to check for whitespaces" );
}
}
return xmlPullParser.isWhitespace();
}
@Override
public String getText()
{
return current != null ? current.text : xmlPullParser.getText();
}
@Override
public char[] getTextCharacters( int[] holderForStartAndLength )
{
if ( current != null )
{
throw new IllegalStateException( "Not supported during events replay" );
}
return xmlPullParser.getTextCharacters( holderForStartAndLength );
}
@Override
public String getNamespace()
{
return current != null ? current.namespace : xmlPullParser.getNamespace();
}
@Override
public String getName()
{
return current != null ? current.name : xmlPullParser.getName();
}
@Override
public String getPrefix()
{
return current != null ? current.prefix : xmlPullParser.getPrefix();
}
@Override
public boolean isEmptyElementTag() throws XmlPullParserException
{
return current != null ? current.empty : xmlPullParser.isEmptyElementTag();
}
@Override
public int getAttributeCount()
{
if ( current != null )
{
return current.attributes != null ? current.attributes.length : 0;
}
else
{
return xmlPullParser.getAttributeCount();
}
}
@Override
public String getAttributeNamespace( int index )
{
if ( current != null )
{
return current.attributes[index].namespace;
}
else
{
return xmlPullParser.getAttributeNamespace( index );
}
}
@Override
public String getAttributeName( int index )
{
if ( current != null )
{
return current.attributes[index].name;
}
else
{
return xmlPullParser.getAttributeName( index );
}
}
@Override
public String getAttributePrefix( int index )
{
if ( current != null )
{
return current.attributes[index].prefix;
}
else
{
return xmlPullParser.getAttributePrefix( index );
}
}
@Override
public String getAttributeType( int index )
{
if ( current != null )
{
return current.attributes[index].type;
}
else
{
return xmlPullParser.getAttributeType( index );
}
}
@Override
public boolean isAttributeDefault( int index )
{
if ( current != null )
{
return current.attributes[index].isDefault;
}
else
{
return xmlPullParser.isAttributeDefault( index );
}
}
@Override
public String getAttributeValue( int index )
{
if ( current != null )
{
return current.attributes[index].value;
}
else
{
return xmlPullParser.getAttributeValue( index );
}
}
@Override
public String getAttributeValue( String namespace, String name )
{
if ( current != null )
{
if ( current.attributes != null )
{
for ( Attribute attr : current.attributes )
{
if ( Objects.equals( namespace, attr.namespace )
&& Objects.equals( name, attr.name ) )
{
return attr.value;
}
}
}
return null;
}
else
{
return xmlPullParser.getAttributeValue( namespace, name );
}
}
@Override
public void require( int type, String namespace, String name ) throws XmlPullParserException, IOException
{
if ( current != null )
{
throw new IllegalStateException( "Not supported during events replay" );
}
xmlPullParser.require( type, namespace, name );
}
@Override
public int getEventType() throws XmlPullParserException
{
return current != null ? current.event : xmlPullParser.getEventType();
}
@Override
public int next() throws XmlPullParserException, IOException
{
while ( true )
{
if ( events != null && !events.isEmpty() )
{
current = events.removeFirst();
return current.event;
}
else
{
current = null;
}
if ( getEventType() == END_DOCUMENT )
{
throw new XmlPullParserException( "already reached end of XML input", this, null );
}
int currentEvent = xmlPullParser.next();
if ( disabled || accept() )
{
return currentEvent;
}
}
}
@Override
public int nextToken() throws XmlPullParserException, IOException
{
while ( true )
{
if ( events != null && !events.isEmpty() )
{
current = events.removeFirst();
return current.event;
}
else
{
current = null;
}
if ( getEventType() == END_DOCUMENT )
{
throw new XmlPullParserException( "already reached end of XML input", this, null );
}
int currentEvent = xmlPullParser.nextToken();
if ( accept() )
{
return currentEvent;
}
}
}
@Override
public int nextTag() throws XmlPullParserException, IOException
{
int eventType = next();
if ( eventType == TEXT && isWhitespace() )
{ // skip whitespace
eventType = next();
}
if ( eventType != START_TAG && eventType != END_TAG )
{
throw new XmlPullParserException( "expected START_TAG or END_TAG not "
+ TYPES[getEventType()], this, null );
}
return eventType;
}
@Override
public String nextText() throws XmlPullParserException, IOException
{
int eventType = getEventType();
if ( eventType != START_TAG )
{
throw new XmlPullParserException( "parser must be on START_TAG to read next text", this, null );
}
eventType = next();
if ( eventType == TEXT )
{
final String result = getText();
eventType = next();
if ( eventType != END_TAG )
{
throw new XmlPullParserException( "TEXT must be immediately followed by END_TAG and not "
+ TYPES[getEventType()], this, null );
}
return result;
}
else if ( eventType == END_TAG )
{
return "";
}
else
{
throw new XmlPullParserException( "parser must be on START_TAG or TEXT to read text", this, null );
}
}
protected Event bufferEvent() throws XmlPullParserException
{
Event event = new Event();
XmlPullParser pp = xmlPullParser;
event.event = xmlPullParser.getEventType();
switch ( event.event )
{
case START_DOCUMENT:
case END_DOCUMENT:
break;
case START_TAG:
event.name = pp.getName();
event.namespace = pp.getNamespace();
event.prefix = pp.getPrefix();
event.empty = pp.isEmptyElementTag();
event.text = pp.getText();
break;
case END_TAG:
event.name = pp.getName();
event.namespace = pp.getNamespace();
event.prefix = pp.getPrefix();
event.text = pp.getText();
break;
case TEXT:
case COMMENT:
case IGNORABLE_WHITESPACE:
event.text = pp.getText();
break;
default:
break;
}
return event;
}
protected void pushEvent( Event event )
{
if ( events == null )
{
events = new ArrayDeque<>();
}
events.add( event );
}
protected boolean accept() throws XmlPullParserException, IOException
{
return true;
}
protected void enable()
{
disabled = false;
}
protected void disable()
{
if ( events != null && !events.isEmpty() )
{
throw new IllegalStateException( "Can not disable filter while processing" );
}
disabled = true;
if ( xmlPullParser instanceof BufferingParser )
{
( ( BufferingParser ) xmlPullParser ).disable();
}
}
protected static String nullSafeAppend( String originalValue, String charSegment )
{
if ( originalValue == null )
{
return charSegment;
}
else
{
return originalValue + charSegment;
}
}
}