Fixing entity reader.

git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/branches/archiva-jpox-database-refactor@525280 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Joakim Erdfelt 2007-04-03 21:17:42 +00:00
parent 74cb10586c
commit 936fe55580
7 changed files with 405 additions and 31 deletions

View File

@ -298,7 +298,25 @@ public class LatinEntities
public static String resolveEntity( String entity )
{
String result = (String) defaultEntityMap.get( entity );
if ( entity == null )
{
// Invalid. null.
return entity;
}
if ( entity.trim().length() <= 0 )
{
// Invalid. empty.
return entity;
}
if ( !( entity.charAt( 0 ) == '&' ) && ( entity.charAt( entity.length() ) == ';' ) )
{
// Invalid, not an entity.
return entity;
}
String result = (String) defaultEntityMap.get( entity.substring( 1, entity.length() - 1 ) );
if ( result == null )
{
return entity;

View File

@ -21,11 +21,12 @@ package org.apache.maven.archiva.xml;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* LatinEntityResolutionReader
* LatinEntityResolutionReader - Read a Character Stream.
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
* @version $Id$
@ -33,23 +34,152 @@ import java.io.Reader;
public class LatinEntityResolutionReader
extends Reader
{
private PushbackReader originalReader;
private BufferedReader originalReader;
private char leftover[];
private Pattern entityPattern;
public LatinEntityResolutionReader( Reader reader )
{
this.originalReader = new PushbackReader( reader );
this.originalReader = new BufferedReader( reader );
this.entityPattern = Pattern.compile( "\\&[a-zA-Z]+\\;" );
}
public int read( char[] cbuf, int off, int len )
/**
* Read characters into a portion of an array. This method will block until some input is available,
* an I/O error occurs, or the end of the stream is reached.
*
* @param destbuf Destination buffer
* @param offset Offset (in destination buffer) at which to start storing characters
* @param length Maximum number of characters to read
* @return The number of characters read, or -1 if the end of the stream has been reached
* @throws IOException if an I/O error occurs.
*/
public int read( char[] destbuf, int offset, int length )
throws IOException
{
char tmpbuf[] = new char[cbuf.length];
int count = this.originalReader.read( tmpbuf, off, len );
int tmp_length;
int current_requested_offset = offset;
int current_requested_length = length;
StringBuffer sb = new StringBuffer();
// Drain leftover from last read request.
if ( leftover != null )
{
if ( leftover.length > length )
{
// Copy partial leftover.
System.arraycopy( leftover, 0, destbuf, current_requested_offset, length );
// Create new leftover of remaining.
char tmp[] = new char[length];
System.arraycopy( leftover, length, tmp, 0, length );
leftover = new char[tmp.length];
System.arraycopy( tmp, 0, leftover, 0, length );
return count;
// Return len
return length;
}
else
{
tmp_length = leftover.length;
// Copy full leftover
System.arraycopy( leftover, 0, destbuf, current_requested_offset, tmp_length );
// Empty out leftover (as there is now none left)
leftover = null;
// Adjust offset and lengths.
current_requested_offset += tmp_length;
current_requested_length -= tmp_length;
}
}
StringBuffer sbuf = getExpandedBuffer( current_requested_length );
// Have we reached the end of the buffer?
if ( sbuf == null )
{
// Do we have content?
if ( current_requested_offset > offset )
{
// Signal that we do, by calculating length.
return ( current_requested_offset - offset );
}
// No content. signal end of buffer.
return -1;
}
// Copy from expanded buf whatever length we can accomodate.
tmp_length = Math.min( sbuf.length(), current_requested_length );
sbuf.getChars( 0, tmp_length, destbuf, current_requested_offset );
// Create the leftover (if any)
if ( tmp_length < sbuf.length() )
{
leftover = new char[sbuf.length() - tmp_length];
sbuf.getChars( tmp_length, tmp_length + leftover.length, leftover, 0 );
}
// Calculate Actual Length and return.
return ( current_requested_offset - offset ) + tmp_length;
}
private StringBuffer getExpandedBuffer( int minimum_length )
throws IOException
{
StringBuffer buf = null;
String line = this.originalReader.readLine();
boolean done = ( line == null );
while ( !done )
{
if ( buf == null )
{
buf = new StringBuffer();
}
buf.append( expandLine( line ) );
// Add newline only if there is more data.
if ( this.originalReader.ready() )
{
buf.append( "\n" );
}
if ( buf.length() > minimum_length )
{
done = true;
}
else
{
line = this.originalReader.readLine();
done = ( line == null );
}
}
return buf;
}
private String expandLine( String line )
{
StringBuffer ret = new StringBuffer();
int offset = 0;
String entity;
Matcher mat = this.entityPattern.matcher( line );
while ( mat.find() )
{
ret.append( line.substring( offset, mat.start() ) );
entity = mat.group();
ret.append( LatinEntities.resolveEntity( entity ) );
offset += mat.start() + entity.length();
}
ret.append( line.substring( offset ) );
return ret.toString();
}
public void close()

View File

@ -0,0 +1,6 @@
<basic>
<names>
<name>Trygve Laugstøl</name>
<name>The ∞ Archiva</name>
</names>
</basic>

View File

@ -0,0 +1,51 @@
package org.apache.maven.archiva.xml;
/*
* 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.File;
import junit.framework.TestCase;
/**
* AbstractArchivaXmlTestCase
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
* @version $Id$
*/
public abstract class AbstractArchivaXmlTestCase
extends TestCase
{
protected File getExampleXml( String filename )
{
File examplesDir = new File( "src/test/examples" );
if ( !examplesDir.exists() )
{
fail( "Missing the examples directory: " + examplesDir.getAbsolutePath() );
}
File exampleFile = new File( examplesDir, filename );
if ( !exampleFile.exists() )
{
fail( "Missing the example xml file: " + exampleFile.getAbsolutePath() );
}
return exampleFile;
}
}

View File

@ -0,0 +1,45 @@
package org.apache.maven.archiva.xml;
/*
* 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 junit.framework.TestCase;
/**
* LatinEntitiesTest
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
* @version $Id$
*/
public class LatinEntitiesTest
extends TestCase
{
public void testResolveEntity()
{
// Good Entities.
assertEquals( "©", LatinEntities.resolveEntity( "&copy;" ) );
assertEquals( "", LatinEntities.resolveEntity( "&infin;" ) );
assertEquals( "ø", LatinEntities.resolveEntity( "&oslash;" ) );
// Bad Entities.
assertEquals( "", LatinEntities.resolveEntity( "" ) );
assertEquals( "&amp;", LatinEntities.resolveEntity( "&amp;" ) );
assertEquals( null, LatinEntities.resolveEntity( null ) );
}
}

View File

@ -0,0 +1,141 @@
package org.apache.maven.archiva.xml;
/*
* 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.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
/**
* LatinEntityResolutionReaderTest
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
* @version $Id$
*/
public class LatinEntityResolutionReaderTest
extends AbstractArchivaXmlTestCase
{
/**
* A method to obtain the content of a reader as a String,
* while allowing for specifing the buffer size of the operation.
*
* This method is only really useful for testing a Reader implementation.
*
* @param input the reader to get the input from.
* @param bufsize the buffer size to use.
* @return the contents of the reader as a String.
* @throws IOException if there was an I/O error.
*/
private String toStringFromReader( Reader input, int bufsize )
throws IOException
{
StringWriter output = new StringWriter();
final char[] buffer = new char[bufsize];
int n = 0;
while ( -1 != ( n = input.read( buffer ) ) )
{
output.write( buffer, 0, n );
}
output.flush();
return output.toString();
}
/**
* This reads a text file from the src/test/examples directory,
* normalizes the end of lines, and returns the contents as a big String.
*
* @param examplePath the name of the file in the src/test/examples directory.
* @return the contents of the provided file
* @throws IOException if there was an I/O error.
*/
private String toStringFromExample( String examplePath )
throws IOException
{
File exampleFile = getExampleXml( examplePath );
FileReader fileReader = new FileReader( exampleFile );
BufferedReader lineReader = new BufferedReader( fileReader );
StringBuffer sb = new StringBuffer();
boolean hasContent = false;
String line = lineReader.readLine();
while ( line != null )
{
if ( hasContent )
{
sb.append( "\n" );
}
sb.append( line );
hasContent = true;
line = lineReader.readLine();
}
return sb.toString();
}
public void assertProperRead( String sourcePath, String expectedPath, int bufsize )
{
try
{
File inputFile = getExampleXml( sourcePath );
FileReader fileReader = new FileReader( inputFile );
LatinEntityResolutionReader testReader = new LatinEntityResolutionReader( fileReader );
String actualOutput = toStringFromReader( testReader, bufsize );
String expectedOutput = toStringFromExample( expectedPath );
assertEquals( expectedOutput, actualOutput );
}
catch ( IOException e )
{
fail( "IOException: " + e.getMessage() );
}
}
public void testReaderNormalBufsize()
throws IOException
{
assertProperRead( "no-prolog-with-entities.xml", "no-prolog-with-entities.xml-resolved", 4096 );
}
public void testReaderSmallBufsize()
throws IOException
{
assertProperRead( "no-prolog-with-entities.xml", "no-prolog-with-entities.xml-resolved", 1024 );
}
public void testReaderRediculouslyTinyBufsize()
throws IOException
{
assertProperRead( "no-prolog-with-entities.xml", "no-prolog-with-entities.xml-resolved", 32 );
}
public void testReaderHugeBufsize()
throws IOException
{
assertProperRead( "no-prolog-with-entities.xml", "no-prolog-with-entities.xml-resolved", 409600 );
}
}

View File

@ -26,8 +26,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
/**
* XMLReaderTest
*
@ -35,23 +33,8 @@ import junit.framework.TestCase;
* @version $Id$
*/
public class XMLReaderTest
extends TestCase
extends AbstractArchivaXmlTestCase
{
private File getExampleXml( String filename )
{
File examplesDir = new File( "src/test/examples" );
if ( !examplesDir.exists() )
{
fail( "Missing the examples directory: " + examplesDir.getAbsolutePath() );
}
File exampleFile = new File( examplesDir, filename );
if ( !exampleFile.exists() )
{
fail( "Missing the example xml file: " + exampleFile.getAbsolutePath() );
}
return exampleFile;
}
private void assertElementTexts( List elementList, String[] expectedTexts )
{
assertEquals( "Element List Size", expectedTexts.length, elementList.size() );