Developing Components:
Using xArchADT

Using xArchADT

One of the most important components that you will call as an ArchStudio 3 component developer is xArchADT, the main data store for all architecture descriptions.

This component exposes one interface, called the XArchFlatInterface. The XArchFlatInterface is Javadoc-documented in the ArchStudio 3 distribution.

XArchFlatInterface is a distributable (that is, it doesn't pass pointers) version of the interface provided by the Data Binding Library. Additionally, it exposes some low-level convenience functions that are not available in the Data Binding Library, like "find by ID" and "jump to parent." In order to use XArchFlatInterface, you need to become familiar with the Data Binding Library. Please read through:

Now, let's look at how to translate traditional calls to the Data Binding Library into calls that go through XArchFlatInterface. The first major difference to note is that objects like IComponents and IConnectors never get passed across XArchFlatInterface. Instead, serializable object references, called ObjRefs, are sent instead. The next major difference is that, since ObjRefs are opaque, no calls are ever made on them directly. Instead, XArchFlatInterface does all the work for you.

Translating a call from a Data Binding Library call to an XArchFlatInterface call is easy, since it's merely a matter of rearranging some parameters. Here's a typical program snippet that calls the Data Binding Library from the Data Binding Library example program:

  //Create a new xArch element (i.e. a xADL 2.0 document)
  IXArch xArch = XArchUtils.createXArch();
  //Create an instance context in which we can create objects in the instances namespace.
  InstanceContext instances = new InstanceContext(xArch);
  //Create an ArchInstance element, suitable for adding as a child to the IXArch object.
  IArchInstance archInstance = instances.createArchInstanceElement();
  //Add the ArchInstance element as a child of the IXArch element.
  xArch.addObject(archInstance);

Now, let's look at how to translate each of these calls into an XArchFlatInterface call to achieve the desired effect.

First, let's look at this call:

  //Create a new xArch element (i.e. a xADL 2.0 document)
  IXArch xArch = XArchUtils.createXArch();

In the XArchFlatInterface, the equivalent function is:

public ObjRef createXArch(String url);

This creates a new XArch element in xArchADT with the given URL. Whereas the Data Binding Library doesn't require URLs to be associated with each xADL 2.0 document, xArchADT does. This URL can be a real URL, like an http:// URL or a local URL, like a urn:MyURL URL. Instead of returning an object that implements the interface IXArch, this function returns an ObjRef to the object. The object remains inside xArchADT. Any references we make to it from this point on must be through the ObjRef.

So, assuming our local proxy for the XArchFlatInterface is called "flat," our equivalent call will be:

  ObjRef xArchRef = flat.createXArch("urn:MyArchitecture");

Now, we want to create an instance context. Again, this context object will remain inside xArchADT and will be accessible only through an ObjRef. The old call was:

  //Create an instance context in which we can create objects in the instances namespace.
  InstanceContext instances = new InstanceContext(xArch);

The equivalent call in XArchFlatInterface is:

  public ObjRef createContext(ObjRef xArchObject,
                              String contextType);

The first parameter is an ObjRef to the XArch object, which we got from the previous call. The second parameter is a string indicating what "kind" of context we want to create--in this case, an Instance context. The call to create a context is the same, no matter which context we're creating. So, if we look at the old call,

  InstanceContext instances = new InstanceContext(xArch);
The text in bold is the contextType in our new call. Therefore, our new call becomes:
  ObjRef instanceContextRef = flat.createContext(xArchRef, "Instance");

Now let's look at the third call:

  //Create an ArchInstance element, suitable for adding as a child to the IXArch object.
  IArchInstance archInstance = instances.createArchInstanceElement();

The equivalent function we're looking for in XArchFlatInterface is:

  public ObjRef createElement(ObjRef contextObjectRef,
                              String typeOfThing);

This function's first parameter is an ObjRef to a context object. We got that from the previous call. The second parameter is the "kind" of thing to create. Again, we get this from the previous method call's name:

  IArchInstance archInstance = instances.createArchInstanceElement();

So, our new call is:

  ObjRef archInstanceRef = flat.createElement(instanceContextRef, "ArchInstance");

Finally, let's take a look at the last call:

  //Add the ArchInstance element as a child of the IXArch element.
  xArch.addObject(archInstance);

The equivalent call in XArchFlatInterface is:

  public void add(ObjRef baseObjectRef,
                  String typeOfThing,
                  ObjRef thingToAddRef);

The first parameter to this call is the base object reference--the parent of the new child we're adding. That's the xArchRef that we got when we created it in the first call. The second parameter is, again, the type of thing we're adding. We get this from the old method name, as usual:

  xArch.addObject(archInstance);

The third parameter is an ObjRef to the child we're adding. That's the archInstanceRef we just got with our createElement call. So, our new call is:

  flat.add(xArchRef, "Object", archInstanceRef);

So, we've translated this simple snippet:

  //Create a new xArch element (i.e. a xADL 2.0 document)
  IXArch xArch = XArchUtils.createXArch();
  //Create an instance context in which we can create objects in the instances namespace.
  InstanceContext instances = new InstanceContext(xArch);
  //Create an ArchInstance element, suitable for adding as a child to the IXArch object.
  IArchInstance archInstance = instances.createArchInstanceElement();
  //Add the ArchInstance element as a child of the IXArch element.
  xArch.addObject(archInstance);

Into this equivalent one...

  //Create a new xArch element (i.e. a xADL 2.0 document)
  ObjRef xArchRef = flat.createXArch("urn:MyArchitecture");
  //Create an instance context in which we can create objects in the instances namespace.
  ObjRef instanceContextRef = flat.createContext(xArchRef, "Instance");
  //Create an ArchInstance element, suitable for adding as a child to the IXArch object.
  ObjRef archInstanceRef = flat.createElement(instanceContextRef, "ArchInstance");
  //Add the ArchInstance element as a child of the IXArch element.
  flat.add(xArchRef, "Object", archInstanceRef);

By now, you've probably noticed that there are a lot of ObjRefs floating around. Due to the generality of the XArchFlatInterface, it's impossible for the Java compiler to type-check all the ObjRefs being passed into it. So, you could pass an ObjRef to a context object where an ObjRef for an IXArch object should go. If this happens, it will cause a runtime exception, most likely an IllegalArgumentException to be thrown.
Here, we present a table that shows which calls in the Data Binding Libraries map to which calls in the XArchFlatInterface:

Old CallFunctionNew Call
XArchUtils.createXArch() Create a new xADL 2.0 document public ObjRef createXArch(String url)
XArchUtils.parseFromFile(...) Parse a xADL 2.0 document from a file public ObjRef parseFromFile(String fileName) throws FileNotFoundException, IOException, SAXException
XArchUtils.parseFromURL(...) Parse a xADL 2.0 document from a URL public ObjRef parseFromURL(String urlString) throws MalformedURLException, IOException, SAXException
(No Call) Close an open xADL 2.0 document public void close(String urlString)
XArchUtils.getPrettyXMLRepresentation(...) Serialize a xADL 2.0 document into XML public String serialize(ObjRef xArchRef);
PackageContext foo = new PackageContext(IXArch xArch) Create a new context object. public ObjRef createContext(ObjRef xArchObject, String contextType)
IType PackageContext.createType() Create a new element. public ObjRef create(ObjRef contextObjectRef, String typeOfThing)
IType PackageContext.createTypeElement() Create a new top-level element (i.e. one that will be a child of the <xArch> tag). public ObjRef createElement(ObjRef contextObjectRef, String typeOfThing)
IPromotedType PackageContext.promoteToBaseType(IBaseType) Promote a base type to one of its subtypes. public ObjRef promoteTo(ObjRef contextObjectRef, String promotionTarget, ObjRef targetObjectRef)
IType PackageContext.recontextualizeType(IType) Change an element's context so it can be used in a different setting. public ObjRef recontextualize(ObjRef contextObjectRef, String typeOfThing, ObjRef targetObjectRef)
IXArch IType.getXArch() Gets the xArch element that is the top-level element of the document containing the given element. public ObjRef getXArch(ObjRef baseObjectRef)
IType PackageContext.getTypeElement(IXArch) Gets a child of the <xArch> tag. public ObjRef getElement(ObjRef contextObjectRef, String typeOfThing, ObjRef xArchObjectRef)
String IType.getClass().getName() Gets the true class name of a given element. public String getType(ObjRef baseObjectRef)
IType instanceof someClass Determines if a given element is an instance of a given class or interface. public boolean isInstanceOf(ObjRef baseObjectRef, String className)
void IType.addChildType(IChildType child); Add a child of ChildType to the object of type IType public void add(ObjRef baseObjectRef, String typeOfThing, ObjRef thingToAddRef)
void IType.addChildTypes(Collection children); Add several children of ChildType to the object of type IType public void add(ObjRef baseObjectRef, String typeOfThing, ObjRef[] thingsToAddRefs)
void IType.clearChildTypes(); Clear all children of ChildType from the object of type IType public void clear(ObjRef baseObjectRef, String typeOfThing)
IChildType IType.getChildType(); Gets a single child of ChildType from the object of type IType public Object get(ObjRef baseObjectRef, String typeOfThing)
IChildType IType.getChildType(String id); Gets a single child of ChildType from the object of type IType, using the child's ID as a selector. public ObjRef get(ObjRef baseObjectRef, String typeOfThing, String id)
Collection IType.getChildType(Collection ids); Gets a set of children of ChildType from the object of type IType, using the childrens' IDs as selectors. public ObjRef[] get(ObjRef baseObjectRef, String typeOfThing, String[] ids)
Collection IType.getAllChildTypes(); Gets all children of ChildType from the object of type IType public ObjRef[] getAll(ObjRef baseObjectRef, String typeOfThing)
boolean IType.hasChildType(String valueToCheck); Determines if the child of IType, of type ChildType, has the given value. public boolean has(ObjRef baseObjectRef, String typeOfThing, String valueToCheck)
boolean IType.hasChildType(IChildType valueToCheck); Determines if the child of IType, of type ChildType, is equivalent to the given value. public boolean has(ObjRef baseObjectRef, String typeOfThing, ObjRef valueToCheck)
boolean IType.hasAllChildTypes(Collection valuesToCheck); Determines if the child of IType, of type ChildType, has children equivalent to all the given values. public boolean hasAll(ObjRef baseObjectRef, String typeOfThing, ObjRef[] valuesToCheck)
Collection IType.hasChildTypes(Collection valuesToCheck); Determines if the child of IType, of type ChildType, has children equivalent to all the given values. public boolean[] has(ObjRef baseObjectRef, String typeOfThing, ObjRef[] thingsToCheck)
void IType.removeChildType(IChildType childToRemove); Removes a single child of ChildType from the object of type IType. public void remove(ObjRef baseObjectRef, String typeOfThing, ObjRef thingToRemove)
void IType.removeChildType(Collection childrenToRemove); Removes a set of children of ChildType from the object of type IType. public void remove(ObjRef baseObjectRef, String typeOfThing, ObjRef[] thingsToRemove)
void IType.setChildType(String valueToSet); Sets a single string-value child of ChildType on the object of type IType. public void set(ObjRef baseObjectRef, String typeOfThing, String value)
void IType.setChildType(IChildType childToSet); Sets a single object-value child of ChildType on the object of type IType. public void set(ObjRef baseObjectRef, String typeOfThing, ObjRef value)
boolean IType.isEqual(IType objectToCompare); Determines if two objects are equal by comparing their IDs. public boolean isEqual(ObjRef baseObjectRef, ObjRef thingToCheck)
boolean IType.isEquivalent(IType objectToCompare); Determines if two objects are equivalent by comparing their content, but ignoring their IDs. public boolean isEquivalent(ObjRef baseObjectRef, ObjRef thingToCheck)
(No Call) Get the parent of a given element. public ObjRef getParent(ObjRef targetObjectRef)
(No Call) Get all the ancestors of a given element. public ObjRef[] getAllAncestors(ObjRef targetObjectRef)
(No Call) Resolve an href, as might be found in an XLink. public ObjRef resolveHref(ObjRef xArchRef, String href)
(No Call) Get a list of open xADL 2.0 documents' URLs. public String[] getOpenXArchURLs()
(No Call) Get an ObjRef to the IXArch element of an open xADL 2.0 document. public ObjRef getOpenXArch(String url)
(No Call) Get an element by its ID, no matter where it is in a document. public ObjRef getByID(ObjRef xArchRef, String id)

xArchADT Events

As an event-based component, any change to the internal state of xArchADT is reported through an event. One type of event, an XArchFileEvent, is handled by the Hello World Component. However, a second type of event, the XArchFlatEvent is similarly emitted whenever the internal structure of one of the open xADL 2.0 documents is changed.

It is your responsibility as a component developer to ensure that your component acts correctly when it receives an XArchFlatEvent or any similar event. Assumptions to the contrary need to be well documented.