From 7665e116edd660d24a16526e9b27a3bfdc121e6e Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 20 Jul 2015 14:18:51 +0200 Subject: [PATCH] Updated storage info. Updated netty, passes all unit tests --- Dorkbox-Util/.classpath | 4 +- .../dorkbox/util/SerializationManager.java | 94 +++++ Dorkbox-Util/src/dorkbox/util/Sys.java | 351 ++++++++++-------- .../dorkbox/util/bytes/ByteArrayWrapper.java | 110 ++++-- .../serialization/EccPublicKeySerializer.java | 36 +- .../src/dorkbox/util/database/DB_Server.java | 116 ++++++ .../util/database/DatabaseStorage.java | 33 ++ .../util/properties/PropertiesProvider.java | 42 ++- .../src/dorkbox/util/storage/DiskStorage.java | 118 +++--- .../dorkbox/util/storage/MemoryStorage.java | 8 +- .../src/dorkbox/util/storage/Metadata.java | 4 +- .../{DiskStorageIfface.java => Storage.java} | 2 +- .../src/dorkbox/util/storage/StorageBase.java | 2 +- .../storage/{MakeStorage.java => Store.java} | 72 ++-- .../test/dorkbox/util/StorageTest.java | 280 +++++++------- Dorkbox-Util/test/dorkbox/util/UByteTest.java | 19 +- .../test/dorkbox/util/UIntegerTest.java | 94 +++-- .../test/dorkbox/util/UNumberTest.java | 26 +- 18 files changed, 888 insertions(+), 523 deletions(-) create mode 100644 Dorkbox-Util/src/dorkbox/util/SerializationManager.java create mode 100644 Dorkbox-Util/src/dorkbox/util/database/DB_Server.java create mode 100644 Dorkbox-Util/src/dorkbox/util/database/DatabaseStorage.java rename Dorkbox-Util/src/dorkbox/util/storage/{DiskStorageIfface.java => Storage.java} (99%) rename Dorkbox-Util/src/dorkbox/util/storage/{MakeStorage.java => Store.java} (72%) diff --git a/Dorkbox-Util/.classpath b/Dorkbox-Util/.classpath index e8a6f1e..745baac 100644 --- a/Dorkbox-Util/.classpath +++ b/Dorkbox-Util/.classpath @@ -6,7 +6,6 @@ - @@ -23,9 +22,10 @@ - + + diff --git a/Dorkbox-Util/src/dorkbox/util/SerializationManager.java b/Dorkbox-Util/src/dorkbox/util/SerializationManager.java new file mode 100644 index 0000000..a72739c --- /dev/null +++ b/Dorkbox-Util/src/dorkbox/util/SerializationManager.java @@ -0,0 +1,94 @@ +package dorkbox.util; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.KryoException; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; +import io.netty.buffer.ByteBuf; + +/** + * + */ +public +interface SerializationManager { + + + /** + * Registers the class using the lowest, next available integer ID and the + * {@link Kryo#getDefaultSerializer(Class) default serializer}. If the class + * is already registered, the existing entry is updated with the new + * serializer. Registering a primitive also affects the corresponding + * primitive wrapper. + *

+ * Because the ID assigned is affected by the IDs registered before it, the + * order classes are registered is important when using this method. The + * order must be the same at deserialization as it was for serialization. + */ + void register(Class clazz); + + /** + * Registers the class using the lowest, next available integer ID and the + * specified serializer. If the class is already registered, the existing + * entry is updated with the new serializer. Registering a primitive also + * affects the corresponding primitive wrapper. + *

+ * Because the ID assigned is affected by the IDs registered before it, the + * order classes are registered is important when using this method. The + * order must be the same at deserialization as it was for serialization. + */ + void register(Class clazz, Serializer serializer); + + + /** + * Registers the class using the specified ID and serializer. If the ID is + * already in use by the same type, the old entry is overwritten. If the ID + * is already in use by a different type, a {@link KryoException} is thrown. + * Registering a primitive also affects the corresponding primitive wrapper. + *

+ * IDs must be the same at deserialization as they were for serialization. + * + * @param id Must be >= 0. Smaller IDs are serialized more efficiently. IDs + * 0-8 are used by default for primitive types and String, but + * these IDs can be repurposed. + */ + void register(Class clazz, Serializer serializer, int id); + + /** + * Waits until a kryo is available to write, using CAS operations to prevent having to synchronize. + *

+ * No crypto and no sequence number + *

+ * There is a small speed penalty if there were no kryo's available to use. + */ + void write(ByteBuf buffer, Object message); + + /** + * Reads an object from the buffer. + *

+ * No crypto and no sequence number + * + * @param length should ALWAYS be the length of the expected object! + */ + Object read(ByteBuf buffer, int length); + + /** + * Writes the class and object using an available kryo instance + */ + void writeFullClassAndObject(Output output, Object value); + + /** + * Returns a class read from the input + */ + Object readFullClassAndObject(Input input); + + /** + * Borrows a kryo from the threadsafe pool. You must release it back to the pool when done. + */ + Kryo take() throws InterruptedException; + + /** + * Releases the kryo back to the threadsafe pool + */ + void release(Kryo kryo); +} diff --git a/Dorkbox-Util/src/dorkbox/util/Sys.java b/Dorkbox-Util/src/dorkbox/util/Sys.java index 15df59a..8ed4d16 100644 --- a/Dorkbox-Util/src/dorkbox/util/Sys.java +++ b/Dorkbox-Util/src/dorkbox/util/Sys.java @@ -25,18 +25,20 @@ import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class Sys { +public +class Sys { public static final int javaVersion = getJavaVersion(); public static final boolean isAndroid = getIsAndroid(); - public static final int KILOBYTE = 1024; - public static final int MEGABYTE = 1024 * KILOBYTE; - public static final int GIGABYTE = 1024 * MEGABYTE; - public static final long TERABYTE = 1024L * GIGABYTE; + public static final int KILOBYTE = 1024; + public static final int MEGABYTE = 1024 * KILOBYTE; + public static final int GIGABYTE = 1024 * MEGABYTE; + public static final long TERABYTE = 1024L * GIGABYTE; - public static char[] HEX_CHARS = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + public static char[] HEX_CHARS = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - public static final char[] convertStringToChars(String string) { + public static final + char[] convertStringToChars(String string) { char[] charArray = string.toCharArray(); eraseString(string); @@ -44,7 +46,8 @@ public class Sys { return charArray; } - private static boolean getIsAndroid() { + private static + boolean getIsAndroid() { try { Class.forName("android.os.Process"); return true; @@ -53,31 +56,41 @@ public class Sys { } } - private static int getJavaVersion() { + private static + int getJavaVersion() { String fullJavaVersion = System.getProperty("java.version"); // Converts a java version string, such as "1.7u45", and converts it into 7 char versionChar; if (fullJavaVersion.startsWith("1.")) { versionChar = fullJavaVersion.charAt(2); - } else { + } + else { versionChar = fullJavaVersion.charAt(0); } switch (versionChar) { - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - default: return -1; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + default: + return -1; } } - public static final void eraseString(String string) { + public static final + void eraseString(String string) { // You can change the value of the inner char[] using reflection. // // You must be careful to either change it with an array of the same length, @@ -87,26 +100,26 @@ public class Sys { // you will need to recalculate the hash code and set the value of the hashCode field. try { - Field valueField = String.class.getDeclaredField("value"); - valueField.setAccessible(true); - char[] chars = (char[]) valueField.get(string); - Arrays.fill(chars, '*'); // asterisk it out in case of GC not picking up the old char array. + Field valueField = String.class.getDeclaredField("value"); + valueField.setAccessible(true); + char[] chars = (char[]) valueField.get(string); + Arrays.fill(chars, '*'); // asterisk it out in case of GC not picking up the old char array. - valueField.set(string, new char[0]); // replace it. + valueField.set(string, new char[0]); // replace it. - // set count to 0 - try { - // newer versions of java don't have this field - Field countField = String.class.getDeclaredField("count"); - countField.setAccessible(true); - countField.set(string, 0); - } catch (Exception ignored) { - } + // set count to 0 + try { + // newer versions of java don't have this field + Field countField = String.class.getDeclaredField("count"); + countField.setAccessible(true); + countField.set(string, 0); + } catch (Exception ignored) { + } - // set hash to 0 - Field hashField = String.class.getDeclaredField("hash"); - hashField.setAccessible(true); - hashField.set(string, 0); + // set hash to 0 + Field hashField = String.class.getDeclaredField("hash"); + hashField.setAccessible(true); + hashField.set(string, 0); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { @@ -120,10 +133,10 @@ public class Sys { /** * FROM: https://www.cqse.eu/en/blog/string-replace-performance/ - * + *

* Replaces all occurrences of keys of the given map in the given string * with the associated value in that map. - * + *

* This method is semantically the same as calling * {@link String#replace(CharSequence, CharSequence)} for each of the * entries in the map, but may be significantly faster for many replacements @@ -131,11 +144,12 @@ public class Sys { * {@link String#replace(CharSequence, CharSequence)} uses regular * expressions internally and results in many String object allocations when * applied iteratively. - * + *

* The order in which replacements are applied depends on the order of the * map's entry set. */ - public static String replaceStringFast(String string, Map replacements) { + public static + String replaceStringFast(String string, Map replacements) { StringBuilder sb = new StringBuilder(string); for (Entry entry : replacements.entrySet()) { String key = entry.getKey(); @@ -158,9 +172,10 @@ public class Sys { * * @return index if it's there, -1 if not there */ - public static int searchStringFast(String string, char c) { + public static + int searchStringFast(String string, char c) { int length = string.length(); - for (int i=0;i TERABYTE) { return String.format("%2.2fTB", (float) size / TERABYTE); } @@ -185,12 +201,13 @@ public class Sys { } return String.valueOf(size) + "B"; - } + } /** * Convenient close for a stream. */ - public static void close(InputStream inputStream) { + public static + void close(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); @@ -204,7 +221,8 @@ public class Sys { /** * Convenient close for a stream. */ - public static void close(OutputStream outputStream) { + public static + void close(OutputStream outputStream) { if (outputStream != null) { try { outputStream.close(); @@ -218,7 +236,8 @@ public class Sys { /** * Convenient close for a Reader. */ - public static void close(Reader inputReader) { + public static + void close(Reader inputReader) { if (inputReader != null) { try { inputReader.close(); @@ -232,7 +251,8 @@ public class Sys { /** * Convenient close for a Writer. */ - public static void close(Writer outputWriter) { + public static + void close(Writer outputWriter) { if (outputWriter != null) { try { outputWriter.close(); @@ -245,10 +265,11 @@ public class Sys { /** * Copy the contents of the input stream to the output stream. - *

+ *

* DOES NOT CLOSE THE STEAMS! */ - public static T copyStream(InputStream inputStream, T outputStream) throws IOException { + public static + T copyStream(InputStream inputStream, T outputStream) throws IOException { byte[] buffer = new byte[4096]; int read = 0; while ((read = inputStream.read(buffer)) > 0) { @@ -261,7 +282,8 @@ public class Sys { /** * Convert the contents of the input stream to a byte array. */ - public static byte[] getBytesFromStream(InputStream inputStream) throws IOException { + public static + byte[] getBytesFromStream(InputStream inputStream) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(8192); byte[] buffer = new byte[4096]; @@ -275,11 +297,13 @@ public class Sys { return baos.toByteArray(); } - public static final byte[] copyBytes(byte[] src) { + public static final + byte[] copyBytes(byte[] src) { return copyBytes(src, 0); } - public static final byte[] copyBytes(byte[] src, int position) { + public static final + byte[] copyBytes(byte[] src, int position) { int length = src.length - position; byte[] b = new byte[length]; @@ -287,7 +311,8 @@ public class Sys { return b; } - public static final byte[] concatBytes(byte[]... arrayBytes) { + public static final + byte[] concatBytes(byte[]... arrayBytes) { int length = 0; for (byte[] bytes : arrayBytes) { length += bytes.length; @@ -304,8 +329,11 @@ public class Sys { return concatBytes; } - /** gets the SHA256 hash + SALT of the specified username, as UTF-16 */ - public static final byte[] getSha256WithSalt(String username, byte[] saltBytes) { + /** + * gets the SHA256 hash + SALT of the specified username, as UTF-16 + */ + public static final + byte[] getSha256WithSalt(String username, byte[] saltBytes) { if (username == null) { return null; } @@ -322,8 +350,11 @@ public class Sys { return usernameHashBytes; } - /** gets the SHA256 hash of the specified string, as UTF-16 */ - public static final byte[] getSha256(String string) { + /** + * gets the SHA256 hash of the specified string, as UTF-16 + */ + public static final + byte[] getSha256(String string) { byte[] charToBytes = Sys.charToBytes(string.toCharArray()); SHA256Digest sha256 = new SHA256Digest(); @@ -334,8 +365,11 @@ public class Sys { return usernameHashBytes; } - /** gets the SHA256 hash of the specified byte array */ - public static final byte[] getSha256(byte[] bytes) { + /** + * gets the SHA256 hash of the specified byte array + */ + public static final + byte[] getSha256(byte[] bytes) { SHA256Digest sha256 = new SHA256Digest(); byte[] hashBytes = new byte[sha256.getDigestSize()]; @@ -345,20 +379,24 @@ public class Sys { return hashBytes; } - /** this saves the char array in UTF-16 format of bytes */ - public static final byte[] charToBytes(char[] text) { + /** + * this saves the char array in UTF-16 format of bytes + */ + public static final + byte[] charToBytes(char[] text) { // NOTE: this saves the char array in UTF-16 format of bytes. - byte[] bytes = new byte[text.length*2]; - for(int i=0; i> 8); - bytes[2*i+1] = (byte) text[i]; + byte[] bytes = new byte[text.length * 2]; + for (int i = 0; i < text.length; i++) { + bytes[2 * i] = (byte) (text[i] >> 8); + bytes[2 * i + 1] = (byte) text[i]; } return bytes; } - public static final byte[] intsToBytes(int[] ints) { + public static final + byte[] intsToBytes(int[] ints) { int length = ints.length; byte[] bytes = new byte[length]; @@ -369,13 +407,14 @@ public class Sys { return new byte[length]; } - bytes[i] = (byte)intValue; + bytes[i] = (byte) intValue; } return bytes; } - public static final int[] bytesToInts(byte[] bytes) { + public static final + int[] bytesToInts(byte[] bytes) { int length = bytes.length; int[] ints = new int[length]; @@ -386,11 +425,13 @@ public class Sys { return ints; } - public static final String bytesToHex(byte[] bytes) { + public static final + String bytesToHex(byte[] bytes) { return bytesToHex(bytes, false); } - public static final String bytesToHex(byte[] bytes, boolean padding) { + public static final + String bytesToHex(byte[] bytes, boolean padding) { if (padding) { char[] hexString = new char[3 * bytes.length]; int j = 0; @@ -402,7 +443,8 @@ public class Sys { } return new String(hexString); - } else { + } + else { char[] hexString = new char[2 * bytes.length]; int j = 0; @@ -419,47 +461,48 @@ public class Sys { * Converts an ASCII character representing a hexadecimal * value into its integer equivalent. */ - public static final int hexByteToInt(byte b) { + public static final + int hexByteToInt(byte b) { switch (b) { - case '0' : + case '0': return 0; - case '1' : + case '1': return 1; - case '2' : + case '2': return 2; - case '3' : + case '3': return 3; - case '4' : + case '4': return 4; - case '5' : + case '5': return 5; - case '6' : + case '6': return 6; - case '7' : + case '7': return 7; - case '8' : + case '8': return 8; - case '9' : + case '9': return 9; - case 'A' : - case 'a' : + case 'A': + case 'a': return 10; - case 'B' : - case 'b' : + case 'B': + case 'b': return 11; - case 'C' : - case 'c' : + case 'C': + case 'c': return 12; - case 'D' : - case 'd' : + case 'D': + case 'd': return 13; - case 'E' : - case 'e' : + case 'E': + case 'e': return 14; - case 'F' : - case 'f' : + case 'F': + case 'f': return 15; - default : + default: throw new IllegalArgumentException("Error decoding byte"); } } @@ -467,7 +510,8 @@ public class Sys { /** * A 4-digit hex result. */ - public static final void hex4(char c, StringBuilder sb) { + public static final + void hex4(char c, StringBuilder sb) { sb.append(HEX_CHARS[(c & 0xF000) >> 12]); sb.append(HEX_CHARS[(c & 0x0F00) >> 8]); sb.append(HEX_CHARS[(c & 0x00F0) >> 4]); @@ -478,12 +522,12 @@ public class Sys { * Returns a string representation of the byte array as a series of * hexadecimal characters. * - * @param bytes - * byte array to convert + * @param bytes byte array to convert * @return a string representation of the byte array as a series of - * hexadecimal characters + * hexadecimal characters */ - public static final String toHexString(byte[] bytes) { + public static final + String toHexString(byte[] bytes) { char[] hexString = new char[2 * bytes.length]; int j = 0; @@ -499,13 +543,14 @@ public class Sys { * XOR two byte arrays together, and save result in originalArray * * @param originalArray this is the base of the XOR operation. - * @param keyArray this is XOR'd into the original array, repeats if necessary. + * @param keyArray this is XOR'd into the original array, repeats if necessary. */ - public static void xorArrays(byte[] originalArray, byte[] keyArray) { + public static + void xorArrays(byte[] originalArray, byte[] keyArray) { int keyIndex = 0; int keyLength = keyArray.length; - for (int i=0;i array) { + public static final + byte[] encodeStringArray(List array) { int length = 0; for (String s : array) { byte[] bytes = s.getBytes(); @@ -526,7 +572,7 @@ public class Sys { return new byte[0]; } - byte[] bytes = new byte[length+array.size()]; + byte[] bytes = new byte[length + array.size()]; length = 0; for (String s : array) { @@ -539,18 +585,19 @@ public class Sys { return bytes; } - public static final ArrayList decodeStringArray(byte[] bytes) { + public static final + ArrayList decodeStringArray(byte[] bytes) { int length = bytes.length; int position = 0; byte token = (byte) 0x01; ArrayList list = new ArrayList(0); int last = 0; - while (last+position < length) { - byte b = bytes[last+position++]; - if (b == token ) { - byte[] xx = new byte[position-1]; - System.arraycopy(bytes, last, xx, 0, position-1); + while (last + position < length) { + byte b = bytes[last + position++]; + if (b == token) { + byte[] xx = new byte[position - 1]; + System.arraycopy(bytes, last, xx, 0, position - 1); list.add(new String(xx)); last += position; position = 0; @@ -561,32 +608,35 @@ public class Sys { return list; } - public static String printArrayRaw(byte[] bytes) { + public static + String printArrayRaw(byte[] bytes) { return printArrayRaw(bytes, 0); } - public static String printArrayRaw(byte[] bytes, int lineLength) { + public static + String printArrayRaw(byte[] bytes, int lineLength) { if (lineLength > 0) { int mod = lineLength; int length = bytes.length; - int comma = length-1; + int comma = length - 1; - StringBuilder builder = new StringBuilder(length + length/mod); + StringBuilder builder = new StringBuilder(length + length / mod); for (int i = 0; i < length; i++) { builder.append(bytes[i]); if (i < comma) { builder.append(","); } - if (i > 0 && i%mod == 0) { + if (i > 0 && i % mod == 0) { builder.append(OS.LINE_SEPARATOR); } } return builder.toString(); - } else { + } + else { int length = bytes.length; - int comma = length-1; + int comma = length - 1; StringBuilder builder = new StringBuilder(length + length); for (int i = 0; i < length; i++) { @@ -600,25 +650,29 @@ public class Sys { } } - public static void printArray(byte[] bytes) { + public static + void printArray(byte[] bytes) { printArray(bytes, bytes.length, true); } - public static void printArray(byte[] bytes, int length, boolean includeByteCount) { + public static + void printArray(byte[] bytes, int length, boolean includeByteCount) { printArray(bytes, length, includeByteCount, 40); } - public static void printArray(byte[] bytes, int length, boolean includeByteCount, int lineLength) { + public static + void printArray(byte[] bytes, int length, boolean includeByteCount, int lineLength) { if (includeByteCount) { System.err.println("Bytes: " + length); } - int comma = length-1; + int comma = length - 1; StringBuilder builder; if (lineLength > 0) { - builder = new StringBuilder(length + comma + length/lineLength + 2); - } else { + builder = new StringBuilder(length + comma + length / lineLength + 2); + } + else { builder = new StringBuilder(length + comma + 2); } builder.append("{"); @@ -628,7 +682,7 @@ public class Sys { if (i < comma) { builder.append(","); } - if (i > 0 && lineLength > 0 && i%lineLength == 0) { + if (i > 0 && lineLength > 0 && i % lineLength == 0) { builder.append(OS.LINE_SEPARATOR); } } @@ -658,17 +712,18 @@ public class Sys { *

* * @throws UnknownHostException If the LAN address of the machine cannot be found. - * - * From: https://issues.apache.org/jira/browse/JCS-40 + *

+ * From: https://issues.apache.org/jira/browse/JCS-40 */ - public static InetAddress getLocalHostLanAddress() throws UnknownHostException { + public static + InetAddress getLocalHostLanAddress() throws UnknownHostException { try { InetAddress candidateAddress = null; // Iterate all NICs (network interface cards)... - for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements();) { + for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { NetworkInterface iface = ifaces.nextElement(); // Iterate all IP addresses assigned to each card... - for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements();) { + for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { InetAddress inetAddr = inetAddrs.nextElement(); if (!inetAddr.isLoopbackAddress()) { @@ -700,8 +755,7 @@ public class Sys { throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); } return jdkSuppliedAddress; - } - catch (Exception e) { + } catch (Exception e) { UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e); unknownHostException.initCause(e); throw unknownHostException; @@ -711,44 +765,39 @@ public class Sys { /** * This will retrieve your IP address via an HTTP server. - *

+ *

* NOTE: Use DnsClient.getPublicIp() instead. It's much faster and more reliable as it uses DNS. * * @return the public IP address if found, or null if it didn't find it */ @Deprecated - public static String getPublicIpViaHttp() { + public static + String getPublicIpViaHttp() { // method 1: use DNS servers // dig +short myip.opendns.com @resolver1.opendns.com // method 2: use public http servers - final String websites[] = { - "http://ip.dorkbox.com/", - "http://ip.javalauncher.com/", - "http://checkip.dyndns.com/", - "http://checkip.dyn.com/", - "http://curlmyip.com/", - "http://tnx.nl/ip", - "http://ipecho.net/plain", - "http://icanhazip.com/", - "http://ip.appspot.com/", - }; + final String websites[] = {"http://ip.dorkbox.com/", "http://ip.javalauncher.com/", "http://checkip.dyndns.com/", + "http://checkip.dyn.com/", "http://curlmyip.com/", "http://tnx.nl/ip", "http://ipecho.net/plain", + "http://icanhazip.com/", "http://ip.appspot.com/",}; // loop, since they won't always work. - for (int i=0;i EMx -> WLANx + * * @return null if not found */ - public static InetAddress getIpAddressesFromNic() { + public static + InetAddress getIpAddressesFromNic() { try { Enumeration nets = NetworkInterface.getNetworkInterfaces(); while (nets.hasMoreElements()) { diff --git a/Dorkbox-Util/src/dorkbox/util/bytes/ByteArrayWrapper.java b/Dorkbox-Util/src/dorkbox/util/bytes/ByteArrayWrapper.java index 616caa0..1457307 100644 --- a/Dorkbox-Util/src/dorkbox/util/bytes/ByteArrayWrapper.java +++ b/Dorkbox-Util/src/dorkbox/util/bytes/ByteArrayWrapper.java @@ -15,38 +15,34 @@ */ package dorkbox.util.bytes; +import org.bouncycastle.crypto.digests.SHA256Digest; + +import java.nio.charset.Charset; import java.util.Arrays; /** * Necessary to provide equals and hashcode methods on a byte arrays, if they are to be used as keys in a map/set/etc */ -public final class ByteArrayWrapper { - private final byte[] data; +public final +class ByteArrayWrapper { + public static final Charset UTF_8 = Charset.forName("UTF-8"); + + private byte[] data; private Integer hashCode; - /** - * Makes a safe copy of the byte array, so that changes to the original do not affect the wrapper. - * Side affect is additional memory is used. - */ - public static ByteArrayWrapper copy(byte[] data) { - return new ByteArrayWrapper(data, true); - } - - - /** - * Does not make a copy of the data, so changes to the original will also affect the wrapper. - * Side affect is no extra memory is needed. - */ - public static ByteArrayWrapper wrap(byte[] data) { - return new ByteArrayWrapper(data, false); + private + ByteArrayWrapper() { + // this is necessary for kryo } /** * Permits the re-use of a byte array. + * * @param copyBytes if TRUE, then the byteArray is copies. if FALSE, the byte array is uses as-is. - * Using FALSE IS DANGEROUS!!!! If the underlying byte array is modified, this changes as well. + * Using FALSE IS DANGEROUS!!!! If the underlying byte array is modified, this changes as well. */ - private ByteArrayWrapper(byte[] data, boolean copyBytes) { + private + ByteArrayWrapper(byte[] data, boolean copyBytes) { if (data == null) { throw new NullPointerException(); } @@ -56,27 +52,61 @@ public final class ByteArrayWrapper { this.data = new byte[length]; // copy so it's immutable as a key. System.arraycopy(data, 0, this.data, 0, length); - } else { + } + else { this.data = data; } } - public byte[] getBytes() { + /** + * Makes a safe copy of the byte array, so that changes to the original do not affect the wrapper. + * Side affect is additional memory is used. + */ + public static + ByteArrayWrapper copy(byte[] data) { + if (data == null) { + return null; + } + + return new ByteArrayWrapper(data, true); + } + + /** + * Does not make a copy of the data, so changes to the original will also affect the wrapper. + * Side affect is no extra memory is needed. + */ + public static + ByteArrayWrapper wrap(byte[] data) { + if (data == null) { + return null; + } + return new ByteArrayWrapper(data, false); + } + + public static + ByteArrayWrapper wrap(String data) { + if (data == null) { + return null; + } + + byte[] bytes = data.getBytes(UTF_8); + + SHA256Digest digest = new SHA256Digest(); + digest.update(bytes, 0, bytes.length); + byte[] hashBytes = new byte[digest.getDigestSize()]; + digest.doFinal(hashBytes, 0); + + return ByteArrayWrapper.wrap(hashBytes); + } + + public + byte[] getBytes() { return this.data; } @Override - public boolean equals(Object other) { - if (!(other instanceof ByteArrayWrapper)) { - return false; - } - - // CANNOT be null, so we don't have to null check! - return Arrays.equals(this.data, ((ByteArrayWrapper) other).data); - } - - @Override - public int hashCode() { + public + int hashCode() { // might be null for a thread because it's stale. who cares, get the value again Integer hashCode = this.hashCode; if (hashCode == null) { @@ -87,7 +117,19 @@ public final class ByteArrayWrapper { } @Override - public String toString() { + public + boolean equals(Object other) { + if (!(other instanceof ByteArrayWrapper)) { + return false; + } + + // CANNOT be null, so we don't have to null check! + return Arrays.equals(this.data, ((ByteArrayWrapper) other).data); + } + + @Override + public + String toString() { return "ByteArrayWrapper " + java.util.Arrays.toString(this.data); } -} \ No newline at end of file +} diff --git a/Dorkbox-Util/src/dorkbox/util/crypto/serialization/EccPublicKeySerializer.java b/Dorkbox-Util/src/dorkbox/util/crypto/serialization/EccPublicKeySerializer.java index 0825610..d9ccf26 100644 --- a/Dorkbox-Util/src/dorkbox/util/crypto/serialization/EccPublicKeySerializer.java +++ b/Dorkbox-Util/src/dorkbox/util/crypto/serialization/EccPublicKeySerializer.java @@ -1,29 +1,31 @@ package dorkbox.util.crypto.serialization; -import java.math.BigInteger; - -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.crypto.params.ECPublicKeyParameters; -import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; - import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; /** - * Only public keys are ever sent across the wire. + * Only public keys are ever sent across the wire. */ -public class EccPublicKeySerializer extends Serializer { +public +class EccPublicKeySerializer extends Serializer { @Override - public void write(Kryo kryo, Output output, ECPublicKeyParameters key) { + public + void write(Kryo kryo, Output output, ECPublicKeyParameters key) { write(output, key); } - public static void write(Output output, ECPublicKeyParameters key) { + public static + void write(Output output, ECPublicKeyParameters key) { byte[] bytes; int length; @@ -50,12 +52,13 @@ public class EccPublicKeySerializer extends Serializer { @SuppressWarnings("rawtypes") @Override - public ECPublicKeyParameters read(Kryo kryo, Input input, Class type) { - ECPublicKeyParameters ecPublicKeyParameters = read(input); - return ecPublicKeyParameters; + public + ECPublicKeyParameters read(Kryo kryo, Input input, Class type) { + return read(input); } - public static ECPublicKeyParameters read(Input input) { + public static + ECPublicKeyParameters read(Input input) { byte[] bytes; int length; @@ -88,7 +91,6 @@ public class EccPublicKeySerializer extends Serializer { input.readBytes(bytes, 0, length); ECPoint Q = curve.decodePoint(bytes); - ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(Q, ecDomainParameters); - return ecPublicKeyParameters; + return new ECPublicKeyParameters(Q, ecDomainParameters); } } diff --git a/Dorkbox-Util/src/dorkbox/util/database/DB_Server.java b/Dorkbox-Util/src/dorkbox/util/database/DB_Server.java new file mode 100644 index 0000000..03e27ae --- /dev/null +++ b/Dorkbox-Util/src/dorkbox/util/database/DB_Server.java @@ -0,0 +1,116 @@ +package dorkbox.util.database; + +import dorkbox.util.bytes.ByteArrayWrapper; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; + +import java.util.Arrays; + +public +class DB_Server { + /** + * Address 0.0.0.0/32 may be used as a source address for this host on this network. + */ + public static final ByteArrayWrapper IP_0_0_0_0 = ByteArrayWrapper.wrap(new byte[] {0, 0, 0, 0}); + + // salt + IP address is used for equals! + private byte[] ipAddress; + private byte[] salt; + + private ECPrivateKeyParameters privateKey; + private ECPublicKeyParameters publicKey; + + // must have empty constructor + public + DB_Server() { + } + + public + byte[] getAddress() { + if (this.ipAddress == null) { + return null; + } + return this.ipAddress; + } + + public + void setAddress(byte[] ipAddress) { + this.ipAddress = ipAddress; + } + + public + byte[] getSalt() { + return this.salt; + } + + public + void setSalt(byte[] salt) { + this.salt = salt; + } + + + public + ECPrivateKeyParameters getPrivateKey() { + return this.privateKey; + } + + public + void setPrivateKey(ECPrivateKeyParameters privateKey) { + this.privateKey = privateKey; + } + + + public + ECPublicKeyParameters getPublicKey() { + return this.publicKey; + } + + public + void setPublicKey(ECPublicKeyParameters publicKey) { + this.publicKey = publicKey; + } + + @Override + public + int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (this.ipAddress == null ? 0 : Arrays.hashCode(this.ipAddress)); + return result; + } + + @Override + public + boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DB_Server other = (DB_Server) obj; + if (this.ipAddress == null) { + if (other.ipAddress != null) { + return false; + } + } + else if (!Arrays.equals(this.ipAddress, other.ipAddress)) { + return false; + } + return Arrays.equals(this.salt, other.salt); + } + + @Override + public + String toString() { + byte[] bytes = this.ipAddress; + if (bytes != null) { + return "DB_Server " + Arrays.toString(bytes); + } + + return "DB_Server [no-ip-set]"; + } +} diff --git a/Dorkbox-Util/src/dorkbox/util/database/DatabaseStorage.java b/Dorkbox-Util/src/dorkbox/util/database/DatabaseStorage.java new file mode 100644 index 0000000..01689cf --- /dev/null +++ b/Dorkbox-Util/src/dorkbox/util/database/DatabaseStorage.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 dorkbox, llc + * + * Licensed 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. + */ +package dorkbox.util.database; + +import dorkbox.util.bytes.ByteArrayWrapper; + +/** + * A list of all of the keys used by the storage database + */ +public +class DatabaseStorage { + public static final ByteArrayWrapper SERVERS = ByteArrayWrapper.wrap("servers"); + public static final ByteArrayWrapper ROOT = ByteArrayWrapper.wrap("root"); + public static final ByteArrayWrapper USERS = ByteArrayWrapper.wrap("users"); + public static final ByteArrayWrapper ADMIN_HASH = ByteArrayWrapper.wrap("adminHash"); + public static final ByteArrayWrapper FILES = ByteArrayWrapper.wrap("files"); + public static final ByteArrayWrapper GENERIC = ByteArrayWrapper.wrap("generic"); + + +} diff --git a/Dorkbox-Util/src/dorkbox/util/properties/PropertiesProvider.java b/Dorkbox-Util/src/dorkbox/util/properties/PropertiesProvider.java index 8acf140..876afed 100644 --- a/Dorkbox-Util/src/dorkbox/util/properties/PropertiesProvider.java +++ b/Dorkbox-Util/src/dorkbox/util/properties/PropertiesProvider.java @@ -25,17 +25,21 @@ import java.util.Properties; import dorkbox.util.FileUtil; -public class PropertiesProvider { +@SuppressWarnings("unused") +public +class PropertiesProvider { private String comments = "Settings and configuration file. Strings must be escape formatted!"; private final Properties properties = new SortedProperties(); private final File propertiesFile; - public PropertiesProvider(String propertiesFile) { + public + PropertiesProvider(String propertiesFile) { this(new File(propertiesFile)); } - public PropertiesProvider(File propertiesFile) { + public + PropertiesProvider(File propertiesFile) { if (propertiesFile == null) { throw new NullPointerException("propertiesFile"); } @@ -43,8 +47,10 @@ public class PropertiesProvider { propertiesFile = FileUtil.normalize(propertiesFile); // make sure the parent dir exists... File parentFile = propertiesFile.getParentFile(); - if (parentFile != null) { - parentFile.mkdirs(); + if (parentFile != null && !parentFile.exists()) { + if (!parentFile.mkdirs()) { + throw new RuntimeException("Unable to create directories for: " + propertiesFile); + } } this.propertiesFile = propertiesFile; @@ -52,11 +58,13 @@ public class PropertiesProvider { _load(); } - public void setComments(String comments) { + public + void setComments(String comments) { this.comments = comments; } - private final void _load() { + private + void _load() { if (!this.propertiesFile.canRead() || !this.propertiesFile.exists()) { // in this case, our properties file doesn't exist yet... create one! _save(); @@ -77,7 +85,8 @@ public class PropertiesProvider { } - private final void _save() { + private + void _save() { try { FileOutputStream fos = new FileOutputStream(this.propertiesFile); this.properties.store(fos, this.comments); @@ -95,18 +104,21 @@ public class PropertiesProvider { } - public synchronized final void remove(final String key) { + public final synchronized + void remove(final String key) { this.properties.remove(key); _save(); } - public synchronized final void save(final String key, Object value) { + @SuppressWarnings("AutoBoxing") + public final synchronized + void save(final String key, Object value) { if (key == null || value == null) { return; } if (value instanceof Color) { - value = ((Color)value).getRGB(); + value = ((Color) value).getRGB(); } this.properties.setProperty(key, value.toString()); @@ -114,8 +126,9 @@ public class PropertiesProvider { _save(); } - @SuppressWarnings("unchecked") - public synchronized T get(String key, Class clazz) { + @SuppressWarnings({"unchecked", "AutoUnboxing"}) + public synchronized + T get(String key, Class clazz) { if (key == null || clazz == null) { return null; } @@ -146,7 +159,8 @@ public class PropertiesProvider { } @Override - public String toString() { + public + String toString() { return "PropertiesProvider [" + this.propertiesFile + "]"; } } diff --git a/Dorkbox-Util/src/dorkbox/util/storage/DiskStorage.java b/Dorkbox-Util/src/dorkbox/util/storage/DiskStorage.java index 751ef0b..1ca211e 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/DiskStorage.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/DiskStorage.java @@ -35,7 +35,7 @@ import java.util.concurrent.locks.ReentrantLock; */ @SuppressWarnings("unused") public -class DiskStorage implements DiskStorageIfface { +class DiskStorage implements Storage { private final DelayTimer timer; private final ByteArrayWrapper defaultKey; private final StorageBase storage; @@ -51,30 +51,35 @@ class DiskStorage implements DiskStorageIfface { * Creates or opens a new database file. */ protected - DiskStorage(File storageFile, SerializationManager serializationManager) throws IOException { + DiskStorage(File storageFile, SerializationManager serializationManager, final boolean readOnly) throws IOException { this.storage = new StorageBase(storageFile, serializationManager); this.defaultKey = ByteArrayWrapper.wrap(""); - this.timer = new DelayTimer("Storage Writer", false, new DelayTimer.Callback() { - @Override - public - void execute() { - Map actions = DiskStorage.this.actionMap; + if (readOnly) { + this.timer = null; + } + else { + this.timer = new DelayTimer("Storage Writer", false, new DelayTimer.Callback() { + @Override + public + void execute() { + Map actions = DiskStorage.this.actionMap; - ReentrantLock actionLock2 = DiskStorage.this.actionLock; + ReentrantLock actionLock2 = DiskStorage.this.actionLock; - try { - actionLock2.lock(); + try { + actionLock2.lock(); - // do a fast swap on the actionMap. - DiskStorage.this.actionMap = new ConcurrentHashMap(); - } finally { - actionLock2.unlock(); + // do a fast swap on the actionMap. + DiskStorage.this.actionMap = new ConcurrentHashMap(); + } finally { + actionLock2.unlock(); + } + + DiskStorage.this.storage.doActionThings(actions); } - - DiskStorage.this.storage.doActionThings(actions); - } - }); + }); + } this.isOpen.set(true); } @@ -95,7 +100,9 @@ class DiskStorage implements DiskStorageIfface { // flush actions // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + if (timer != null) { + this.timer.delay(0L); + } return this.storage.size(); } @@ -281,10 +288,12 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - action(key, object); + if (timer != null) { + action(key, object); - // timer action runs on TIMER thread, not this thread - this.timer.delay(this.milliSeconds); + // timer action runs on TIMER thread, not this thread + this.timer.delay(this.milliSeconds); + } } /** @@ -300,10 +309,12 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - action(this.defaultKey, object); + if (timer != null) { + action(this.defaultKey, object); - // timer action runs on TIMER thread, not this thread - this.timer.delay(this.milliSeconds); + // timer action runs on TIMER thread, not this thread + this.timer.delay(this.milliSeconds); + } } /** @@ -321,9 +332,13 @@ class DiskStorage implements DiskStorageIfface { ByteArrayWrapper wrap = ByteArrayWrapper.wrap(key); // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); - - return this.storage.delete(wrap); + if (timer != null) { + this.timer.delay(0L); + return this.storage.delete(wrap); + } + else { + return false; + } } /** @@ -331,12 +346,16 @@ class DiskStorage implements DiskStorageIfface { */ void close() { // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + if (timer != null) { + this.timer.delay(0L); + } // have to "close" it after we run the timer! this.isOpen.set(false); - this.storage.close(); + if (timer != null) { + this.storage.close(); + } } /** @@ -357,7 +376,9 @@ class DiskStorage implements DiskStorageIfface { public final long getFileSize() { // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + if (timer != null) { + this.timer.delay(0L); + } return this.storage.getFileSize(); } @@ -372,7 +393,12 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - return this.timer.isWaiting(); + if (timer != null) { + return this.timer.isWaiting(); + } + else { + return false; + } } /** @@ -457,7 +483,9 @@ class DiskStorage implements DiskStorageIfface { } // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + if (timer != null) { + this.timer.delay(0L); + } } /** @@ -472,10 +500,11 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - action(ByteArrayWrapper.wrap(key), object); - // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + if (timer != null) { + action(ByteArrayWrapper.wrap(key), object); + this.timer.delay(0L); + } } /** @@ -490,10 +519,13 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - action(ByteArrayWrapper.wrap(key), object); + if (timer != null) { + action(ByteArrayWrapper.wrap(key), object); + + // timer action runs on THIS thread, not timer thread + this.timer.delay(0L); + } - // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); } /** @@ -508,9 +540,11 @@ class DiskStorage implements DiskStorageIfface { throw new RuntimeException("Unable to act on closed storage"); } - action(key, object); + if (timer != null) { + action(key, object); - // timer action runs on THIS thread, not timer thread - this.timer.delay(0L); + // timer action runs on THIS thread, not timer thread + this.timer.delay(0L); + } } } diff --git a/Dorkbox-Util/src/dorkbox/util/storage/MemoryStorage.java b/Dorkbox-Util/src/dorkbox/util/storage/MemoryStorage.java index 39054d0..e730ce5 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/MemoryStorage.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/MemoryStorage.java @@ -10,13 +10,14 @@ import java.util.concurrent.ConcurrentHashMap; * */ public -class MemoryStorage implements DiskStorageIfface { +class MemoryStorage implements Storage { private final ConcurrentHashMap storage; private final ByteArrayWrapper defaultKey; private int version; - private - MemoryStorage() throws IOException { + + public + MemoryStorage() { this.storage = new ConcurrentHashMap(); this.defaultKey = ByteArrayWrapper.wrap(""); } @@ -122,6 +123,7 @@ class MemoryStorage implements DiskStorageIfface { final Object o = storage.get(key); if (o == null) { storage.put(key, data); + return data; } return (T) o; } diff --git a/Dorkbox-Util/src/dorkbox/util/storage/Metadata.java b/Dorkbox-Util/src/dorkbox/util/storage/Metadata.java index 7bb8db7..7bc2bd7 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/Metadata.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/Metadata.java @@ -263,7 +263,7 @@ class Metadata { T readData(SerializationManager serializationManager, InflaterInputStream inputStream) { Input input = new Input(inputStream, 1024); // read 1024 at a time @SuppressWarnings("unchecked") - T readObject = (T) serializationManager.readClassAndObject(input); + T readObject = (T) serializationManager.readFullClassAndObject(input); return readObject; } @@ -277,7 +277,7 @@ class Metadata { final DeflaterOutputStream outputStream) throws IOException { // HAVE TO LOCK BEFORE THIS IS CALLED! (AND FREE AFTERWARDS!) Output output = new Output(outputStream, 1024); // write 1024 at a time - serializationManager.writeClassAndObject(output, data); + serializationManager.writeFullClassAndObject(output, data); output.flush(); outputStream.flush(); // sync-flush is enabled, so the output stream will finish compressing data. diff --git a/Dorkbox-Util/src/dorkbox/util/storage/DiskStorageIfface.java b/Dorkbox-Util/src/dorkbox/util/storage/Storage.java similarity index 99% rename from Dorkbox-Util/src/dorkbox/util/storage/DiskStorageIfface.java rename to Dorkbox-Util/src/dorkbox/util/storage/Storage.java index 41330fe..1014a87 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/DiskStorageIfface.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/Storage.java @@ -9,7 +9,7 @@ import java.io.IOException; * */ public -interface DiskStorageIfface { +interface Storage { /** * Returns the number of objects in the database. */ diff --git a/Dorkbox-Util/src/dorkbox/util/storage/StorageBase.java b/Dorkbox-Util/src/dorkbox/util/storage/StorageBase.java index 0d647fe..3eaee71 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/StorageBase.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/StorageBase.java @@ -449,7 +449,7 @@ class StorageBase { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); OutputStream outputStream = new DeflaterOutputStream(byteArrayOutputStream, deflater); Output output = new Output(outputStream, 1024); // write 1024 at a time - kryo.writeClassAndObject(output, data); + kryo.writeFullClassAndObject(output, data); output.flush(); outputStream.flush(); diff --git a/Dorkbox-Util/src/dorkbox/util/storage/MakeStorage.java b/Dorkbox-Util/src/dorkbox/util/storage/Store.java similarity index 72% rename from Dorkbox-Util/src/dorkbox/util/storage/MakeStorage.java rename to Dorkbox-Util/src/dorkbox/util/storage/Store.java index cab5cf4..2ae864c 100644 --- a/Dorkbox-Util/src/dorkbox/util/storage/MakeStorage.java +++ b/Dorkbox-Util/src/dorkbox/util/storage/Store.java @@ -1,20 +1,22 @@ package dorkbox.util.storage; -import dorkbox.util.SerializationManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dorkbox.util.SerializationManager; + public -class MakeStorage { +class Store { private static final Logger logger = LoggerFactory.getLogger(DiskStorage.class); + @SuppressWarnings("SpellCheckingInspection") - private static final Map storages = new HashMap(1); + private static final Map storages = new HashMap(1); public static DiskMaker Disk() { @@ -32,7 +34,7 @@ class MakeStorage { public static void close(File file) { synchronized (storages) { - DiskStorageIfface storage = storages.get(file); + Storage storage = storages.get(file); if (storage != null) { if (storage instanceof DiskStorage) { final DiskStorage diskStorage = (DiskStorage) storage; @@ -50,18 +52,16 @@ class MakeStorage { * Closes the storage. */ public static - void close(DiskStorageIfface _storage) { + void close(Storage _storage) { synchronized (storages) { File file = _storage.getFile(); - DiskStorageIfface storage = storages.get(file); - if (storage != null) { - if (storage instanceof DiskStorage) { - final DiskStorage diskStorage = (DiskStorage) storage; - boolean isLastOne = diskStorage.decrementReference(); - if (isLastOne) { - diskStorage.close(); - storages.remove(file); - } + Storage storage = storages.get(file); + if (storage instanceof DiskStorage) { + final DiskStorage diskStorage = (DiskStorage) storage; + boolean isLastOne = diskStorage.decrementReference(); + if (isLastOne) { + diskStorage.close(); + storages.remove(file); } } } @@ -70,8 +70,8 @@ class MakeStorage { public static void shutdown() { synchronized (storages) { - Collection values = storages.values(); - for (DiskStorageIfface storage : values) { + Collection values = storages.values(); + for (Storage storage : values) { if (storage instanceof DiskStorage) { //noinspection StatementWithEmptyBody final DiskStorage diskStorage = (DiskStorage) storage; @@ -87,7 +87,7 @@ class MakeStorage { public static void delete(File file) { synchronized (storages) { - DiskStorageIfface remove = storages.remove(file); + Storage remove = storages.remove(file); if (remove != null && remove instanceof DiskStorage) { ((DiskStorage) remove).close(); } @@ -97,7 +97,7 @@ class MakeStorage { } public static - void delete(DiskStorageIfface storage) { + void delete(Storage storage) { File file = storage.getFile(); delete(file); } @@ -107,6 +107,7 @@ class MakeStorage { class DiskMaker { private File file; private SerializationManager serializationManager; + private boolean readOnly; public DiskMaker file(File file) { @@ -121,15 +122,15 @@ class MakeStorage { } public - DiskStorageIfface make() { - if (file == null) { + Storage make() { + if (this.file == null) { throw new IllegalArgumentException("file cannot be null!"); } // if we load from a NEW storage at the same location as an ALREADY EXISTING storage, // without saving the existing storage first --- whoops! synchronized (storages) { - DiskStorageIfface storage = storages.get(file); + Storage storage = storages.get(this.file); if (storage != null) { if (storage instanceof DiskStorage) { @@ -141,13 +142,13 @@ class MakeStorage { ((DiskStorage) storage).increaseReference(); } else { - throw new RuntimeException("Unable to change storage types for: " + file); + throw new RuntimeException("Unable to change storage types for: " + this.file); } } else { try { - storage = new DiskStorage(file, serializationManager); - storages.put(file, storage); + storage = new DiskStorage(this.file, this.serializationManager, this.readOnly); + storages.put(this.file, storage); } catch (IOException e) { logger.error("Unable to open storage", e); } @@ -156,21 +157,20 @@ class MakeStorage { return storage; } } + + public + DiskMaker readOnly() { + this.readOnly = true; + return this; + } } public static class MemoryMaker { - private SerializationManager serializationManager; - public - MemoryMaker serializer(SerializationManager serializationManager) { - this.serializationManager = serializationManager; - return this; - } - - MemoryStorage make() { - return null; + MemoryStorage make() throws IOException { + return new MemoryStorage(); } } } diff --git a/Dorkbox-Util/test/dorkbox/util/StorageTest.java b/Dorkbox-Util/test/dorkbox/util/StorageTest.java index c160077..efe600f 100644 --- a/Dorkbox-Util/test/dorkbox/util/StorageTest.java +++ b/Dorkbox-Util/test/dorkbox/util/StorageTest.java @@ -1,12 +1,11 @@ package dorkbox.util; import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Registration; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; -import dorkbox.util.storage.DiskStorageIfface; -import dorkbox.util.storage.MakeStorage; +import dorkbox.util.storage.Storage; +import dorkbox.util.storage.Store; import io.netty.buffer.ByteBuf; import org.junit.*; import org.junit.runners.MethodSorters; @@ -23,19 +22,6 @@ class StorageTest { private static final SerializationManager manager = new SerializationManager() { Kryo kryo = new Kryo(); - @Override - public - boolean setReferences(final boolean references) { - kryo.setReferences(references); - return false; - } - - @Override - public - void setRegistrationRequired(final boolean registrationRequired) { - kryo.setRegistrationRequired(registrationRequired); - } - @Override public void register(final Class clazz) { @@ -50,16 +36,15 @@ class StorageTest { @Override public - Registration register(final Class type, final Serializer serializer, final int id) { + void register(final Class type, final Serializer serializer, final int id) { kryo.register(type, serializer, id); - return null; } @Override public void write(final ByteBuf buffer, final Object message) { final Output output = new Output(); - writeClassAndObject(output, message); + writeFullClassAndObject(output, message); buffer.writeBytes(output.getBuffer()); } @@ -69,7 +54,7 @@ class StorageTest { final Input input = new Input(); buffer.readBytes(input.getBuffer()); - final Object o = readClassAndObject(input); + final Object o = readFullClassAndObject(input); buffer.skipBytes(input.position()); return o; @@ -77,15 +62,26 @@ class StorageTest { @Override public - void writeClassAndObject(final Output output, final Object value) { + void writeFullClassAndObject(final Output output, final Object value) { kryo.writeClassAndObject(output, value); } @Override public - Object readClassAndObject(final Input input) { + Object readFullClassAndObject(final Input input) { return kryo.readClassAndObject(input); } + + @Override + public + Kryo take() throws InterruptedException { + return kryo; + } + + @Override + public + void release(final Kryo kryo) { + } }; static @@ -96,23 +92,23 @@ class StorageTest { @Before public void deleteDB() { - MakeStorage.delete(TEST_DB); + Store.delete(TEST_DB); } @After public void delete2DB() { - MakeStorage.delete(TEST_DB); + Store.delete(TEST_DB); } @Test public void testCreateDB() throws IOException { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); int numberOfRecords1 = storage.size(); long size1 = storage.getFileSize(); @@ -120,19 +116,19 @@ class StorageTest { Assert.assertEquals("count is not correct", numberOfRecords1, 0); Assert.assertEquals("size is not correct", size1, 208L); // NOTE this will change based on the data size added! - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); int numberOfRecords2 = storage.size(); long size2 = storage.getFileSize(); Assert.assertEquals("Record count is not the same", numberOfRecords1, numberOfRecords2); Assert.assertEquals("size is not the same", size1, size2); - MakeStorage.close(storage); + Store.close(storage); } @@ -142,19 +138,19 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { add(storage, i); } - MakeStorage.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Store.close(storage); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String record1Data = createData(i); String readRecord = readRecord(storage, i); @@ -162,7 +158,7 @@ class StorageTest { Assert.assertEquals("Object is not the same", record1Data, readRecord); } - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -175,10 +171,10 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { log("adding record " + i + "..."); String addRecord = createData(i); @@ -189,12 +185,12 @@ class StorageTest { Assert.assertEquals("Object is not the same", addRecord, readData); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); String dataCheck = createData(total - 1); log("reading record " + (total - 1) + "..."); @@ -208,7 +204,7 @@ class StorageTest { Assert.assertEquals("count is not correct", numberOfRecords1, 1); Assert.assertEquals("size is not correct", size1, 235L); // NOTE this will change based on the data size added! - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -221,10 +217,10 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { add(storage, i); } @@ -241,12 +237,12 @@ class StorageTest { Assert.assertEquals("Object is not the same", record1Data, readRecord); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String dataCheck = createData(i); String readRecord = readRecord(storage, i); @@ -254,7 +250,7 @@ class StorageTest { Assert.assertEquals("Object is not the same", dataCheck, readRecord); } - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -267,10 +263,10 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { add(storage, i); } @@ -282,12 +278,12 @@ class StorageTest { Assert.assertEquals("Object is not the same", record1Data, readRecord); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String dataCheck = createData(i); String readRecord = readRecord(storage, i); @@ -295,7 +291,7 @@ class StorageTest { Assert.assertEquals("Object is not the same", dataCheck, readRecord); } - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -308,22 +304,22 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String addRecord = add(storage, i); String readRecord = readRecord(storage, i); Assert.assertEquals("Object is not the same", addRecord, readRecord); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String dataCheck = createData(i); String readRecord = readRecord(storage, i); @@ -342,17 +338,17 @@ class StorageTest { storage.load(createKey, data2); Assert.assertEquals("Object is not the same", data, data2); - MakeStorage.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Store.close(storage); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); data2 = new Data(); storage.load(createKey, data2); Assert.assertEquals("Object is not the same", data, data2); - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -366,22 +362,22 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String addRecord = add(storage, i); String readRecord = readRecord(storage, i); Assert.assertEquals("Object is not the same", addRecord, readRecord); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String dataCheck = createData(i); String readRecord = readRecord(storage, i); @@ -408,12 +404,12 @@ class StorageTest { Assert.assertEquals("Object is not the same", dataCheck, addRecord); - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); // check 9 again readRecord = readRecord(storage, 9); @@ -437,58 +433,58 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String addRecord = add(storage, i); String readRecord = readRecord(storage, i); Assert.assertEquals("Object is not the same", addRecord, readRecord); } - MakeStorage.close(storage); + Store.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); String updateRecord = updateRecord(storage, 3, createData(3) + "new"); String readRecord = readRecord(storage, 3); Assert.assertEquals("Object is not the same", updateRecord, readRecord); - MakeStorage.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Store.close(storage); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); readRecord = readRecord(storage, 3); Assert.assertEquals("Object is not the same", updateRecord, readRecord); updateRecord = updateRecord(storage, 3, createData(3)); - MakeStorage.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Store.close(storage); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); readRecord = readRecord(storage, 3); Assert.assertEquals("Object is not the same", updateRecord, readRecord); - MakeStorage.close(storage); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Store.close(storage); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); updateRecord = updateRecord(storage, 0, createData(0) + "new"); readRecord = readRecord(storage, 0); Assert.assertEquals("Object is not the same", updateRecord, readRecord); - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -502,10 +498,10 @@ class StorageTest { int total = 100; try { - DiskStorageIfface storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + Storage storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { Data data = new Data(); makeData(data); @@ -513,15 +509,15 @@ class StorageTest { storage.put(createKey, data); } - MakeStorage.close(storage); + Store.close(storage); Data data = new Data(); makeData(data); - storage = MakeStorage.Disk() - .file(TEST_DB) - .serializer(manager) - .make(); + storage = Store.Disk() + .file(TEST_DB) + .serializer(manager) + .make(); for (int i = 0; i < total; i++) { String createKey = createKey(i); @@ -529,7 +525,7 @@ class StorageTest { storage.load(createKey, data2); Assert.assertEquals("Object is not the same", data, data2); } - MakeStorage.close(storage); + Store.close(storage); } catch (Exception e) { e.printStackTrace(); Assert.fail("Error!"); @@ -544,7 +540,7 @@ class StorageTest { } public static - String add(DiskStorageIfface storage, int number) throws IOException { + String add(Storage storage, int number) throws IOException { String record1Data = createData(number); String record1Key = createKey(number); @@ -554,7 +550,7 @@ class StorageTest { } public static - String readRecord(DiskStorageIfface storage, int number) throws ClassNotFoundException, IOException { + String readRecord(Storage storage, int number) throws ClassNotFoundException, IOException { String record1Key = createKey(number); log("reading record " + number + "..."); @@ -565,7 +561,7 @@ class StorageTest { } public static - void deleteRecord(DiskStorageIfface storage, int nNumber) throws ClassNotFoundException, IOException { + void deleteRecord(Storage storage, int nNumber) throws ClassNotFoundException, IOException { String record1Key = createKey(nNumber); log("deleting record " + nNumber + "..."); @@ -573,7 +569,7 @@ class StorageTest { } private static - String updateRecord(DiskStorageIfface storage, int number, String newData) throws IOException { + String updateRecord(Storage storage, int number, String newData) throws IOException { String record1Key = createKey(number); log("updating record " + number + "..."); diff --git a/Dorkbox-Util/test/dorkbox/util/UByteTest.java b/Dorkbox-Util/test/dorkbox/util/UByteTest.java index 682eb44..b23ea98 100644 --- a/Dorkbox-Util/test/dorkbox/util/UByteTest.java +++ b/Dorkbox-Util/test/dorkbox/util/UByteTest.java @@ -35,20 +35,13 @@ */ package dorkbox.util; -import static dorkbox.util.bytes.Unsigned.ubyte; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - +import dorkbox.util.bytes.UByte; import org.junit.Test; -import dorkbox.util.bytes.UByte; +import java.io.*; + +import static dorkbox.util.bytes.Unsigned.ubyte; +import static org.junit.Assert.*; public class UByteTest { @@ -163,4 +156,4 @@ public class UByteTest { assertEquals(expected, actual); // same value assertTrue(expected == actual); // identical objects } -} \ No newline at end of file +} diff --git a/Dorkbox-Util/test/dorkbox/util/UIntegerTest.java b/Dorkbox-Util/test/dorkbox/util/UIntegerTest.java index 8ed0c1d..c8f4aa5 100644 --- a/Dorkbox-Util/test/dorkbox/util/UIntegerTest.java +++ b/Dorkbox-Util/test/dorkbox/util/UIntegerTest.java @@ -1,26 +1,26 @@ /** * Copyright (c) 2011-2013, Lukas Eder, lukas.eder@gmail.com * All rights reserved. - * + *

* This software is licensed to you under the Apache License, Version 2.0 * (the "License"); You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + *

* . Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * + * list of conditions and the following disclaimer. + *

* . Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + *

* . Neither the name "jOOU" nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * + * used to endorse or promote products derived from this software without + * specific prior written permission. + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,39 +35,33 @@ */ package dorkbox.util; -import static dorkbox.util.bytes.Unsigned.uint; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - +import dorkbox.util.bytes.UInteger; import org.junit.Test; -import dorkbox.util.bytes.UInteger; +import java.io.*; -public class UIntegerTest { - private static final int CACHE_SIZE=256; - private static final int NEAR_MISS_OFFSET=4; +import static dorkbox.util.bytes.Unsigned.uint; +import static org.junit.Assert.*; + +public +class UIntegerTest { + private static final int CACHE_SIZE = 256; + private static final int NEAR_MISS_OFFSET = 4; @SuppressWarnings("deprecation") @Test - public void testValueOfLong() { - for(long l=01; l<=UInteger.MAX_VALUE; l<<=1) { - assertEquals(l , uint(l).longValue()); + public + void testValueOfLong() { + for (long l = 01; l <= UInteger.MAX_VALUE; l <<= 1) { + assertEquals(l, uint(l).longValue()); } } @SuppressWarnings("deprecation") @Test - public void testValueOfLongCachingShift() { - for(long l=01; l