/* Copyright 2010-2014 MongoDB 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. */ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; namespace MongoDB.Bson { // this class is a wrapper for an object that we intend to serialize as a BsonDocument // it is a subclass of BsonDocument so that it may be used where a BsonDocument is expected // this class is mostly used by MongoCollection and MongoCursor when supporting generic query objects // if all that ever happens with this wrapped object is that it gets serialized then the BsonDocument is never materialized /// /// Represents a BsonDocument wrapper. /// public class BsonDocumentWrapper : MaterializedOnDemandBsonDocument { // private fields private Type _wrappedNominalType; private object _wrappedObject; private IBsonSerializer _serializer; private IBsonSerializationOptions _serializationOptions; private bool _isUpdateDocument; // constructors // needed for Deserialize // (even though we're going to end up throwing an InvalidOperationException) private BsonDocumentWrapper() { } /// /// Initializes a new instance of the BsonDocumentWrapper class. /// /// The wrapped object. public BsonDocumentWrapper(object wrappedObject) : this((wrappedObject == null) ? typeof(object) : wrappedObject.GetType(), wrappedObject) { } /// /// Initializes a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject) : this(wrappedNominalType, wrappedObject, false) { } /// /// Initializes a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// Whether the wrapped object is an update document that needs to be checked. public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject, bool isUpdateDocument) : this(wrappedNominalType, wrappedObject, BsonSerializer.LookupSerializer(wrappedNominalType), null, isUpdateDocument) { } /// /// Initializes a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// The serializer. /// The serialization options. /// Whether the wrapped object is an update document that needs to be checked. public BsonDocumentWrapper(Type wrappedNominalType, object wrappedObject, IBsonSerializer serializer, IBsonSerializationOptions serializationOptions, bool isUpdateDocument) { if (wrappedNominalType == null) { throw new ArgumentNullException("wrappedNominalType"); } if (serializer == null) { throw new ArgumentNullException("serializer"); } _wrappedNominalType = wrappedNominalType; _wrappedObject = wrappedObject; _serializer = serializer; _serializationOptions = serializationOptions; _isUpdateDocument = isUpdateDocument; } // public properties /// /// Gets whether the wrapped document is an update document. /// public bool IsUpdateDocument { get { return _isUpdateDocument; } } /// /// Gets the serialization options. /// /// /// The serialization options. /// public IBsonSerializationOptions SerializationOptions { get { return _serializationOptions; } } /// /// Gets the serializer. /// /// /// The serializer. /// public IBsonSerializer Serializer { get { return _serializer; } } /// /// Gets the nominal type of the wrapped document. /// public Type WrappedNominalType { get { return _wrappedNominalType; } } /// /// Gets the wrapped object. /// public object WrappedObject { get { return _wrappedObject; } } // public static methods /// /// Creates a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// A BsonDocumentWrapper. public static BsonDocumentWrapper Create(TNominalType value) { return Create(typeof(TNominalType), value); } /// /// Creates a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// Whether the wrapped object is an update document. /// A BsonDocumentWrapper. public static BsonDocumentWrapper Create(TNominalType value, bool isUpdateDocument) { return Create(typeof(TNominalType), value, isUpdateDocument); } /// /// Creates a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// A BsonDocumentWrapper. public static BsonDocumentWrapper Create(Type nominalType, object value) { return Create(nominalType, value, false); // isUpdateDocument = false } /// /// Creates a new instance of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// The wrapped object. /// Whether the wrapped object is an update document. /// A BsonDocumentWrapper. public static BsonDocumentWrapper Create(Type nominalType, object value, bool isUpdateDocument) { return new BsonDocumentWrapper(nominalType, value, isUpdateDocument); } /// /// Creates a list of new instances of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped objects. /// A list of wrapped objects. /// A list of BsonDocumentWrappers. public static IEnumerable CreateMultiple(IEnumerable values) { if (values == null) { throw new ArgumentNullException("values"); } return values.Select(v => new BsonDocumentWrapper(typeof(TNominalType), v)); } /// /// Creates a list of new instances of the BsonDocumentWrapper class. /// /// The nominal type of the wrapped object. /// A list of wrapped objects. /// A list of BsonDocumentWrappers. public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) { if (nominalType == null) { throw new ArgumentNullException("nominalType"); } if (values == null) { throw new ArgumentNullException("values"); } return values.Cast().Select(v => new BsonDocumentWrapper(nominalType, v)); } // public methods /// /// Creates a shallow clone of the document (see also DeepClone). /// /// /// A shallow clone of the document. /// public override BsonValue Clone() { if (IsMaterialized) { return base.Clone(); } else { return new BsonDocumentWrapper( _wrappedNominalType, _wrappedObject, _serializer, _serializationOptions, _isUpdateDocument); } } /// /// Deserialize is an invalid operation for BsonDocumentWrapper. /// /// Not applicable. /// Not applicable. /// Not applicable. /// Not applicable. [Obsolete("Deserialize was intended to be private and will become private in a future release.")] public override object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options) { throw new NotSupportedException(); } /// /// Serializes the wrapped object to a BsonWriter. /// /// The writer. /// The nominal type (overridden by the wrapped nominal type). /// The serialization options (can be null). [Obsolete("Serialize was intended to be private and will become private in a future release.")] public override void Serialize(BsonWriter bsonWriter, Type nominalType, IBsonSerializationOptions options) { BsonDocumentWrapperSerializer.Instance.Serialize(bsonWriter, nominalType, this, options); } // protected methods /// /// Materializes the BsonDocument. /// /// The materialized elements. protected override IEnumerable Materialize() { var bsonDocument = new BsonDocument(); var writerSettings = BsonDocumentWriterSettings.Defaults; using (var bsonWriter = new BsonDocumentWriter(bsonDocument, writerSettings)) { BsonDocumentWrapperSerializer.Instance.Serialize(bsonWriter, typeof(BsonDocumentWrapper), this, null); } return bsonDocument.Elements; } /// /// Informs subclasses that the Materialize process completed so they can free any resources related to the unmaterialized state. /// protected override void MaterializeCompleted() { } } }