Package ch.agent.crnickl.mongodb

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

/*
*   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.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

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.DBObjectId;
import ch.agent.crnickl.api.Surrogate;
import ch.agent.crnickl.api.ValueScanner;
import ch.agent.crnickl.api.ValueType;
import ch.agent.crnickl.impl.Permission;
import ch.agent.crnickl.impl.SchemaUpdatePolicy;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.WriteConcern;

/**
* A stateless object with methods providing write access to value types.
* <p>
* A value type in MongoDB is stored as:
* <blockquote><pre><code>
* { _id : OID,
*   name : STRING,
*   type : STRING,
*   values? : {
*      STRING : STRING, ...
*    }
* }
* </code></pre></blockquote>
* The <em>values</em> field exists only in restricted value types.
* <p>
*
* @author Jean-Paul Vetterli
*/
public class WriteMethodsForValueType extends MongoDatabaseMethods {

  public WriteMethodsForValueType() {
  }
 
  /**
   * Create a value type in the database.
   * Throw an exception if the operation fails.
   *
   * @param vt a value type
   * @throws T2DBException
   */
  public <T>void createValueType(ValueType<T> vt) throws T2DBException {
    Surrogate surrogate = null;
    Throwable cause = null;
    try {
      check(Permission.CREATE, vt);
      DBObjectId ox = insert(vt);
      surrogate = makeSurrogate(vt, ox);
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (surrogate == null || cause != null)
      throw T2DBMsg.exception(cause, E.E10114, vt.getName());
    vt.getSurrogate().upgrade(surrogate);
  }

  /**
   * Delete a value type from the database.
   * Throw an exception if the operation fails.
   *
   * @param vt a value type
   * @param policy a schema udpdating policy
   * @throws T2DBException
   */
  public <T>void deleteValueType(ValueType<T> vt, SchemaUpdatePolicy policy) throws T2DBException {
    boolean done = false;
    Throwable cause = null;
    Surrogate s = vt.getSurrogate();
    MongoDatabase database = (MongoDatabase) s.getDatabase();
    try {
      check(Permission.MODIFY, vt);
      policy.willDelete(vt);
      ValueType<T> original = database.getReadMethodsForValueType().getValueType(s);
      DBCollection coll = getMongoDB(s).getValueTypes();
      coll.remove(asQuery(s.getId()), WriteConcern.SAFE); // ??? REPLICA_SAFE --> MongoException("norepl");
      database.sleep();
      try {
        policy.willDelete(original);
      } catch (T2DBException e) {
        // Oops! referential integrity broken!
        createValueType(original);
        throw e;
      }
      done = true;
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (!done || cause != null) {
      throw T2DBMsg.exception(cause, E.E10145, vt.getName());
    }
  }
 
  /**
   * Update a value type in the database.
   * Throw an exception if the operation cannot be done.
   * Updating a value type is an expensive operation, because in case
   *
   * @param vt a value type
   * @param policy a schema udpdating policy
   * @throws T2DBException
   */
  public <T>void updateValueType(ValueType<T> vt, SchemaUpdatePolicy policy) throws T2DBException {
    boolean done = false;
    Throwable cause = null;
    Surrogate s = vt.getSurrogate();
    MongoDatabase database = (MongoDatabase) s.getDatabase();
    try {
      check(Permission.MODIFY, vt);
      DBCollection coll = getMongoDB(s).getValueTypes();
     
      if (vt.isRestricted() && vt.getValues().size() > 0) {
        ValueType<T> original = database.getReadMethodsForValueType().getValueType(s);
        Set<T> deleted = deletedValues(original, vt);
        com.mongodb.DBObject operation = operation(Operator.SET,
            MongoDatabase.FLD_VT_NAME, vt.getName(),
            MongoDatabase.FLD_VT_VALUES, valueDescriptionsAsMap(vt));
       
        if (deleted.size() > 0) {
          // dangerous update! see comment in MongoDatabase.sleep
          Iterator<T> it = deleted.iterator();
          while (it.hasNext()) {
            policy.willDelete(vt, it.next());
          }
          coll.update(asQuery(s.getId()), operation, false, false, WriteConcern.SAFE);
          database.sleep();
          try {
            it = deleted.iterator();
            while (it.hasNext()) {
              policy.willDelete(vt, it.next());
            }
          } catch (T2DBException e) {
            // restore state and throw exception
            operation = operation(Operator.SET,
                MongoDatabase.FLD_VT_NAME, original.getName(),
                MongoDatabase.FLD_VT_VALUES, valueDescriptionsAsMap(original));
            coll.update(asQuery(s.getId()), operation);
            throw e;
          }
        } else {
          coll.update(asQuery(s.getId()), operation);
        }
      } else
        coll.update(asQuery(s.getId()), operation(Operator.SET, MongoDatabase.FLD_VT_NAME, vt.getName()));
      done = true;
    } catch (Exception e) {
      cause = e;
    } finally {
    }
    if (!done || cause != null)
      throw T2DBMsg.exception(cause, E.E10146, vt.getName());
  }
 
  private <T>Set<T> deletedValues(ValueType<T> original, ValueType<T> vt) throws T2DBException {
    Set<T> deleted = new HashSet<T>(original.getValues());
    deleted.removeAll(vt.getValues());
    return deleted;
  }
 
  private <T>DBObjectId insert(ValueType<T> vt) throws T2DBException {
    Surrogate s = vt.getSurrogate();
    com.mongodb.BasicDBObject bo = new BasicDBObject();
    if (!s.inConstruction())
      bo.put(MongoDatabase.FLD_ID, getId(vt));
    bo.put(MongoDatabase.FLD_VT_NAME, vt.getName());
    bo.put(MongoDatabase.FLD_VT_TYPE, vt.getExternalRepresentation());
    if (vt.isRestricted())
      bo.put(MongoDatabase.FLD_VT_VALUES, valueDescriptionsAsMap(vt));
    getMongoDB(s).getValueTypes().insert(bo);
    ObjectId ox = getObjectId(bo)
    return new MongoDBObjectId(ox);
  }
 
  private <T> Map<String, String> valueDescriptionsAsMap(ValueType<T> vt) throws T2DBException {
    Map<T, String> vd = vt.getValueDescriptions();
    ValueScanner<T> scanner = vt.getScanner();
    Map<String, String> map = new HashMap<String, String>(vd.size());
    for (Map.Entry<T, String> entry : vd.entrySet()) {
      map.put(scanner.toString(entry.getKey()), entry.getValue());
    }
    return map;
  }
 
}
TOP

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

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.