org.fastmongo.odm.bson.repository.BsonDbObject.java Source code

Java tutorial

Introduction

Here is the source code for org.fastmongo.odm.bson.repository.BsonDbObject.java

Source

/*
 * 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;
    }
}