HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component composition.Intercept by barry
expand copy to clipboardexpand
uses InterceptEvents

data ObjectWrap {
	Object o
	}

component provides Intercept {

	void interceptStatefulObject(IDC ofComponent, Object object, IDC source, char type[], char icReqInterface[])
		{
		if (dana.pauseObject(ofComponent, object))
			{
			// - wait for all in-progress calls to finish in the old object
			dana.waitForObject(object)
			
			Data transferState = ofComponent.getTransferState(object)
			
			// - initialise a new object, without calling its constructor
			Object a = source.initObject(type)
			// - rewire live object so calls now go to the new one (a becomes null)
			Object b = dana.rewireObject(object, a)
			// - notify the object that it's now the "active" copy
			if (source.hasInterface(object, "composition.InterceptEvents", null))
				{
				source.callInterface(object, "composition.InterceptEvents", null, InterceptEvents.[setTarget(Object)], new ObjectWrap(b))
				source.adoptObject(icReqInterface, b)
				}
			ofComponent.setTransferState(b, transferState)
			
			// - allow new calls to proceed in the new object
			dana.resumeObject(object)
			}
		}
	
	void interceptStatelessObject(IDC ofComponent, Object object, IDC source, char type[], char icReqInterface[])
		{
		InterceptEvents ie
		if (dana.pauseObject(ofComponent, object))
			{
			// - initialise a new object, without calling its constructor
			Object a = source.initObject(type)
			// - rewire live object so calls now go to the new one (a becomes null)
			Object b = dana.rewireObject(object, a)
			// - notify the object that it's now the "active" copy
			if (source.hasInterface(object, "composition.InterceptEvents", null))
				{
				source.callInterface(object, "composition.InterceptEvents", null, InterceptEvents.[setTarget(Object)], new ObjectWrap(b))
				source.adoptObject(icReqInterface, b)
				}
			// - allow new calls to proceed in the new object
			dana.resumeObject(object)
			// - wait for all in-progress calls to finish in the old object
			dana.waitForObject(b)
			}
		}
	
	bool addObjectIntercept(IDC ofComponent, Object object, IDC newImplementation, char typeName[], char icReqInterface[])
		{
		if (ofComponent.hasTransferState(object))
			interceptStatefulObject(ofComponent, object, newImplementation, typeName, icReqInterface)
			else
			interceptStatelessObject(ofComponent, object, newImplementation, typeName, icReqInterface)
		
		return true
		}
	
	bool Intercept:insertIntercept(IDC ofComponent, char reqInterface[], IDC toComponent, char icProvInterface[], char icReqInterface[])
		{
		if (ofComponent.hasRequires(reqInterface))
			{
			IDC oldTarget = ofComponent.getComponent(reqInterface)
			
			//temporarily prevent new object instances being created or destroyed, and snapshot the current set of objects
			ofComponent.pause(reqInterface)
			//switch the binding from this role to the new component (all new objects will be sourced from the new component)
			ofComponent.wire(reqInterface, toComponent, icProvInterface)
			Object objects[] = ofComponent.getObjects(reqInterface)
			ofComponent.resume(reqInterface)
			
			//switch all existing objects to the new class
			for (int i = 0; i < objects.arrayLength; i++)
				{
				addObjectIntercept(oldTarget, objects[i], toComponent, icProvInterface, icReqInterface)
				}
			}
			else
			{
			throw new Exception("No bindport of type '$reqInterface' found on component")
			}
		
		return true
		}
	
	void deinterceptStatefulObject(IDC ofComponent, Object object, Object objectTo, IDC source, char type[], char icReqInterface[])
		{
		InterceptEvents ie
		Object a = objectTo
		if (dana.pauseObject(ofComponent, object))
			{
			// - wait for all in-progress calls to finish in the old object
			dana.waitForObject(object)
			
			Data transferState = source.getTransferState(objectTo)
			
			// - rewire live object so calls now go to the new one (a becomes null)
			Object b = dana.rewireObject(object, a)
			
			source.setTransferState(object, transferState)
			
			// - allow new calls to proceed in the new object
			dana.resumeObject(object)
			}
		}
	
	void deinterceptStatelessObject(IDC ofComponent, Object object, Object objectTo, IDC source, char type[], char icReqInterface[])
		{
		InterceptEvents ie
		Object a = objectTo
		if (dana.pauseObject(ofComponent, object))
			{
			// - rewire live object so calls now go to the new one (a becomes null)
			Object b = dana.rewireObject(object, a)
			
			// - allow new calls to proceed in the new object
			dana.resumeObject(object)
			// - wait for all in-progress calls to finish in the old object
			dana.waitForObject(b)
			}
		}
	
	bool remObjectIntercept(IDC ofComponent, Object object, Object objectTo, IDC newImplementation, char typeName[], char icReqInterface[])
		{
		if (ofComponent.hasTransferState(object))
			deinterceptStatefulObject(ofComponent, object, objectTo, newImplementation, typeName, icReqInterface)
			else
			deinterceptStatelessObject(ofComponent, object, objectTo, newImplementation, typeName, icReqInterface)
		
		return true
		}
	
	bool Intercept:removeIntercept(IDC ofComponent, char reqInterface[], IDC toComponent, char toInterface[], char icReqInterface[])
		{
		if (ofComponent.hasRequires(reqInterface))
			{
			IDC oldTarget = ofComponent.getComponent(reqInterface)
			
			//temporarily prevent new object instances being created or destroyed, and snapshot the current set of objects
			ofComponent.pause(reqInterface)
			//switch the binding from this role to the new component (all new objects will be sourced from the new component)
			ofComponent.wire(reqInterface, toComponent, toInterface)
			Object objects[] = ofComponent.getObjects(reqInterface)
			Object objectsTo[] = oldTarget.getObjects(icReqInterface)
			ofComponent.resume(reqInterface)
			
			//switch all existing objects to the new class
			for (int i = 0; i < objects.arrayLength; i++)
				{
				remObjectIntercept(oldTarget, objects[i], objectsTo[(objects.arrayLength-1)-i], toComponent, toInterface, icReqInterface)
				}
			}
			else
			{
			throw new Exception("No bindport of type '$reqInterface' found on component")
			}
		
		return true
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n composition.Intercept -m "reason for update" -u yourUsername
Version 1 (this version) by barry
Notes for this version: Standard Library Initialisation