All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coweb.oe.Operation Maven / Gradle / Ivy

The newest version!
package org.coweb.oe;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;


public abstract class Operation {
	
	protected final static int infinity = 99999999;
	protected int siteId;
	protected int seqId;
	protected String type = null;
	protected boolean local = false;
	protected ContextVector contextVector = null;
	protected String key = null;
	protected String value = null;
	protected int position;
	protected int order;
	protected boolean immutable;
	protected Vector xCache = null;
	
	public static Operation createOperationFromType(String type, Map args) throws OperationEngineException  {
		
		Operation op = null;
		
		if(type.equals("insert")) {
			op = new InsertOperation(args);
		}
		else if(type.equals("delete")) {
			op = new DeleteOperation(args);
		}
		else if(type.equals("update")) {
			op = new UpdateOperation(args);
		}
		
		return op;
	}
	
	public static Operation createOperationFromState(Object[] state) throws OperationEngineException {
		return null;
	}
	
	public static String createHistoryKey(int site, int seq) {
		return new Integer(site).toString() + "," + new Integer(seq).toString();
	}
	
	@Override
	public String toString() {
		StringBuffer b = new StringBuffer();
		b.append("{siteId : " + this.siteId);
		b.append(",seqId : " + this.seqId);
		b.append(",type :" + type);
		b.append(",contextVector : " + this.contextVector);
		b.append(",key : " + this.key);
		b.append(",position : " + this.position);
		b.append(",order : " + this.order);
		b.append("}");
		
		return b.toString();
	}
	/**
     * Contains information about a local or remote event for transformation.
     *
     * Initializes the operation from serialized state or individual props if
     * state is not defined in the args parameter.
     *
     * @param args Map containing the following:
	 *        
  • state Array in format returned by getState * bundling the following individual parameter values *
  • siteId Integer site ID where the op originated *
  • contextVector Context in which the op occurred *
  • key Name of the property the op affected *
  • value Value of the op *
  • position Integer position of the op in a linear collection *
  • order Integer sequence number of the op in the * total op order across all sites *
  • seqId Integer sequence number of the op at its originating site. * If undefined, computed from the context vector and site ID. *
  • immutable True if the op cannot be changed, most likely because * it is in a history buffer somewhere to this instance * @throws OperationEngineException */ @SuppressWarnings("unchecked") protected Operation(Map args) throws OperationEngineException { if(args == null) { this.type = null; return; } if(args.containsKey("state")) { this.setState((Object[])args.get("state")); this.local = false; } else { this.siteId = ((Integer)args.get("siteId")).intValue(); this.contextVector = (ContextVector)args.get("contextVector"); this.key = (String)args.get("key"); this.value = (String)args.get("value"); this.position = ((Integer)args.get("position")).intValue(); Integer ord = (Integer)args.get("order"); if(ord == null) { this.order = Operation.infinity; } else { this.order = ord.intValue(); } if(args.containsKey("seqId")) { this.seqId = ((Integer)args.get("seqId")).intValue(); } else if(this.contextVector != null) { this.seqId = this.contextVector.getSeqForSite(this.siteId) + 1; } else { throw new OperationEngineException("missing sequence id for new operation"); } if(args.containsKey("xCache")) { this.xCache = (Vector)args.get("xCache"); } else { this.xCache = null; } this.local = ((Boolean)args.get("local")).booleanValue() || false; } this.immutable = false; if(this.xCache == null) { this.xCache = new Vector(); } } public abstract Operation transformWithDelete(Operation op); public abstract Operation transformWithInsert(Operation op); public abstract Operation transformWithUpdate(Operation op); /** * Serializes the operation as an array of values for transmission. * * @return {Object[]} Array with the name of the operation type and all * of its instance variables as primitive JS types */ public Object[] getState() { // use an array to minimize the wire format Object[] arr = { this.type, this.key, this.value, this.position, this.contextVector.getSites(), this.seqId, this.siteId, this.order }; return arr; } /** * Unserializes operation data and sets it as the instance data. Throws an * exception if the state is not from an operation of the same type. * * @param arr Array in the format returned by getState * @throws OperationEngineException */ public void setState(Object[] arr) throws OperationEngineException { if(!((String)arr[0]).equals(this.type)) { throw new OperationEngineException("setState invoked with state from wrong op type"); } else if(this.immutable) { throw new OperationEngineException("op is immutable"); } // name args as required by constructor this.key = (String)arr[1]; this.value = (String)arr[2]; this.position = ((Integer)arr[3]).intValue(); HashMap args = new HashMap(); args.put("state", (Object[])arr[4]); this.contextVector = new ContextVector(args); this.seqId = ((Integer)arr[5]).intValue(); this.siteId = ((Integer)arr[6]).intValue(); if(arr.length >= 8) { this.order = ((Integer)arr[7]).intValue(); } else { this.order = Operation.infinity; } } /** * Makes a copy of this operation object. Takes a shortcut and returns * a ref to this instance if the op is marked as mutable. * @throws OperationEngineException * * @return Operation object */ public Operation copy() throws OperationEngineException { HashMap args = new HashMap(); args.put("siteId", new Integer(this.siteId)); args.put("seqId", new Integer(this.seqId)); args.put("contextVector", this.contextVector.copy()); args.put("key", this.key); args.put("value", this.value); args.put("position", new Integer(this.position)); args.put("order", new Integer(this.order)); args.put("local", new Boolean(this.local)); args.put("xCache", this.xCache); Operation op; try { op = Operation.createOperationFromType(this.type, args); } catch(OperationEngineException e) { e.printStackTrace(); op = null; } return op; } /** * Gets a version of the given operation previously transformed into the * given context if available. * * @param cv Context of the transformed op to seek * @throws OperationEngineException * @return Copy of the transformed operation from the * cache or null if not found in the cache */ public Operation getFromCache(ContextVector cv) throws OperationEngineException { // check if the cv is a key in the xCache Vector cache = this.xCache; int l = cache.size(); Operation xop; for(int i=0; i cache = this.xCache; Operation cop = this.copy(); // mark copy as immutable cop.immutable = true; // add a copy of this transformed op to the history cache.addElement(cop); // check the count of cached ops against number of sites - 1 int diff = cache.size() - (siteCount-1); if(diff > 0) { // if overflow, remove oldest op(s) Operation[] arr = new Operation[cache.size()]; arr = cache.toArray(arr); Operation[] newArr = Arrays.copyOf(arr, diff); cache.removeAllElements(); for(int i=0; i op.siteId) { return 1; } else { return 0; } } return rv; } /** * Computes an ordered comparison of this op and another based on their * position in the total op order. * * @param op Other operation * @return -1 if this op is ordered before the other, 0 if they * are in the same context, and 1 if this op is ordered after the other */ public int compareByOrder(Operation op) { if(this.order == op.order) { // both unknown total order so next check if both ops are from // the same site or if one is from the local site and the other // remote if(this.local == op.local) { // compare sequence ids for local-local or remote-remote order return (this.seqId < op.seqId) ? -1 : 1; } else if(this.local && !op.local) { // this local op must appear after the remote one in the total // order as the remote one was included in the late joining // state sent by the remote site to this one meaning it was // sent before this site finished joining return 1; } else if(!this.local && op.local) { // same as above, but this op is the remote one now return -1; } } else if(this.order < op.order) { return -1; } else if(this.order > op.order) { return 1; } return -1; } /** * Transforms this operation to include the effects of the operation * provided as a parameter IT(this, op). Upgrade the context of this * op to reflect the inclusion of the other. * @throws OperationEngineException * * @return This operation, transformed in-place, or null * if its effects are nullified by the transform * @throws {Error} If this op to be transformed is immutable or if the * this operation subclass does not implement the transform method needed * to handle the passed op */ public Operation transformWith(Operation op) throws OperationEngineException { if(this.immutable) { throw new OperationEngineException("attempt to transform immutable op"); } Operation rv = null; if(op.type.equals("delete")) { rv = this.transformWithDelete(op); } else if(op.type.equals("insert")) { rv = this.transformWithInsert(op); } else if(op.type.equals("update")) { rv = this.transformWithUpdate(op); } if(rv != null) { this.upgradeContextTo(op); } return rv; } /** * Upgrades the context of this operation to reflect the inclusion of a * single other operation from some site. * * @param op The operation to include in the context of this op * @throws OperationEngineException * @throws {Error} If this op to be upgraded is immutable */ public void upgradeContextTo(Operation op) throws OperationEngineException { if(this.immutable) { throw new OperationEngineException("attempt to upgrade context of immutable op"); } this.contextVector.setSeqForSite(op.siteId, op.seqId); } public int getSiteId() { return this.siteId; } public int getSeqId() { return this.seqId; } public String getValue() { return this.value; } public int getPosition() { return this.position; } public ContextVector getContextVector() { return this.contextVector; } public void setImmutable(boolean immutable) { this.immutable = immutable; } }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy