Package ch.agent.crnickl.mongodb

Source Code of ch.agent.crnickl.mongodb.WriteMethodsForSchema

/*
*   Copyright 2012-2013 Hauser Olsson GmbH
*
* 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 ch.agent.crnickl.mongodb;

import java.util.Collection;

import org.bson.types.ObjectId;

import ch.agent.crnickl.T2DBException;
import ch.agent.crnickl.T2DBMsg;
import ch.agent.crnickl.T2DBMsg.E;
import ch.agent.crnickl.api.AttributeDefinition;
import ch.agent.crnickl.api.DBObjectId;
import ch.agent.crnickl.api.DBObjectType;
import ch.agent.crnickl.api.Database;
import ch.agent.crnickl.api.Property;
import ch.agent.crnickl.api.Schema;
import ch.agent.crnickl.api.SeriesDefinition;
import ch.agent.crnickl.api.Surrogate;
import ch.agent.crnickl.api.UpdatableSchema;
import ch.agent.crnickl.impl.Permission;
import ch.agent.crnickl.impl.SchemaUpdatePolicy;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;

/**
* A stateless object with methods providing write access to schemas.
* <p>
* A schema in MongoDB is stored as: <blockquote>
*
* <pre>
* <code>
* { _id : OID,
*   name : STRING,
*   base? : OID,
*   attribs : [
*     {
*       number : NUMBER,
*       erasing? : BOOLEAN
*       prop? : OID,
*       value? : STRING
*     }, ...
*   ]
*   series : [
*     {
*       number : NUMBER,
*       erasing? : BOOLEAN
*       description? : STRING,
*       attribs : [
*         ...
*       ]
*     }, ...
*   ]
* }
* </code>
* </pre>
* </blockquote>
*
* Note that attribute and series definitions are not keyed,
* because they do not always have a name (erasing). The position inside the
* array is independent of number. When erasing is present, it is true, and all
* other fields except number are absent. When erasing is absent, the presence
* of other fields denotes overriding behavior. When present, the <em>base</em>
* field identifies the base schema. The attribs and series arrays can be empty
* but are present.
*
* @author Jean-Paul Vetterli
*/
public class WriteMethodsForSchema extends ReadMethodsForSchema {

  public WriteMethodsForSchema() {
  }
 
  /**
   * Create an empty schema in the database.
   * Throw an exception if the operation cannot be done.
   *
   * @param schema a schema
   * @throws T2DBException
   */
  public void createSchema(UpdatableSchema schema) throws T2DBException {
    Surrogate surrogate = null;
    Throwable cause = null;
    try {
      check(Permission.CREATE, schema);
      Schema base = schema.getBase();
      if (base != null)
        check(Permission.READ, base);
      DBObjectId ox = insert(schema);
      surrogate = makeSurrogate(schema, ox);
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (surrogate == null || cause != null)
      throw T2DBMsg.exception(cause, E.E30122, schema.getName());
    schema.getSurrogate().upgrade(surrogate);
  }
 
  /**
   * Delete a schema from the database.
   * Throw an exception if the operation cannot be done.
   *
   * @param schema a schema
   * @param policy a schema udpdating policy
   * @throws T2DBException
   */
  public void deleteSchema(UpdatableSchema schema, SchemaUpdatePolicy policy) throws T2DBException {
    boolean done = false;
    Throwable cause = null;
    Surrogate s = schema.getSurrogate();
    MongoDatabase database = (MongoDatabase) s.getDatabase();
    try {
      check(Permission.MODIFY, schema);
      policy.willDelete(schema);
      UpdatableSchema original = database.getReadMethodsForSchema().getSchema(s);
      DBCollection coll = getMongoDB(s).getSchemas();
      coll.remove(asQuery(s.getId()), WriteConcern.SAFE);
      database.sleep();
      try {
        policy.willDelete(schema);
      } catch (T2DBException e) {
        // Oops! referential integrity broken!
        createSchema(original);
        throw e;
      }
      done = true;
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (!done || cause != null) {
      throw T2DBMsg.exception(cause, E.E30123, schema.getName());
    }
  }

  /**
   * Update the basic schema setup in the database.
   * Throw an exception if the operation cannot be done.
   *
   * @param schema a schema
   * @param policy
   * @return true if the schema was updated
   * @throws T2DBException
   */
  public boolean updateSchema(UpdatableSchema schema, SchemaUpdatePolicy policy) throws T2DBException {
    boolean done = false;
    Throwable cause = null;
    Surrogate s = schema.getSurrogate();
    MongoDatabase database = (MongoDatabase) s.getDatabase();
    try {
      check(Permission.MODIFY, schema);
      UpdatableSchema original = database.getReadMethodsForSchema().getSchema(s);
      Schema base = schema.getBase();
      if (base != null && !base.equals(original.getBase()))
        check(Permission.READ, base);
      DBCollection coll = getMongoDB(s).getSchemas();
      // full replace (no need to set _id in full update)
      com.mongodb.DBObject operation = mongoObject(
          MongoDatabase.FLD_SCHEMA_NAME, schema.getName(),
          MongoDatabase.FLD_SCHEMA_BASE, getIdOrZero(schema.getBase()),
          MongoDatabase.FLD_SCHEMA_ATTRIBS,
          attributeDefinitions(schema.getAttributeDefinitions()),
          MongoDatabase.FLD_SCHEMA_SERIES,
          seriesDefinitions(schema.getSeriesDefinitions()));
      coll.update(asQuery(s.getId()), operation, false, false, WriteConcern.SAFE);
      database.sleep();
      try {
        policy.willUpdate(schema);
      } catch (T2DBException e) {
        // Oops! referential integrity broken!
        operation = mongoObject(
            MongoDatabase.FLD_SCHEMA_NAME, original.getName(),
            MongoDatabase.FLD_SCHEMA_BASE, getId(original.getBase()),
            MongoDatabase.FLD_SCHEMA_ATTRIBS, original.getAttributeDefinitions(),
            MongoDatabase.FLD_SCHEMA_SERIES, original.getSeriesDefinitions());
        coll.update(asQuery(s.getId()), operation);
        throw e;
      }
      done = true;
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (cause != null)
      throw T2DBMsg.exception(cause, E.E30122, schema.getName());

    return done;
  }
 
  /**
   * Find a chronicle referencing one of the schemas.
   * This looks like a "reading" method but is used in the context of schema updating.
   *
   * @param schema a schema
   * @return a surrogate or null
   * @throws T2DBException
   */
  public Surrogate findChronicle(Schema schema) throws T2DBException {
    Surrogate result = null;
    try {
      Database db = schema.getDatabase();
      DBObject query = new BasicDBObject();
      query.put(MongoDatabase.FLD_CHRON_SCHEMA, getId(schema));
      DBObject obj = getMongoDB(db).getChronicles().findOne(query);
      if (obj != null)
        result = makeSurrogate(db, DBObjectType.CHRONICLE, getObjectId((BasicDBObject)obj));
    } catch (Exception e) {
      throw T2DBMsg.exception(e, E.E30117);
    }
    return result;
  }
 
  /**
   * Find a chronicle with an explicit attribute value for a given property and schemas.
   * This looks like a "reading" method but is used in the context of schema updating.
   *
   * @param property a property
   * @param schema a schema
   * @return a surrogate or null
   * @throws T2DBException
   */
  public Surrogate findChronicle(Property<?> property, Schema schema) throws T2DBException {
    Surrogate result = null;
    DBCursor cursor = null
    try {
      Database db = schema.getDatabase();
      cursor = getMongoDB(db).getAttributes().find(mongoObject(
          MongoDatabase.FLD_ATTR_PROP, getId(property)));
      while (cursor.hasNext()) {
        ObjectId chrOid = ((BasicDBObject) cursor.next()).getObjectId(MongoDatabase.FLD_ATTR_CHRON);
        Surrogate entityKey = makeSurrogate(db, DBObjectType.CHRONICLE, chrOid);
        Schema s = db.getChronicle(entityKey).getSchema(true);
        if (s.dependsOnSchema(schema)) {
          result = entityKey;
          break;
        }
      }
    } catch (Exception e) {
      throw T2DBMsg.exception(e, E.E30117);
    } finally {
      if (cursor != null)
        cursor.close();
    }
    return result;
  }

  /**
   * Find a chronicle with a given series in a collection of schemas.
   * This looks like a "reading" method but is used in the context of schema updating.
   *
   * @param ss a series definition
   * @param schema a schema
   * @return a surrogate or null
   * @throws T2DBException
   */
  public Surrogate findChronicle(SeriesDefinition ss, Schema schema) throws T2DBException {
    Surrogate result = null;
    DBCursor cursor1 = null
    DBCursor cursor2 = null
    try {
      Database db = schema.getDatabase();
      cursor1 = getMongoDB(db).getChronicles().find(mongoObject(
          MongoDatabase.FLD_CHRON_SCHEMA, getId(schema)));
      OUTER: while (cursor1.hasNext()) {
        ObjectId chronicleOid = getObjectId((BasicDBObject) cursor1.next());
        cursor2 = getMongoDB(db).getSeries().find(mongoObject(
            MongoDatabase.FLD_SER_CHRON, chronicleOid,
            MongoDatabase.FLD_SER_NUM, ss.getNumber()));
        while (cursor2.hasNext()) {
          Surrogate entityKey = makeSurrogate(db, DBObjectType.CHRONICLE, chronicleOid);
          Schema s = db.getChronicle(entityKey).getSchema(true);
          if (s.dependsOnSchema(schema)) {
            result = entityKey;
            break OUTER;
          }
        }
      }
    } catch (Exception e) {
      throw T2DBMsg.exception(e, E.E30117);
    } finally {
      if (cursor1 != null)
        cursor1.close();
      if (cursor2 != null)
        cursor2.close();
    }
    return result;
 
 
  private <T>DBObjectId insert(UpdatableSchema schema) throws T2DBException {
    com.mongodb.BasicDBObject bo = new BasicDBObject();
    Surrogate s = schema.getSurrogate();
    if (!s.inConstruction())
      bo.put(MongoDatabase.FLD_ID, getId(schema));
    bo.put(MongoDatabase.FLD_SCHEMA_NAME, schema.getName());
    bo.put(MongoDatabase.FLD_SCHEMA_BASE, getIdOrZero(schema.getBase()));
    bo.put(MongoDatabase.FLD_SCHEMA_ATTRIBS, attributeDefinitions(schema.getAttributeDefinitions()));
    bo.put(MongoDatabase.FLD_SCHEMA_SERIES, seriesDefinitions(schema.getSeriesDefinitions()));
    getMongoDB(s).getSchemas().insert(bo);
    ObjectId ox = getObjectId(bo)
    return new MongoDBObjectId(ox);
  }

  private BasicDBList attributeDefinitions(
      Collection<AttributeDefinition<?>> defs) throws T2DBException {
    BasicDBList list = new BasicDBList();
    if (defs != null) {
      int i = 0;
      for (AttributeDefinition<?> def : defs) {
        list.put(i++, attributeDefinition(def));
      }
    }
    return list;
  }

  private BasicDBObject attributeDefinition(AttributeDefinition<?> def) throws T2DBException {
    com.mongodb.BasicDBObject bo = new BasicDBObject();
    bo.put(MongoDatabase.FLD_ATTRIBDEF_NUM, def.getNumber());
    bo.put(MongoDatabase.FLD_ATTRIBDEF_ERASING, def.isErasing());
    bo.put(MongoDatabase.FLD_ATTRIBDEF_PROP, def.isErasing() ? null : getId(def.getProperty()));
    bo.put(MongoDatabase.FLD_ATTRIBDEF_VAL, def.isErasing() ? null :
      def.getProperty().getValueType().toString(def.getValue()));
    return bo;
  }
 
  private BasicDBList seriesDefinitions(Collection<SeriesDefinition> defs) throws T2DBException {
    BasicDBList list = new BasicDBList();
    if (defs != null) {
      int i = 0;
      for (SeriesDefinition def : defs) {
        list.put(i++, seriesDefinition(def));
      }
    }
    return list;
  }
 
  private BasicDBObject seriesDefinition(SeriesDefinition def) throws T2DBException {
    com.mongodb.BasicDBObject bo = new BasicDBObject();
    bo.put(MongoDatabase.FLD_SERIESDEF_NUM, def.getNumber());
    bo.put(MongoDatabase.FLD_SERIESDEF_ERASING, def.isErasing());
    bo.put(MongoDatabase.FLD_SERIESDEF_DESC, def.isErasing() ? null : def.getDescription());
    bo.put(MongoDatabase.FLD_SERIESDEF_ATTRIBS, def.isErasing() ? attributeDefinitions(null) :
      attributeDefinitions(def.getAttributeDefinitions()));
    return bo;
  }
 
}
TOP

Related Classes of ch.agent.crnickl.mongodb.WriteMethodsForSchema

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.