All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bson.BSON Maven / Gradle / Ivy

There is a newer version: 5.10
Show newest version
// BSON.java

/**
 * Copyright (C) 2008 10gen Inc.
 * 

* 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.bson; import org.bson.types.*; import org.bson.util.ClassMap; import java.math.BigDecimal; import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Logger; import java.util.regex.Pattern; /** * Global setting for BSON usage. */ public class BSON { static final Logger LOGGER = Logger.getLogger("org.bson.BSON"); // ---- basics ---- public static final byte EOO = 0; public static final byte NUMBER = 1; public static final byte STRING = 2; public static final byte OBJECT = 3; public static final byte ARRAY = 4; public static final byte BINARY = 5; public static final byte UNDEFINED = 6; public static final byte OID = 7; public static final byte BOOLEAN = 8; public static final byte DATE = 9; public static final byte NULL = 10; public static final byte REGEX = 11; public static final byte REF = 12; public static final byte CODE = 13; public static final byte SYMBOL = 14; public static final byte CODE_W_SCOPE = 15; public static final byte NUMBER_INT = 16; public static final byte TIMESTAMP = 17; public static final byte NUMBER_LONG = 18; public static final byte NUMBER_DECIMAL = 100; public static final byte MINKEY = -1; public static final byte MAXKEY = 127; // --- binary types /* these are binary types so the format would look like <...> */ public static final byte B_GENERAL = 0; public static final byte B_FUNC = 1; public static final byte B_BINARY = 2; public static final byte B_UUID = 3; // ---- regular expression handling ---- /** Converts a string of regular expression flags from the database in Java regular * expression flags. * @param flags flags from database * @return the Java flags */ public static int regexFlags(String flags) { int fint = 0; if (flags == null || flags.length() == 0) return fint; flags = flags.toLowerCase(); for (int i = 0; i < flags.length(); i++) { RegexFlag flag = RegexFlag.getByCharacter(flags.charAt(i)); if (flag != null) { fint |= flag.javaFlag; if (flag.unsupported != null) _warnUnsupportedRegex(flag.unsupported); } else { throw new IllegalArgumentException("unrecognized flag [" + flags.charAt(i) + "] " + (int) flags.charAt(i)); } } return fint; } public static int regexFlag(char c) { RegexFlag flag = RegexFlag.getByCharacter(c); if (flag == null) throw new IllegalArgumentException("unrecognized flag [" + c + "]"); if (flag.unsupported != null) { _warnUnsupportedRegex(flag.unsupported); return 0; } return flag.javaFlag; } /** Converts Java regular expression flags into a string of flags for the database * @param flags Java flags * @return the flags for the database */ public static String regexFlags(int flags) { StringBuilder buf = new StringBuilder(); for (RegexFlag flag : RegexFlag.values()) { if ((flags & flag.javaFlag) > 0) { buf.append(flag.flagChar); flags -= flag.javaFlag; } } if (flags > 0) throw new IllegalArgumentException("some flags could not be recognized."); return buf.toString(); } private static enum RegexFlag { CANON_EQ(Pattern.CANON_EQ, 'c', "Pattern.CANON_EQ"), UNIX_LINES(Pattern.UNIX_LINES, 'd', "Pattern.UNIX_LINES"), GLOBAL(GLOBAL_FLAG, 'g', null), CASE_INSENSITIVE(Pattern.CASE_INSENSITIVE, 'i', null), MULTILINE(Pattern.MULTILINE, 'm', null), DOTALL(Pattern.DOTALL, 's', "Pattern.DOTALL"), LITERAL(Pattern.LITERAL, 't', "Pattern.LITERAL"), UNICODE_CASE(Pattern.UNICODE_CASE, 'u', "Pattern.UNICODE_CASE"), COMMENTS(Pattern.COMMENTS, 'x', null); private static final Map byCharacter = new HashMap(); static { for (RegexFlag flag : values()) { byCharacter.put(flag.flagChar, flag); } } public static RegexFlag getByCharacter(char ch) { return byCharacter.get(ch); } public final int javaFlag; public final char flagChar; public final String unsupported; RegexFlag(int f, char ch, String u) { javaFlag = f; flagChar = ch; unsupported = u; } } private static void _warnUnsupportedRegex(String flag) { LOGGER.info("flag " + flag + " not supported by db."); } private static final int GLOBAL_FLAG = 256; // --- (en|de)coding hooks ----- /** * check has decode hooks or not. * @return true for having, and false for not */ public static boolean hasDecodeHooks() { return _decodeHooks; } /** * Add a encoding hook for transforming a instance of class c into a * instance of the BSON supported classes. *

     *  Usage:
     *  public void testEncodeDecodeHook() {
     *       BSON.addEncodingHook(GregorianCalendar.class, new Transformer() {
     *          public Object transform(Object o) {
     *               return ((GregorianCalendar)o).getTime();
     *           }
     *       });
     *
     *       BSON.addDecodingHook(Date.class, new Transformer() {
     *           public Object transform(Object o) {
     *               Calendar calendar = new GregorianCalendar();
     *               calendar.setTime((Date)o);
     *               return calendar;
     *           }
     *       });
     *
     *       Calendar calendar = new GregorianCalendar();
     *       calendar.set(2015, 0,1);
     *       BSONObject object = new BasicBSONObject();
     *       object.put("calendar", calendar);
     *       cl.insert(object);
     *       DBCursor cursor = cl.query();
     *       while(cursor.hasNext()) {
     *           BSONObject record = cursor.getNext();
     *           System.out.println("record is: " + record);
     *           Object resultObject = record.get("calendar");
     *           calendar.equals(resultObject);
     *           Assert.assertTrue(resultObject instanceof GregorianCalendar);
     *       }
     *   }
     * 
* @param c the class of the instance which is going to be transformed. * @param t the Transformer, user should defines the transform rule. */ public static void addEncodingHook(Class c, Transformer t) { _encodeHooks = true; List l = _encodingHooks.get(c); if (l == null) { l = new CopyOnWriteArrayList(); _encodingHooks.put(c, l); } l.add(t); } /** * Add a decoding hook for transforming a instance of BSON supported classes into a * instance of class c. *
     *  Usage:
     *  public void testEncodeDecodeHook() {
     *       BSON.addEncodingHook(GregorianCalendar.class, new Transformer() {
     *          public Object transform(Object o) {
     *               return ((GregorianCalendar)o).getTime();
     *           }
     *       });
     *
     *       BSON.addDecodingHook(Date.class, new Transformer() {
     *           public Object transform(Object o) {
     *               Calendar calendar = new GregorianCalendar();
     *               calendar.setTime((Date)o);
     *               return calendar;
     *           }
     *       });
     *
     *       Calendar calendar = new GregorianCalendar();
     *       calendar.set(2015, 0,1);
     *       BSONObject object = new BasicBSONObject();
     *       object.put("calendar", calendar);
     *       cl.insert(object);
     *       DBCursor cursor = cl.query();
     *       while(cursor.hasNext()) {
     *           BSONObject record = cursor.getNext();
     *           System.out.println("record is: " + record);
     *           Object resultObject = record.get("calendar");
     *           calendar.equals(resultObject);
     *           Assert.assertTrue(resultObject instanceof GregorianCalendar);
     *       }
     *   }
     * 
* @param c the class of the instance which is going to be transformed into. * @param t the Transformer, user should defines the transform rule. */ public static void addDecodingHook(Class c, Transformer t) { _decodeHooks = true; List l = _decodingHooks.get(c); if (l == null) { l = new CopyOnWriteArrayList(); _decodingHooks.put(c, l); } l.add(t); } /** * Use the registered encoding hooks to transform the specific instance into the instance of BSON * supported classes. * @param o * @return */ public static Object applyEncodingHooks(Object o) { if (!_anyHooks()) return o; if (_encodingHooks.size() == 0 || o == null) return o; List l = _encodingHooks.get(o.getClass()); if (l != null) for (Transformer t : l) o = t.transform(o); return o; } /** * Use the registered decoding hooks to transform the instance of BSON supported classes into another * instance of user expect. * @param o * @return */ public static Object applyDecodingHooks(Object o) { if (!_anyHooks() || o == null) return o; List l = _decodingHooks.get(o.getClass()); if (l != null) for (Transformer t : l) o = t.transform(o); return o; } /** * Returns the encoding hook(s) associated with the specified class * @param c the specified class for getting it's registered encoding hook. * @return all the registered encoding hooks. */ public static List getEncodingHooks(Class c) { return _encodingHooks.get(c); } /** * Clears all encoding hooks. */ public static void clearEncodingHooks() { _encodeHooks = false; _encodingHooks.clear(); } /** * Remove all encoding hooks for a specific class. */ public static void removeEncodingHooks(Class c) { _encodingHooks.remove(c); } /** * Remove a specific encoding hook for a specific class. */ public static void removeEncodingHook(Class c, Transformer t) { getEncodingHooks(c).remove(t); } /** * Returns the decoding hook(s) associated with the specific class */ public static List getDecodingHooks(Class c) { return _decodingHooks.get(c); } /** * Clears all decoding hooks. */ public static void clearDecodingHooks() { _decodeHooks = false; _decodingHooks.clear(); } /** * Remove all decoding hooks for a specific class. */ public static void removeDecodingHooks(Class c) { _decodingHooks.remove(c); } /** * Remove a specific encoding hook for a specific class. */ public static void removeDecodingHook(Class c, Transformer t) { getDecodingHooks(c).remove(t); } /** * Remove all the hooks. */ public static void clearAllHooks() { clearEncodingHooks(); clearDecodingHooks(); } /** * Returns true if any encoding or decoding hooks are loaded. */ private static boolean _anyHooks() { return _encodeHooks || _decodeHooks; } private static boolean _encodeHooks = false; private static boolean _decodeHooks = false; static ClassMap> _encodingHooks = new ClassMap>(); static ClassMap> _decodingHooks = new ClassMap>(); static protected Charset _utf8 = Charset.forName("UTF-8"); // ----- static encode/_decode ----- /** * Encoding a BSONObject instance into bytes * @param o the instance of BSONObject. * @return the bytes. */ public static byte[] encode(BSONObject o) { BSONEncoder e = _staticEncoder.get(); try { return e.encode(o); } finally { e.done(); } } /** * Decode the bytes into a BSONObject instance. * @param b bytes to be decoded. * @return a BSONObject instance. */ public static BSONObject decode(byte[] b) { BSONDecoder d = _staticDecoder.get(); return d.readObject(b); } /** * Decode the bytes into a BSONObject instance. * @param b bytes to be decoded. * @param offset the start position. * @return a BSONObject instance. * */ public static BSONObject decode(byte[] b, int offset) { BSONDecoder d = _staticDecoder.get(); return d.readObject(b, offset); } static ThreadLocal _staticEncoder = new ThreadLocal() { protected BSONEncoder initialValue() { return new BasicBSONEncoder(); } }; static ThreadLocal _staticDecoder = new ThreadLocal() { protected BSONDecoder initialValue() { return new NewBSONDecoder(); } }; // --- coercing --- public static int toInt(Object o) { if (o == null) throw new NullPointerException("can't be null"); if (o instanceof Number) return ((Number) o).intValue(); if (o instanceof Boolean) return ((Boolean) o) ? 1 : 0; throw new IllegalArgumentException("can't convert: " + o.getClass().getName() + " to int"); } public static boolean IsBasicType(Object obj) { if (obj == null) return true; else if (obj.getClass().isPrimitive()) return true; else if (obj instanceof Date) return true; else if (obj instanceof Number) return true; else if (obj instanceof Character) return true; else if (obj instanceof String) return true; else if (obj instanceof ObjectId) return true; // else if (obj instanceof BSONObject) // return true; else if (obj instanceof Boolean) return true; else if (obj instanceof Pattern) return true; // else if (obj instanceof Map) // return true; // else if (obj instanceof Iterable) // return true; else if (obj instanceof byte[]) return true; else if (obj instanceof Binary) return true; else if (obj instanceof UUID) return true; // else if (obj.getClass().isArray()) // return true; else if (obj instanceof Symbol) return true; else if (obj instanceof BSONTimestamp) return true; else if (obj instanceof BSONDecimal) return true; else if (obj instanceof BigDecimal) return true; else if (obj instanceof CodeWScope) return true; else if (obj instanceof Code) return true; else if (obj instanceof MinKey) return true; else if (obj instanceof MaxKey) return true; else return false; } // setting display mode private static boolean _compatible = false; /** * When "compatible" is true, the content of BasicBSONObject method "toString" is show * absolutely the same with which is show in sdb shell. * @param compatible true or false, default to be false; * * {@code * // we have a bson as below: * BSONObject obj = new BasicBSONObject("a", Long.MAX_VALUE); * // sdb shell shows this bson like this: * {"a" : { "$numberLong" : "9223372036854775807"}} * // sdb shell use javascript grammer, so, it can't display number * // which is great that 2^53 - 1. So it use "$numberLong" to represent * // the type, and keep the number between the quotes. * // However, in java, when we use "obj.toString()", * // most of the time, we don't hope to get a result with * // the format "$numberLong", we hope to see the result as * // below: * {"a" : 9223372036854775807} * // When parameter "compatible" is false, we get this kind of result * // all the time. Otherwise, we get a result which is show as the sdb shell shows. * } */ public static void setJSCompatibility(boolean compatible) { _compatible = compatible; } /** * Get whether the display mode of BSON is the same with that in sdb shell or not. * @return true or false. * @see #setJSCompatibility(boolean) */ public static boolean getJSCompatibility() { return _compatible; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy