Commit 55486c89 authored by Jonathon Duerig's avatar Jonathon Duerig

Added the source for the flash demo. Build instructions and basic architecture...

Added the source for the flash demo. Build instructions and basic architecture are described in README.
parent 1625ef5b
The demo for the flash ProtoGENI client consists of three basic
parts.
test.fla is the base flash file which contains the basic structure and
art assets of the demo.
src/*.as is the set of classes which implement the demo
src/com/mattism/http/xmlrpc/* is the xmlrpc library which has been
modified to act as the network channel.
-----
Build
-----
The only way to build the flash demo is with the flash authoring tool. Start the flash authoring tool and open test.fla. Select File -> Publish.
test.swf will be created in the same directory as test.fla.
------------------
Basic Architecture
------------------
The demo is organized at a fundamental level as a set of menus only
one of which is active at any time. Main.as contains the basic
functionality to select and move between menus. MenuSliceSelect,
MenuSliceCreate, and MenuSliceDetail provide the implementations for
the three menus.
The canvas which is used to manage and modify a slice is
MenuSliceDetail. It delegates the work to three different objects: an
ActiveNodes object which manages the nodes and links between them, a
ComponentManager object which maintains the combo box and selection
list for nodes, and a Console which executes any xmlrpc calls needed
and update the console text box.
This diff is collapsed.
package
{
import flash.display.MovieClip;
public class AddLinkClip extends MovieClip
{
public function AddLinkClip() : void
{
number = 0;
}
public var number : int;
}
}
package
{
// This object populates and takes events from both 'select', a
// combo-box used to specify the component manager and 'list', a
// listbox with all of the nodes managed by the component manager.
import fl.controls.ComboBox;
import fl.controls.List;
import fl.events.ListEvent;
import flash.events.Event;
class ComponentManager
{
public function ComponentManager(newSelect : ComboBox,
newList : List,
newNodes : ActiveNodes) : void
{
select = newSelect;
list = newList;
list.allowMultipleSelection = true;
listStatus = new ListStatusClip();
list.addChild(listStatus);
listStatus.alpha = 0.3;
nodes = newNodes;
names = new Array();
uuids = new Array();
used = new Array();
tickets = new Array();
states = new Array();
select.removeAll();
var i : int = 0;
for (; i < cmNames.length; ++i)
{
select.addItem(new ListItem(cmNames[i], null));
names.push(new Array());
uuids.push(new Array());
used.push(new Array());
tickets.push(null);
states.push(LOADING);
// populateNodes(i, cmResults[i]);
}
select.selectedIndex = 0;
states[0] = NORMAL;
list.addEventListener(ListEvent.ITEM_CLICK, clickItem);
list.addEventListener(Event.CHANGE, changeItem);
select.addEventListener(Event.CHANGE, changeComponent);
updateList();
}
public function cleanup() : void
{
list.removeEventListener(ListEvent.ITEM_CLICK, clickItem);
list.removeEventListener(Event.CHANGE, changeItem);
select.removeEventListener(Event.CHANGE, changeComponent);
listStatus.parent.removeChild(listStatus);
}
public function getTicket(index : int) : String
{
return tickets[index];
}
public function setTicket(index : int, value : String) : void
{
tickets[index] = value;
}
public function getUrl(index : int) : String
{
return cmUrls[index];
}
public function getCmCount() : int
{
return cmNames.length;
}
public function removeNode(cmIndex : int, nodeIndex : int) : void
{
var target : int = used[cmIndex].indexOf(nodeIndex);
if (target != -1)
{
used[cmIndex].splice(target, 1);
}
if (cmIndex == select.selectedIndex)
{
list.selectedIndices = used[select.selectedIndex].slice();
}
}
function clickItem(event : ListEvent) : void
{
if (used[select.selectedIndex].indexOf(event.index) == -1)
{
nodes.addNode(names[select.selectedIndex][event.index],
uuids[select.selectedIndex][event.index],
select.selectedIndex,
event.index,
removeNode,
select.stage.mouseX,
select.stage.mouseY);
used[select.selectedIndex].push(event.index);
}
list.selectedIndices = used[select.selectedIndex].slice();
}
function changeItem(event : Event) : void
{
list.selectedIndices = used[select.selectedIndex].slice();
}
function changeComponent(event : Event) : void
{
updateList();
}
function updateList() : void
{
var current = select.selectedIndex;
list.removeAll();
list.clearSelection();
var i : int = 0;
for (; i < names[current].length; ++i)
{
list.addItem(new ListItem(names[current][i], "NodeNone"));
}
list.selectedIndices = used[current].slice();
if (states[current] == NORMAL)
{
listStatus.visible = false;
}
else if (states[current] == LOADING)
{
listStatus.visible = true;
listStatus.text.text = "Loading";
listStatus.text.backgroundColor = 0x00ff00;
}
else
{
listStatus.visible = true;
listStatus.text.text = "Failed";
listStatus.text.backgroundColor = 0xff0000;
}
}
public function populateNodes(index : int, str : String) : void
{
if (str != null)
{
var rspec : XML = XML(str);
var nodeName : QName = new QName(rspec.namespace(), "node");
for each (var element in rspec.elements(nodeName))
{
if (element.attribute("uuid") != null
&& element.attribute("uuid") != "")
{
names[index].push(element.attribute("name"));
uuids[index].push(element.attribute("uuid"));
}
}
}
states[index] = NORMAL;
updateList();
}
public function failResources(index : int)
{
states[index] = FAILED;
updateList();
}
var select : ComboBox;
var list : List;
var listStatus : ListStatusClip;
var nodes : ActiveNodes;
var names : Array;
var uuids : Array;
var used : Array;
var tickets : Array;
var states : Array;
var NORMAL = 0;
var LOADING = 1;
var FAILED = 2;
public static var cmNames : Array = new Array("", "ProtoGENI", "Emulab");
static var cmUrls : Array =
new Array(null,
"https://myboss.myelab.testbed.emulab.net:443/protogeni/xmlrpc",
"https://boss.emulab.net:443/protogeni/xmlrpc/");
static var cmResults : Array =
new Array(null,
"<rspec xmlns=\"http://protogeni.net/resources/rspec/0.1\"> "+
" <node uuid=\"de9803c2-773e-102b-8eb4-001143e453fe\" " +
" hrn=\"geni1\" " +
" virtualization_type=\"emulab-vnode\"> " +
" </node>" +
" <node uuid=\"de995217-773e-102b-8eb4-001143e453fe\" " +
" hrn=\"geni-other\" " +
" virtualization_type=\"emulab-vnode\"> " +
" </node>" +
"</rspec>",
"<rspec xmlns=\"http://protogeni.net/resources/rspec/0.1\"> "+
" <node uuid=\"deb23428-773e-102b-8eb4-001143e453fe\" " +
" hrn=\"pgeni4\" " +
" virtualization_type=\"emulab-vnode\"> " +
" </node>" +
" <node uuid=\"deb06bd8-773e-102b-8eb4-001143e453fe\" " +
" hrn=\"pgeni2\" " +
" virtualization_type=\"plab_node\"> " +
" </node>" +
" <node uuid=\"deaaad4b-773e-102b-8eb4-001143e453fe\" " +
" hrn=\"pgeni3\" " +
" virtualization_type=\"plab_node\"> " +
" </node>" +
"</rspec>");
}
}
package
{
import flash.display.DisplayObjectContainer;
import flash.events.MouseEvent;
import flash.events.ErrorEvent;
import fl.controls.Button;
import com.mattism.http.xmlrpc.MethodFault;
class Console
{
public function Console(parent : DisplayObjectContainer,
newNodes : ActiveNodes, newCm : ComponentManager,
newConsoleButton : Button,
newCreateSliversButton : Button,
newBootSliversButton : Button,
newDeleteSliversButton : Button,
newCredential : Credential) : void
{
nodes = newNodes;
cm = newCm;
consoleButton = newConsoleButton;
consoleButton.label = "Console";
consoleButton.addEventListener(MouseEvent.CLICK, clickConsole);
createSliversButton = newCreateSliversButton;
createSliversButton.label = "Create Slivers";
createSliversButton.addEventListener(MouseEvent.CLICK,
clickCreateSlivers);
bootSliversButton = newBootSliversButton;
bootSliversButton.label = "Boot Slivers";
bootSliversButton.addEventListener(MouseEvent.CLICK,
clickBootSlivers);
deleteSliversButton = newDeleteSliversButton;
deleteSliversButton.label = "Delete Slivers";
deleteSliversButton.addEventListener(MouseEvent.CLICK,
clickDeleteSlivers);
credential = newCredential;
clip = new ConsoleClip();
parent.addChild(clip);
clip.back.label = "Back";
clip.back.addEventListener(MouseEvent.CLICK, clickBack);
clip.visible = false;
queue = new DList();
working = false;
}
public function cleanup() : void
{
consoleButton.removeEventListener(MouseEvent.CLICK, clickConsole);
createSliversButton.removeEventListener(MouseEvent.CLICK,
clickCreateSlivers);
bootSliversButton.removeEventListener(MouseEvent.CLICK,
clickBootSlivers);
clip.back.removeEventListener(MouseEvent.CLICK, clickBack);
clip.parent.removeChild(clip);
}
public function discoverResources() : void
{
forEachComponent(discoverSliver);
}
function discoverSliver(index : int) : Request
{
var result : Request = null;
if (cm.getUrl(index) != null)
{
result = new RequestResourceDiscovery(index, cm);
}
return result;
}
function clickConsole(event : MouseEvent) : void
{
clip.visible = true;
}
function forEachComponent(func : Function) : void
{
var i : int = 0;
for (; i < cm.getCmCount(); ++i)
{
if (cm.getUrl(i) != null)
{
var newRequest = func(i);
if (newRequest != null)
{
queue.push_back(newRequest);
nodes.changeState(i, ActiveNodes.PENDING);
if (! working)
{
start();
}
}
}
}
}
function clickCreateSlivers(event : MouseEvent) : void
{
forEachComponent(createSliver);
}
function createSliver(index : int) : Request
{
var result : Request = null;
var rspec = nodes.getXml(index);
if (rspec != null)
{
if (credential.slivers[index] == null)
{
result = new RequestSliverCreate(index, nodes, cm, rspec);
}
else
{
result = new RequestSliverUpdate(index, nodes, cm, rspec);
}
}
return result;
}
function clickBootSlivers(event : MouseEvent) : void
{
forEachComponent(bootSliver);
}
function bootSliver(index : int) : Request
{
var result : Request = null;
if (nodes.existsState(index, ActiveNodes.CREATED))
{
result = new RequestSliverStart(index, nodes, cm.getUrl(index));
}
return result;
}
function clickDeleteSlivers(event : MouseEvent) : void
{
forEachComponent(deleteSliver);
}
function deleteSliver(index : int) : Request
{
var result : Request = null;
if (nodes.existsState(index, ActiveNodes.PENDING)
|| nodes.existsState(index, ActiveNodes.CREATED)
|| nodes.existsState(index, ActiveNodes.BOOTED))
{
result = new RequestSliverDestroy(index, nodes, cm.getUrl(index));
}
return result;
}
function clickBack(event : MouseEvent) : void
{
clip.visible = false;
}
function start() : void
{
if (! queue.isEmpty())
{
var front = queue.front();
var op = front.start(credential);
clip.text.appendText(Util.getSend(front.getOpName(),
""));
clip.text.scrollV = clip.text.maxScrollV;
op.call(complete, failure);
clip.text.appendText(front.getSendXml());
clip.text.scrollV = clip.text.maxScrollV;
working = true;
}
else
{
working = false;
}
}
function failure(event : ErrorEvent, fault : MethodFault) : void
{
clip.text.appendText(Util.getFailure(queue.front().getOpName(),
event, fault));
clip.text.scrollV = clip.text.maxScrollV;
queue.front().fail();
queue.front().cleanup();
queue.pop_front();
start();
}
function complete(code : Number, response : Object) : void
{
clip.text.appendText(Util.getResponse(queue.front().getOpName(),
queue.front().getResponseXml()));
clip.text.scrollV = clip.text.maxScrollV;
var next : Request = queue.front().complete(code, response, credential);
queue.front().cleanup();
queue.pop_front();
if (next != null)
{
queue.push_back(next);
}
start();
}
var clip : ConsoleClip;
var nodes : ActiveNodes;
var cm : ComponentManager;
var consoleButton : Button;
var createSliversButton : Button;
var bootSliversButton : Button;
var deleteSliversButton : Button;
var queue : DList;
var working : Boolean;
var credential : Credential;
}
}
package
{
class Credential
{
public function Credential() : void
{
base = null;
slice = null;
slivers = null;
}
public function setupSlivers(count : int)
{
slivers = new Array();
var i : int = 0;
for (; i < count; ++i)
{
slivers.push(null);
}
}
public var base : String;
public var slice : String;
public var slivers : Array;
}
}
package
{
public class DIterator
{
public function DIterator() : void
{
this.current = null;
}
public function get() : *
{
if(this.current == null)
{
return null;
}
else
{
return this.current.data;
}
}
public function isValid() : Boolean
{
return this.current != null;
}
public function increment() : void
{
if(this.current != null)
{
this.current = this.current.next;
}
}
public function decrement() : void
{
if(this.current != null)
{
this.current = this.current.prev;
}
}
public function copyFrom(right : DIterator) : void
{
this.current = right.current;
}
public function getNode() : DNode
{
return this.current;
}
public function setNode(newNode : DNode) : void
{
this.current = newNode;
}
protected var current : DNode;
}
}
package
{
public class DList
{
public function DList() : void
{
this.head = null;
this.tail = null;
currentSize = 0;
}
public function size() : int
{
return currentSize;
}
public function isEmpty() : Boolean
{
return this.head == null;
}
public function frontIterator() : DIterator
{
var result : DIterator = new DIterator();
result.setNode(this.head);
return result;
}
public function backIterator() : DIterator
{
var result : DIterator = new DIterator();
result.setNode(this.tail);
return result;
}
public function insert(pos : DIterator,newData : *) : DIterator
{
var result : DIterator = new DIterator();
if(!pos.isValid())
{
this.push_back(newData);
result.setNode(this.tail);
}
else if(pos.getNode() == this.head)
{
this.push_front(newData);
result.setNode(this.head);
}
else
{
var newNode : DNode = new DNode();
newNode.data = newData;
newNode.prev = pos.getNode().prev;
newNode.next = pos.getNode();
pos.getNode().prev.next = newNode;
pos.getNode().prev = newNode;
result.setNode(newNode);
}
++currentSize;
return result;
}
public function erase(pos : DIterator) : DIterator
{
var result : DIterator = new DIterator();
if(pos.isValid())
{
if(pos.getNode() == this.head)
{
this.pop_front();
result.setNode(this.head);
}
else if(pos.getNode() == this.tail)
{
this.pop_back();
result.setNode(this.tail);
}
else
{
pos.getNode().prev.next = pos.getNode().next;
pos.getNode().next.prev = pos.getNode().prev;
result.setNode(pos.getNode().next);
}
--currentSize;
}
return result;
}
public function remove(value : *) : void
{
var pos = find(value);
if (pos.isValid())
{
erase(pos);
}
}
// Returns an iterator pointing to value or an invalid iterator
public function find(value : *) : DIterator
{
var current = frontIterator();
for (; current.isValid(); current.increment())
{
if (current.get() == value)
{
break;
}
}
return current;
}
public function front() : *
{
if(this.head != null)
{
return this.head.data;
}
else
{