Merge pull request #60 from simon04/java-8

Modernise Java codebase
This commit is contained in:
Jochen Topf 2021-01-04 09:16:56 +01:00 committed by GitHub
commit ee9144ef25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 63 additions and 59 deletions

View File

@ -18,27 +18,28 @@
package crosby.binary; package crosby.binary;
import java.io.UncheckedIOException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import crosby.binary.Osmformat;
import crosby.binary.file.BlockReaderAdapter; import crosby.binary.file.BlockReaderAdapter;
import crosby.binary.file.FileBlock; import crosby.binary.file.FileBlock;
import crosby.binary.file.FileBlockPosition; import crosby.binary.file.FileBlockPosition;
import crosby.binary.file.FileFormatException;
public abstract class BinaryParser implements BlockReaderAdapter { public abstract class BinaryParser implements BlockReaderAdapter {
protected int granularity; protected int granularity;
private long lat_offset; private long lat_offset;
private long lon_offset; private long lon_offset;
protected int date_granularity; protected int date_granularity;
private String strings[]; private String[] strings;
/** Take a Info protocol buffer containing a date and convert it into a java Date object */ /** Take a Info protocol buffer containing a date and convert it into a java Date object */
protected Date getDate(Osmformat.Info info) { protected Date getDate(Osmformat.Info info) {
if (info.hasTimestamp()) { if (info.hasTimestamp()) {
return new Date(date_granularity * (long) info.getTimestamp()); return new Date(date_granularity * info.getTimestamp());
} else } else
return NODATE; return NODATE;
} }
@ -47,8 +48,8 @@ public abstract class BinaryParser implements BlockReaderAdapter {
/** Get a string based on the index used. /** Get a string based on the index used.
* *
* Index 0 is reserved to use as a delimiter, therefore, index 1 corresponds to the first string in the table * Index 0 is reserved to use as a delimiter, therefore, index 1 corresponds to the first string in the table
* @param id * @param id the index
* @return * @return the string at the given index
*/ */
protected String getStringById(int id) { protected String getStringById(int id) {
return strings[id]; return strings[id];
@ -56,7 +57,6 @@ public abstract class BinaryParser implements BlockReaderAdapter {
@Override @Override
public void handleBlock(FileBlock message) { public void handleBlock(FileBlock message) {
// TODO Auto-generated method stub
try { try {
if (message.getType().equals("OSMHeader")) { if (message.getType().equals("OSMHeader")) {
Osmformat.HeaderBlock headerblock = Osmformat.HeaderBlock Osmformat.HeaderBlock headerblock = Osmformat.HeaderBlock
@ -68,9 +68,7 @@ public abstract class BinaryParser implements BlockReaderAdapter {
parse(primblock); parse(primblock);
} }
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block throw new UncheckedIOException(new FileFormatException(e));
e.printStackTrace();
throw new Error("ParseError"); // TODO
} }
} }

View File

@ -17,7 +17,10 @@
package crosby.binary; package crosby.binary;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -35,7 +38,7 @@ import crosby.binary.file.FileBlock;
* ordered to process their data at the appropriate time. * ordered to process their data at the appropriate time.
* */ * */
public class BinarySerializer { public class BinarySerializer implements Closeable, Flushable {
/** /**
* Interface used to write a group of primitives. One of these for each * Interface used to write a group of primitives. One of these for each
@ -67,11 +70,11 @@ public class BinarySerializer {
this.batch_limit = batch_limit; this.batch_limit = batch_limit;
} }
// Paramaters affecting the output size. // Parameters affecting the output size.
protected final int MIN_DENSE = 10; protected final int MIN_DENSE = 10;
protected int batch_limit = 4000; protected int batch_limit = 4000;
// Parmaters affecting the output. // Parameters affecting the output.
protected int granularity = 100; protected int granularity = 100;
protected int date_granularity = 1000; protected int date_granularity = 1000;
@ -80,8 +83,8 @@ public class BinarySerializer {
/** How many primitives have been seen in this batch */ /** How many primitives have been seen in this batch */
protected int batch_size = 0; protected int batch_size = 0;
protected int total_entities = 0; protected int total_entities = 0;
private StringTable stringtable = new StringTable(); private final StringTable stringtable = new StringTable();
protected List<PrimGroupWriterInterface> groups = new ArrayList<PrimGroupWriterInterface>(); protected List<PrimGroupWriterInterface> groups = new ArrayList<>();
protected BlockOutputStream output; protected BlockOutputStream output;
public BinarySerializer(BlockOutputStream output) { public BinarySerializer(BlockOutputStream output) {
@ -92,11 +95,13 @@ public class BinarySerializer {
return stringtable; return stringtable;
} }
@Override
public void flush() throws IOException { public void flush() throws IOException {
processBatch(); processBatch();
output.flush(); output.flush();
} }
@Override
public void close() throws IOException { public void close() throws IOException {
flush(); flush();
output.close(); output.close();
@ -139,9 +144,7 @@ public class BinarySerializer {
output.write(FileBlock.newInstance("OSMData", message output.write(FileBlock.newInstance("OSMData", message
.toByteString(), null)); .toByteString(), null));
} catch (IOException e) { } catch (IOException e) {
// TODO Auto-generated catch block throw new UncheckedIOException(e);
e.printStackTrace();
throw new Error(e);
} finally { } finally {
batch_size = 0; batch_size = 0;
groups.clear(); groups.clear();

View File

@ -24,7 +24,7 @@ import java.util.HashMap;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
/** /**
* Class for mapping a set of strings to integers, giving frequently occuring * Class for mapping a set of strings to integers, giving frequently occurring
* strings small integers. * strings small integers.
*/ */
public class StringTable { public class StringTable {
@ -34,34 +34,28 @@ public class StringTable {
private HashMap<String, Integer> counts; private HashMap<String, Integer> counts;
private HashMap<String, Integer> stringmap; private HashMap<String, Integer> stringmap;
private String set[]; private String[] set;
/**
* Increments the count of the given string
* @param s the string
*/
public void incr(String s) { public void incr(String s) {
if (counts.containsKey(s)) { counts.merge(s, 1, Integer::sum);
counts.put(s, new Integer(counts.get(s).intValue() + 1));
} else {
counts.put(s, new Integer(1));
}
} }
/** After the stringtable has been built, return the offset of a string in it. /** After the stringtable has been built, return the offset of a string in it.
* *
* Note, value '0' is reserved for use as a delimiter and will not be returned. * Note, value '0' is reserved for use as a delimiter and will not be returned.
* @param s * @param s the string to lookup
* @return * @return the offset of the string
*/ */
public int getIndex(String s) { public int getIndex(String s) {
return stringmap.get(s).intValue(); return stringmap.get(s);
} }
public void finish() { public void finish() {
Comparator<String> comparator = new Comparator<String>() { Comparator<String> comparator = (s1, s2) -> counts.get(s2) - counts.get(s1);
@Override
public int compare(final String s1, String s2) {
int diff = counts.get(s2) - counts.get(s1);
return diff;
}
};
/* Sort the stringtable */ /* Sort the stringtable */
@ -88,7 +82,7 @@ public class StringTable {
So, when I decide on the master stringtable to use, I put the 127 most frequently occurring So, when I decide on the master stringtable to use, I put the 127 most frequently occurring
strings into A (accomplishing goal 1), and sort them by frequency (to accomplish goal 2), but strings into A (accomplishing goal 1), and sort them by frequency (to accomplish goal 2), but
for B and C, which contain the less progressively less frequently encountered strings, I sort for B and C, which contain the less progressively less frequently encountered strings, I sort
them lexiconographically, to maximize goal 3 and ignoring goal 2. them lexicographically, to maximize goal 3 and ignoring goal 2.
Goal 1 is the most important. Goal 2 helped enough to be worth it, and goal 3 was pretty minor, Goal 1 is the most important. Goal 2 helped enough to be worth it, and goal 3 was pretty minor,
but all should be re-benchmarked. but all should be re-benchmarked.
@ -103,7 +97,7 @@ public class StringTable {
// Sort based on the frequency. // Sort based on the frequency.
Arrays.sort(set, comparator); Arrays.sort(set, comparator);
// Each group of keys that serializes to the same number of bytes is // Each group of keys that serializes to the same number of bytes is
// sorted lexiconographically. // sorted lexicographically.
// to maximize deflate compression. // to maximize deflate compression.
// Don't sort the first array. There's not likely to be much benefit, and we want frequent values to be small. // Don't sort the first array. There's not likely to be much benefit, and we want frequent values to be small.
@ -114,15 +108,15 @@ public class StringTable {
Arrays.sort(set, Math.min(1 << 14, set.length-1), Math.min(1 << 21, Arrays.sort(set, Math.min(1 << 14, set.length-1), Math.min(1 << 21,
set.length-1), comparator); set.length-1), comparator);
} }
stringmap = new HashMap<String, Integer>(2 * set.length); stringmap = new HashMap<>(2 * set.length);
for (int i = 0; i < set.length; i++) { for (int i = 0; i < set.length; i++) {
stringmap.put(set[i], new Integer(i+1)); // Index 0 is reserved for use as a delimiter. stringmap.put(set[i], i + 1); // Index 0 is reserved for use as a delimiter.
} }
counts = null; counts = null;
} }
public void clear() { public void clear() {
counts = new HashMap<String, Integer>(100); counts = new HashMap<>(100);
stringmap = null; stringmap = null;
set = null; set = null;
} }
@ -131,8 +125,9 @@ public class StringTable {
Osmformat.StringTable.Builder builder = Osmformat.StringTable Osmformat.StringTable.Builder builder = Osmformat.StringTable
.newBuilder(); .newBuilder();
builder.addS(ByteString.copyFromUtf8("")); // Add a unused string at offset 0 which is used as a delimiter. builder.addS(ByteString.copyFromUtf8("")); // Add a unused string at offset 0 which is used as a delimiter.
for (int i = 0; i < set.length; i++) for (String s : set) {
builder.addS(ByteString.copyFromUtf8(set[i])); builder.addS(ByteString.copyFromUtf8(s));
}
return builder; return builder;
} }
} }

View File

@ -17,11 +17,12 @@
package crosby.binary.file; package crosby.binary.file;
import java.io.Closeable;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
public class BlockInputStream { public class BlockInputStream implements Closeable {
// TODO: Should be seekable input stream! // TODO: Should be seekable input stream!
public BlockInputStream(InputStream input, BlockReaderAdapter adaptor) { public BlockInputStream(InputStream input, BlockReaderAdapter adaptor) {
this.input = input; this.input = input;
@ -38,6 +39,7 @@ public class BlockInputStream {
} }
} }
@Override
public void close() throws IOException { public void close() throws IOException {
input.close(); input.close();
} }

View File

@ -44,7 +44,7 @@ public class BlockOutputStream {
else if (s.equals("deflate")) else if (s.equals("deflate"))
compression = CompressFlags.DEFLATE; compression = CompressFlags.DEFLATE;
else else
throw new Error("Unknown compression type: " + s); throw new IllegalArgumentException("Unknown compression type: " + s);
} }
/** Write a block with the stream's default compression flag */ /** Write a block with the stream's default compression flag */
@ -69,6 +69,6 @@ public class BlockOutputStream {
} }
OutputStream outwrite; OutputStream outwrite;
List<FileBlockPosition> writtenblocks = new ArrayList<FileBlockPosition>(); List<FileBlockPosition> writtenblocks = new ArrayList<>();
CompressFlags compression; CompressFlags compression;
} }

View File

@ -18,10 +18,12 @@
package crosby.binary.file; package crosby.binary.file;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -48,13 +50,13 @@ public class FileBlock extends FileBlockBase {
if (blob != null && blob.size() > MAX_BODY_SIZE/2) { if (blob != null && blob.size() > MAX_BODY_SIZE/2) {
System.err.println("Warning: Fileblock has body size too large and may be considered corrupt"); System.err.println("Warning: Fileblock has body size too large and may be considered corrupt");
if (blob != null && blob.size() > MAX_BODY_SIZE-1024*1024) { if (blob != null && blob.size() > MAX_BODY_SIZE-1024*1024) {
throw new Error("This file has too many entities in a block. Parsers will reject it."); throw new IllegalArgumentException("This file has too many entities in a block. Parsers will reject it.");
} }
} }
if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE/2) { if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE/2) {
System.err.println("Warning: Fileblock has indexdata too large and may be considered corrupt"); System.err.println("Warning: Fileblock has indexdata too large and may be considered corrupt");
if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE-512) { if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE-512) {
throw new Error("This file header is too large. Parsers will reject it."); throw new IllegalArgumentException("This file header is too large. Parsers will reject it.");
} }
} }
return new FileBlock(type, blob, indexdata); return new FileBlock(type, blob, indexdata);
@ -65,7 +67,7 @@ public class FileBlock extends FileBlockBase {
Deflater deflater = new Deflater(); Deflater deflater = new Deflater();
deflater.setInput(data.toByteArray()); deflater.setInput(data.toByteArray());
deflater.finish(); deflater.finish();
byte out[] = new byte[size]; byte[] out = new byte[size];
deflater.deflate(out); deflater.deflate(out);
if (!deflater.finished()) { if (!deflater.finished()) {
@ -77,7 +79,7 @@ public class FileBlock extends FileBlockBase {
deflater.deflate(out, deflater.getTotalOut(), out.length deflater.deflate(out, deflater.getTotalOut(), out.length
- deflater.getTotalOut()); - deflater.getTotalOut());
if (!deflater.finished()) { if (!deflater.finished()) {
throw new Error("Internal error in compressor"); throw new UncheckedIOException(new EOFException());
} }
} }
ByteString compressed = ByteString.copyFrom(out, 0, deflater ByteString compressed = ByteString.copyFrom(out, 0, deflater
@ -103,7 +105,7 @@ public class FileBlock extends FileBlockBase {
if (flags == CompressFlags.DEFLATE) if (flags == CompressFlags.DEFLATE)
deflateInto(blobbuilder); deflateInto(blobbuilder);
else else
throw new Error("Compression flag not understood"); throw new IllegalArgumentException("Compression flag not understood");
} }
Fileformat.Blob blob = blobbuilder.build(); Fileformat.Blob blob = blobbuilder.build();

View File

@ -50,7 +50,7 @@ public class FileBlockHead extends FileBlockReference {
throw new FileFormatException("Unexpectedly long header "+MAX_HEADER_SIZE+ " bytes. Possibly corrupt file."); throw new FileFormatException("Unexpectedly long header "+MAX_HEADER_SIZE+ " bytes. Possibly corrupt file.");
} }
byte buf[] = new byte[headersize]; byte[] buf = new byte[headersize];
datinput.readFully(buf); datinput.readFully(buf);
// System.out.format("Read buffer for header of %d bytes\n",buf.length); // System.out.format("Read buffer for header of %d bytes\n",buf.length);
Fileformat.BlobHeader header = Fileformat.BlobHeader Fileformat.BlobHeader header = Fileformat.BlobHeader
@ -90,7 +90,7 @@ public class FileBlockHead extends FileBlockReference {
*/ */
FileBlock readContents(InputStream input) throws IOException { FileBlock readContents(InputStream input) throws IOException {
DataInputStream datinput = new DataInputStream(input); DataInputStream datinput = new DataInputStream(input);
byte buf[] = new byte[getDatasize()]; byte[] buf = new byte[getDatasize()];
datinput.readFully(buf); datinput.readFully(buf);
return parseData(buf); return parseData(buf);
} }

View File

@ -21,6 +21,7 @@ import java.io.DataInputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.zip.DataFormatException; import java.util.zip.DataFormatException;
import java.util.zip.Inflater; import java.util.zip.Inflater;
@ -43,21 +44,20 @@ public class FileBlockPosition extends FileBlockBase {
} }
/** Parse out and decompress the data part of a fileblock helper function. */ /** Parse out and decompress the data part of a fileblock helper function. */
FileBlock parseData(byte buf[]) throws InvalidProtocolBufferException { FileBlock parseData(byte[] buf) throws InvalidProtocolBufferException {
FileBlock out = FileBlock.newInstance(type, null, indexdata); FileBlock out = FileBlock.newInstance(type, null, indexdata);
Fileformat.Blob blob = Fileformat.Blob.parseFrom(buf); Fileformat.Blob blob = Fileformat.Blob.parseFrom(buf);
if (blob.hasRaw()) { if (blob.hasRaw()) {
out.data = blob.getRaw(); out.data = blob.getRaw();
} else if (blob.hasZlibData()) { } else if (blob.hasZlibData()) {
byte buf2[] = new byte[blob.getRawSize()]; byte[] buf2 = new byte[blob.getRawSize()];
Inflater decompresser = new Inflater(); Inflater decompresser = new Inflater();
decompresser.setInput(blob.getZlibData().toByteArray()); decompresser.setInput(blob.getZlibData().toByteArray());
// decompresser.getRemaining(); // decompresser.getRemaining();
try { try {
decompresser.inflate(buf2); decompresser.inflate(buf2);
} catch (DataFormatException e) { } catch (DataFormatException e) {
e.printStackTrace(); throw new UncheckedIOException(new FileFormatException(e));
throw new Error(e);
} }
assert (decompresser.finished()); assert (decompresser.finished());
decompresser.end(); decompresser.end();
@ -85,11 +85,11 @@ public class FileBlockPosition extends FileBlockBase {
public FileBlock read(InputStream input) throws IOException { public FileBlock read(InputStream input) throws IOException {
if (input instanceof FileInputStream) { if (input instanceof FileInputStream) {
((FileInputStream) input).getChannel().position(data_offset); ((FileInputStream) input).getChannel().position(data_offset);
byte buf[] = new byte[getDatasize()]; byte[] buf = new byte[getDatasize()];
(new DataInputStream(input)).readFully(buf); (new DataInputStream(input)).readFully(buf);
return parseData(buf); return parseData(buf);
} else { } else {
throw new Error("Random access binary reads require seekability"); throw new IllegalArgumentException("Random access binary reads require seekability");
} }
} }
@ -98,12 +98,12 @@ public class FileBlockPosition extends FileBlockBase {
* stored. * stored.
*/ */
public ByteString serialize() { public ByteString serialize() {
throw new Error("TODO"); throw new UnsupportedOperationException("TODO");
} }
/** TODO: Parse a serialized representation of this block reference */ /** TODO: Parse a serialized representation of this block reference */
static FileBlockPosition parseFrom(ByteString b) { static FileBlockPosition parseFrom(ByteString b) {
throw new Error("TODO"); throw new UnsupportedOperationException("TODO");
} }
protected int datasize; protected int datasize;

View File

@ -25,6 +25,10 @@ public class FileFormatException extends IOException {
super(string); super(string);
} }
public FileFormatException(Throwable cause) {
super(cause);
}
/** /**
* *
*/ */