Java tutorial
/* * Copyright (c) 2014 Alexander Gulko <kirhog at gmail dot com>. * * 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.fastmongo.odm.bson.repository; import com.mongodb.DBCollection; import com.mongodb.DBObject; import com.mongodb.DefaultDBDecoder; import org.bson.BSON; import org.bson.BSONObject; import org.fastmongo.odm.bson.mapping.core.BsonReader; import java.util.Map; import java.util.Set; import static org.bson.BSON.EOO; /** * {@link com.mongodb.DBObject} implementation that holds unparsed BSON stream instead of parsed JSON tree. * * @author Alexander Gulko */ class BsonDbObject implements DBObject { private static final String ERROR_FIELD_NAME = "$err"; private byte[] data; private DBObject db; // not null if and only if it is an error object ($err) BsonDbObject(byte[] data) { this.data = data; checkIfError(); } /** * If an error occurs on a query or on a getMore operation sent by a replica set member, * MongoDB returns an error object instead of user data. * <p/> * The error objects first field has the reserved key $err. For example: * <pre> * { $err : "some error message", code : 1234 } * </pre> * see http://docs.mongodb.org/meta-driver/latest/legacy/error-handling-in-drivers/ . */ private void checkIfError() { BsonReader reader = new BsonReader(data); reader.skipInt(); // skip size // check if the first field is $err byte type = reader.readType(); if (type != BSON.EOO) { String field = reader.readFieldName(); if (ERROR_FIELD_NAME.equals(field)) { // we found an error, stop and convert to full DBObject as it doesn't contain our document db = toDbObjectAndClear(); } } } /** * Prefer to use this method if you don't need to get data from this object in the future. * MongoDB QueryResultIterator references to this data and has finalize method, * preventing data be collected after first GC run. */ public byte[] getDataAndClear() { byte[] result = data; data = null; return result; } /** * Converts BSON array to {@link com.mongodb.BasicDBObject} and remove reference to this array. * <strong>Should be called at most once.</strong> */ public DBObject toDbObjectAndClear() { if (db != null) { return db; } DBObject dbObj = convertToDbObject(); data = null; return dbObj; } private DBObject convertToDbObject() { return DefaultDBDecoder.FACTORY.create().decode(data, (DBCollection) null); } /** * Should <strong>NOT</strong> be called in client code. * It's only called by MongoDB driver for error handling. */ @Override public Object get(String key) { return db != null ? db.get(key) : null; } @Override public void markAsPartialObject() { } @Override public boolean isPartialObject() { return false; } @Override public Object put(String key, Object v) { return null; } @Override public void putAll(BSONObject o) { } @Override public void putAll(Map m) { } @Override public Map toMap() { return null; } @Override public Object removeField(String key) { return null; } @Override public boolean containsKey(String s) { return false; } @Override public boolean containsField(String s) { return false; } @Override public Set<String> keySet() { return null; } }