org.modeshape.schematic.internal.document.BsonUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of modeshape-schematic Show documentation
Show all versions of modeshape-schematic Show documentation
API for storing JSON/BSON documents and JSON Schemas support
The newest version!
/*
* ModeShape (http://www.modeshape.org)
*
* 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 org.modeshape.schematic.internal.document;
import java.util.regex.Pattern;
import org.modeshape.schematic.document.Null;
import org.modeshape.schematic.document.ObjectId;
public class BsonUtils {
public static int regexFlagsFrom(String flags) {
if (flags == null)
return 0;
flags = flags.toLowerCase();
int value = 0;
for (int i = 0; i < flags.length(); i++) {
char c = flags.charAt(i);
switch (c) {
case 'i':
value |= Pattern.CASE_INSENSITIVE;
break;
case 'm':
value |= Pattern.MULTILINE;
break;
case 'd':
value |= Pattern.UNIX_LINES;
break;
case 'c':
value |= Pattern.CANON_EQ;
break;
case 's':
value |= Pattern.DOTALL;
break;
case 't':
value |= Pattern.LITERAL;
break;
case 'u':
value |= Pattern.UNICODE_CASE;
break;
case 'x':
value |= Pattern.COMMENTS;
break;
case 'g': // global flag
// ignore
break;
default:
throw new IllegalArgumentException("unrecognized regex flag '" + c + "'");
}
}
return value;
}
public static String regexFlagsFor(Pattern pattern) {
return regexFlagsFor(pattern.flags());
}
public static String regexFlagsFor(int flags) {
if (flags == 0)
return "";
StringBuilder sb = new StringBuilder();
// Order of characters is important here
if ((flags & Pattern.CANON_EQ) == Pattern.CANON_EQ)
sb.append('c');
if ((flags & Pattern.UNIX_LINES) == Pattern.UNIX_LINES)
sb.append('d');
if ((flags & Pattern.CASE_INSENSITIVE) == Pattern.CASE_INSENSITIVE)
sb.append('i');
if ((flags & Pattern.MULTILINE) == Pattern.MULTILINE)
sb.append('m');
if ((flags & Pattern.DOTALL) == Pattern.DOTALL)
sb.append('s');
if ((flags & Pattern.LITERAL) == Pattern.LITERAL)
sb.append('t');
if ((flags & Pattern.UNICODE_CASE) == Pattern.UNICODE_CASE)
sb.append('u');
if ((flags & Pattern.COMMENTS) == Pattern.COMMENTS)
sb.append('x');
return sb.toString();
}
/**
* The BSON specification (or rather the MongoDB
* documentation) defines the structure of this data:
*
* "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte
* machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored
* big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure a mostly
* increasing order."
*
*
* @param bytes
* @return the ObjectId
*/
public static ObjectId readObjectId(byte[] bytes) {
// Compute the values in big-endian ...
int time = ((bytes[0] & 0xff) << 24) + ((bytes[1] & 0xff) << 16) + ((bytes[2] & 0xff) << 8)
+ ((bytes[3] & 0xff) << 0);
int machine = ((bytes[4] & 0xff) << 16) + ((bytes[5] & 0xff) << 8) + ((bytes[6] & 0xff) << 0);
int process = ((bytes[7] & 0xff) << 8) + ((bytes[8] & 0xff) << 0);
int inc = ((bytes[9] & 0xff) << 16) + ((bytes[10] & 0xff) << 8) + ((bytes[11] & 0xff) << 0);
// Create the value object ...
return new ObjectId(time, machine, process, inc);
}
/**
* Read the {@link ObjectId} from the hexadecimal string representation of the ObjectId.
*
* @param bytesInHex
* the hexadecimal identifier
* @return the ObjectId
*/
public static ObjectId readObjectId(String bytesInHex) {
byte[] bytes = new byte[12];
assert bytesInHex.length() == 24;
for (int i = 0, index = 0; i != 12; ++i) {
String hexChar = bytesInHex.substring(index, index += 2);
bytes[i] = (byte) Integer.parseInt(hexChar, 16);
}
return readObjectId(bytes);
}
/**
* Write the 12-byte representation of the ObjectId per the BSON specification (or rather the MongoDB documentation).
*
* @param id
* the ObjectId; may not be null
* @param b
* the bytes into which the object ID should be written
*/
public static void writeObjectId(ObjectId id, byte[] b) {
int time = id.getTime();
int machine = id.getMachine();
int process = id.getProcess();
int inc = id.getInc();
b[0] = (byte) ((time >>> 24) & 0xFF);
b[1] = (byte) ((time >>> 16) & 0xFF);
b[2] = (byte) ((time >>> 8) & 0xFF);
b[3] = (byte) ((time >>> 0) & 0xFF);
b[4] = (byte) ((machine >>> 16) & 0xFF);
b[5] = (byte) ((machine >>> 8) & 0xFF);
b[6] = (byte) ((machine >>> 0) & 0xFF);
b[7] = (byte) ((process >>> 8) & 0xFF);
b[8] = (byte) ((process >>> 0) & 0xFF);
b[9] = (byte) ((inc >>> 16) & 0xFF);
b[10] = (byte) ((inc >>> 8) & 0xFF);
b[11] = (byte) ((inc >>> 0) & 0xFF);
}
public static boolean valuesAreEqual(Object thisValue, Object thatValue) {
if (thisValue == thatValue) {
return true;
}
if (thisValue == null || thisValue instanceof Null) {
return Null.matches(thatValue);
}
if (thisValue instanceof Number && thatValue instanceof Number) {
// Need to handle float vs. doubles
Number thisNumber = (Number) thisValue;
Number thatNumber = (Number) thatValue;
return thisNumber.doubleValue() == thatNumber.doubleValue();
}
if (thisValue instanceof Pattern && thatValue instanceof Pattern) {
// java.util.regex.Pattern does not implement equals!!
Pattern thisPattern = (Pattern) thisValue;
Pattern thatPattern = (Pattern) thatValue;
return thisPattern.pattern().equals(thatPattern.pattern()) && thisPattern.flags() == thatPattern.flags();
}
return thisValue.equals(thatValue);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy