package org.archstudio.aim.core;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.archstudio.aim.ArchitectureInstantiationException;
import org.archstudio.aim.IAIM;
import org.archstudio.aim.core.AIMInstantiationOrderCalculator.OrderedGroup;
import org.archstudio.myx.fw.EMyxInterfaceDirection;
import org.archstudio.myx.fw.IMyxBrickDescription;
import org.archstudio.myx.fw.IMyxBrickInitializationData;
import org.archstudio.myx.fw.IMyxName;
import org.archstudio.myx.fw.IMyxProgressMonitor;
import org.archstudio.myx.fw.IMyxRuntime;
import org.archstudio.myx.fw.IMyxWeld;
import org.archstudio.myx.fw.MyxBasicBrickInitializationData;
import org.archstudio.myx.fw.MyxBrickCreationException;
import org.archstudio.myx.fw.MyxBrickLoadException;
import org.archstudio.myx.fw.MyxContainer;
import org.archstudio.myx.fw.MyxJavaClassInterfaceDescription;
import org.archstudio.myx.fw.MyxNullProgressMonitor;
import org.archstudio.myx.fw.MyxSubProgressMonitor;
import org.archstudio.myx.fw.MyxUnsupportedBrickDescriptionException;
import org.archstudio.myx.fw.MyxUtils;
import org.archstudio.myx.java.MyxJavaClassBrickDescription;
import org.archstudio.xadl.XadlUtils;
import org.archstudio.xadl.myx.IMyxBrickDescriptionFromXadl;
import org.archstudio.xadl.myx.MyxGenBrickDescriptionFromXadl;
import org.archstudio.xadl.myx.MyxJavaClassBrickDescriptionFromXadl;
import org.archstudio.xadl.myx.MyxOSGiBrickDescriptionFromXadl;
import org.archstudio.xadl3.implementation_3_0.Implementation_3_0Package;
import org.archstudio.xadl3.javaimplementation_3_0.Javaimplementation_3_0Package;
import org.archstudio.xadl3.lookupimplementation_3_0.Lookupimplementation_3_0Package;
import org.archstudio.xadl3.structure_3_0.Direction;
import org.archstudio.xarchadt.IXArchADT;
import org.archstudio.xarchadt.ObjRef;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class AIMImpl implements IAIM {
protected IXArchADT xarch = null;
protected IMyxRuntime myx = null;
protected IMyxBrickDescription containerDescription = new MyxJavaClassBrickDescription(MyxContainer.class.getName());
public AIMImpl() {
}
public AIMImpl(IXArchADT xarch, IMyxRuntime myx) {
this.xarch = xarch;
this.myx = myx;
}
public synchronized void setXArch(IXArchADT xarch) {
this.xarch = xarch;
}
public synchronized void setMyxRuntime(IMyxRuntime myxruntime) {
this.myx = myxruntime;
}
@Override
public synchronized void instantiate(String name, ObjRef documentRootRef, ObjRef structureRef,
IMyxProgressMonitor monitor) throws ArchitectureInstantiationException {
if (myx == null) {
throw new IllegalStateException("AIMImpl has no Myx Runtime");
}
IMyxName containerName = MyxUtils.createName(name);
try {
myx.addBrick(IMyxRuntime.EMPTY_NAME_LIST, containerName, containerDescription, null);
instantiate(myx, documentRootRef, structureRef, Collections.singletonList(containerName), monitor);
}
catch (MyxUnsupportedBrickDescriptionException e) {
throw new ArchitectureInstantiationException("Myx cannot load brick description", e);
}
catch (MyxBrickLoadException mble) {
throw new ArchitectureInstantiationException("Myx cannot load brick", mble);
}
catch (MyxBrickCreationException mbce) {
throw new ArchitectureInstantiationException("Myx cannot create brick", mbce);
}
}
@Override
public synchronized void begin(String name, IMyxProgressMonitor monitor) {
if (myx == null) {
throw new IllegalStateException("AIMImpl has no Myx Runtime");
}
IMyxName containerName = MyxUtils.createName(name);
myx.begin(IMyxRuntime.EMPTY_NAME_LIST, containerName);
}
@Override
public synchronized void end(String name, IMyxProgressMonitor monitor) {
if (myx == null) {
throw new IllegalStateException("AIMImpl has no Myx Runtime");
}
IMyxName containerName = MyxUtils.createName(name);
myx.end(IMyxRuntime.EMPTY_NAME_LIST, containerName);
}
@Override
public synchronized void destroy(String name, IMyxProgressMonitor monitor) {
if (myx == null) {
throw new IllegalStateException("AIMImpl has no Myx Runtime");
}
IMyxName containerName = MyxUtils.createName(name);
try {
myx.destroy(IMyxRuntime.EMPTY_NAME_LIST, containerName);
}
finally {
myx.removeBrick(IMyxRuntime.EMPTY_NAME_LIST, containerName);
}
}
private static class AIMInterfaceData {
public EMyxInterfaceDirection myxDirection;
public List<IMyxName> containerPath;
public IMyxName brickName;
public IMyxName interfaceName;
public List<String> serviceObjectInterfaceNames;
/* Following are not used for non-mapped interfaces */
public IMyxName internalBrickName;
public IMyxName internalBrickInterfaceName;
}
public void instantiate(IMyxRuntime myx, ObjRef xArchRef, ObjRef structureRef, List<IMyxName> containerPath,
IMyxProgressMonitor monitor) throws ArchitectureInstantiationException,
MyxUnsupportedBrickDescriptionException {
if (monitor == null) {
monitor = new MyxNullProgressMonitor();
}
monitor.beginTask("Instantiating " + xarch.get(structureRef, "name"), 3);
// Let's do the components+connectors
// This routine orders the bricks in dependency order
List<? extends OrderedGroup> orderedGroups = AIMInstantiationOrderCalculator.calculateInstantiationOrder(xarch,
structureRef);
monitor.worked(1);
// Iterate through the list and instantiate.
IMyxProgressMonitor brickGroupsMonitor = new MyxSubProgressMonitor(monitor, 1,
MyxSubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
brickGroupsMonitor.beginTask("Brick", orderedGroups.size());
for (OrderedGroup group : orderedGroups) {
for (ObjRef brickRef : group.getBrickRefs()) {
brickGroupsMonitor.subTask((String) xarch.get(brickRef, "name"));
String brickID = XadlUtils.getID(xarch, brickRef);
if (brickID == null) {
throw new ArchitectureInstantiationException("Brick missing ID: " + brickRef);
}
IMyxName myxBrickName = MyxUtils.createName(brickID);
//System.err.println("Processing brick: " + XadlUtils.getName(xarch, brickRef));
ObjRef subStructureRef = (ObjRef) xarch.get(brickRef, "subStructure");
if (subStructureRef != null) {
//Process subarchitecture
//Create the container:
IMyxName containerName = MyxUtils.createName(brickID);
try {
myx.addBrick(containerPath, containerName, containerDescription, null);
}
catch (MyxBrickLoadException mble) {
throw new ArchitectureInstantiationException("Myx cannot load brick", mble);
}
catch (MyxBrickCreationException mbce) {
throw new ArchitectureInstantiationException("Myx cannot create brick", mbce);
}
ObjRef innerStructureRef = (ObjRef) xarch.get(subStructureRef, "innerStructureLink");
if (innerStructureRef == null) {
throw new ArchitectureInstantiationException("Invalid inner structure link on brick "
+ XadlUtils.getName(xarch, brickRef));
}
//This is easy enough; we just recurse.
List<IMyxName> innerContainerPath = new ArrayList<IMyxName>(containerPath.size() + 1);
innerContainerPath.addAll(containerPath);
innerContainerPath.add(containerName);
instantiate(myx, xArchRef, innerStructureRef, innerContainerPath, new MyxSubProgressMonitor(
brickGroupsMonitor, 1));
//Okay, the container is created and added; its inner structure is all
//set up, now we have to go about creating and mapping all its interfaces.
for (ObjRef interfaceRef : Iterables.filter(xarch.getAll(brickRef, "interface"), ObjRef.class)) {
AIMInterfaceData aid = parseAndValidateMappedInterfaceData(containerPath, brickRef,
interfaceRef);
MyxJavaClassInterfaceDescription aidDesc = new MyxJavaClassInterfaceDescription(
aid.serviceObjectInterfaceNames);
myx.addContainerInterface(aid.containerPath, aid.brickName, aid.interfaceName, aidDesc,
aid.myxDirection, aid.internalBrickName, aid.internalBrickInterfaceName);
}
}
else {
IMyxBrickInitializationData initData = null;
ObjRef initializationParametersRef = XadlUtils.getImplementation(xarch, brickRef,
Implementation_3_0Package.Literals.INITIALIZATION_PARAMETERS_IMPLEMENTATION);
if (initializationParametersRef != null) {
Map<String, String> initializationParameters = getProperties(initializationParametersRef);
if (initializationParameters != null) {
initData = new MyxBasicBrickInitializationData(initializationParameters);
}
}
IMyxBrickDescription myxBrickDescription = null;
List<IMyxBrickDescriptionFromXadl> implParsers = Lists.newArrayList();
//TODO: use some extension mechanisms
implParsers.add(new MyxGenBrickDescriptionFromXadl());
implParsers.add(new MyxOSGiBrickDescriptionFromXadl());
implParsers.add(new MyxJavaClassBrickDescriptionFromXadl());
for (IMyxBrickDescriptionFromXadl implParser : implParsers) {
myxBrickDescription = implParser.parse(xarch, brickRef);
if (myxBrickDescription != null) {
break;
}
}
if (myxBrickDescription == null) {
throw new ArchitectureInstantiationException("Myx cannot parse brick implementation");
}
try {
myx.addBrick(containerPath, myxBrickName, myxBrickDescription, initData);
}
catch (MyxBrickLoadException mble) {
throw new ArchitectureInstantiationException("Myx cannot load brick", mble);
}
catch (MyxBrickCreationException mbce) {
throw new ArchitectureInstantiationException("Myx cannot create brick", mbce);
}
//Okay, the brick is created and added; now we have to go about
//creating all its interfaces.
for (ObjRef interfaceRef : Iterables.filter(xarch.getAll(brickRef, "interface"), ObjRef.class)) {
AIMInterfaceData aid = parseAndValidateInterfaceData(containerPath, brickRef, interfaceRef);
MyxJavaClassInterfaceDescription aidDesc = new MyxJavaClassInterfaceDescription(
aid.serviceObjectInterfaceNames);
myx.addInterface(aid.containerPath, aid.brickName, aid.interfaceName, aidDesc, aid.myxDirection);
}
//System.err.println("initing " + myxBrickName);
myx.init(containerPath, myxBrickName);
}
}
brickGroupsMonitor.worked(1);
}
brickGroupsMonitor.done();
//Process the links
IMyxProgressMonitor linkGroupsMonitor = new MyxSubProgressMonitor(monitor, 1,
MyxSubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
linkGroupsMonitor.beginTask("Links", orderedGroups.size());
for (OrderedGroup group : orderedGroups) {
for (ObjRef linkRef : group.getLinkRefs()) {
linkGroupsMonitor.subTask((String) xarch.get(linkRef, "name"));
ObjRef interface1Ref = (ObjRef) xarch.get(linkRef, "point1");
if (interface1Ref == null) {
throw new ArchitectureInstantiationException("Link " + XadlUtils.getName(xarch, linkRef)
+ " has invalid point 1 link.");
}
ObjRef interface2Ref = (ObjRef) xarch.get(linkRef, "point2");
if (interface2Ref == null) {
throw new ArchitectureInstantiationException("Link " + XadlUtils.getName(xarch, linkRef)
+ " has invalid point 2 link.");
}
Direction direction1 = (Direction) xarch.get(interface1Ref, "direction");
if (direction1 == null) {
throw new ArchitectureInstantiationException("Interface " + XadlUtils.getName(xarch, interface1Ref)
+ " missing direction.");
}
Direction direction2 = (Direction) xarch.get(interface2Ref, "direction");
if (direction2 == null) {
throw new ArchitectureInstantiationException("Interface " + XadlUtils.getName(xarch, interface1Ref)
+ " missing direction.");
}
if (!(direction1.equals(Direction.IN) && direction2.equals(Direction.OUT) || direction1
.equals(Direction.OUT) && direction2.equals(Direction.IN))) {
throw new ArchitectureInstantiationException("Link " + XadlUtils.getName(xarch, linkRef)
+ " links two interfaces with incompatible directions.");
}
ObjRef providedInterfaceRef = null;
ObjRef requiredInterfaceRef = null;
if (direction1.equals(Direction.IN)) {
providedInterfaceRef = interface1Ref;
requiredInterfaceRef = interface2Ref;
}
else {
requiredInterfaceRef = interface1Ref;
providedInterfaceRef = interface2Ref;
}
//Okay, we have both the provided and required interface refs.
ObjRef providedBrickRef = xarch.getParent(providedInterfaceRef);
if (providedBrickRef == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, providedInterfaceRef) + " missing parent.");
}
ObjRef requiredBrickRef = xarch.getParent(requiredInterfaceRef);
if (requiredBrickRef == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, requiredInterfaceRef) + " missing parent.");
}
String providedBrickID = XadlUtils.getID(xarch, providedBrickRef);
if (providedBrickID == null) {
throw new ArchitectureInstantiationException("Brick " + XadlUtils.getName(xarch, providedBrickRef)
+ " missing ID.");
}
String requiredBrickID = XadlUtils.getID(xarch, requiredBrickRef);
if (requiredBrickID == null) {
throw new ArchitectureInstantiationException("Brick " + XadlUtils.getName(xarch, requiredBrickRef)
+ " missing ID.");
}
String providedInterfaceID = XadlUtils.getID(xarch, providedInterfaceRef);
if (providedInterfaceID == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, providedInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, providedBrickRef) + " missing ID.");
}
String requiredInterfaceID = XadlUtils.getID(xarch, requiredInterfaceRef);
if (requiredInterfaceID == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, requiredInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, requiredBrickRef) + " missing ID.");
}
ObjRef providedLookupImplementationRef = XadlUtils.getImplementation(xarch, providedInterfaceRef,
Lookupimplementation_3_0Package.Literals.LOOKUP_IMPLEMENTATION);
if (providedLookupImplementationRef == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, providedInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, providedBrickRef) + " missing lookup implementation.");
}
ObjRef requiredLookupImplementationRef = XadlUtils.getImplementation(xarch, requiredInterfaceRef,
Lookupimplementation_3_0Package.Literals.LOOKUP_IMPLEMENTATION);
if (requiredLookupImplementationRef == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, requiredInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, requiredBrickRef) + " missing lookup implementation.");
}
String providedLookupImplementationName = (String) xarch.get(providedLookupImplementationRef, "lookup");
if (providedLookupImplementationName == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, providedInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, providedBrickRef) + " missing lookup implementation info.");
}
String requiredLookupImplementationName = (String) xarch.get(requiredLookupImplementationRef, "lookup");
if (requiredLookupImplementationName == null) {
throw new ArchitectureInstantiationException("Interface "
+ XadlUtils.getName(xarch, requiredInterfaceRef) + " on brick "
+ XadlUtils.getName(xarch, requiredBrickRef) + " missing lookup implementation info.");
}
IMyxWeld weld = myx.createWeld(
/* Required */
containerPath, MyxUtils.createName(requiredBrickID),
MyxUtils.createName(requiredLookupImplementationName),
/* Provided */
containerPath, MyxUtils.createName(providedBrickID),
MyxUtils.createName(providedLookupImplementationName));
try {
myx.addWeld(weld);
}
catch (Exception e) {
throw new ArchitectureInstantiationException("Problem adding weld or invalid weld: "
+ weld.toString(), e);
}
}
linkGroupsMonitor.worked(1);
}
linkGroupsMonitor.done();
monitor.done();
}
private AIMInterfaceData parseAndValidateInterfaceData(List<IMyxName> containerPath, ObjRef brickRef,
ObjRef interfaceRef) throws ArchitectureInstantiationException {
String interfaceID = XadlUtils.getID(xarch, interfaceRef);
if (interfaceID == null) {
throw new ArchitectureInstantiationException("Missing ID on interface: "
+ XadlUtils.getName(xarch, interfaceRef) + " on brick " + XadlUtils.getName(xarch, brickRef));
}
//We have to get the implementation lookup name for the interface.
ObjRef lookupImplementationRef = XadlUtils.getImplementation(xarch, interfaceRef,
Lookupimplementation_3_0Package.Literals.LOOKUP_IMPLEMENTATION);
if (lookupImplementationRef == null) {
throw new ArchitectureInstantiationException("Missing lookup implementation on interface "
+ XadlUtils.getName(xarch, interfaceRef));
}
String lookupImplementationName = (String) xarch.get(lookupImplementationRef, "lookup");
if (lookupImplementationName == null) {
throw new ArchitectureInstantiationException("Missing lookup implementation name on interface "
+ XadlUtils.getName(xarch, interfaceRef));
}
Direction direction = (Direction) xarch.get(interfaceRef, "direction");
if (direction == null) {
throw new ArchitectureInstantiationException("Missing direction on interface "
+ XadlUtils.getName(xarch, interfaceRef));
}
EMyxInterfaceDirection myxDirection = null;
if (direction.equals(Direction.IN)) {
myxDirection = EMyxInterfaceDirection.IN;
}
else if (direction.equals(Direction.OUT)) {
myxDirection = EMyxInterfaceDirection.OUT;
}
else {
throw new ArchitectureInstantiationException("Invalid direction (not in/out) on interface "
+ XadlUtils.getName(xarch, interfaceRef));
}
List<String> serviceObjectInterfaceNames = new ArrayList<String>();
ObjRef javaImplementationRef = XadlUtils.getImplementation(xarch, interfaceRef,
Javaimplementation_3_0Package.Literals.JAVA_IMPLEMENTATION);
if (javaImplementationRef != null) {
List<ObjRef> classRefs = new ArrayList<ObjRef>();
ObjRef mainClassRef = (ObjRef) xarch.get(javaImplementationRef, "mainClass");
if (mainClassRef != null) {
classRefs.add(mainClassRef);
}
classRefs.addAll(Lists.newArrayList(Iterables.filter(xarch.getAll(javaImplementationRef, "auxClass"),
ObjRef.class)));
for (ObjRef classRef : classRefs) {
String className = (String) xarch.get(classRef, "className");
if (className != null) {
serviceObjectInterfaceNames.add(className);
}
}
}
AIMInterfaceData aid = new AIMInterfaceData();
aid.myxDirection = myxDirection;
aid.containerPath = containerPath;
aid.brickName = MyxUtils.createName(XadlUtils.getID(xarch, brickRef));
aid.interfaceName = MyxUtils.createName(lookupImplementationName);
aid.serviceObjectInterfaceNames = serviceObjectInterfaceNames;
return aid;
}
private AIMInterfaceData parseAndValidateMappedInterfaceData(List<IMyxName> containerPath, ObjRef brickRef,
ObjRef interfaceRef) throws ArchitectureInstantiationException {
AIMInterfaceData aid = parseAndValidateInterfaceData(containerPath, brickRef, interfaceRef);
ObjRef subStructureRef = (ObjRef) xarch.get(brickRef, "subStructure");
if (subStructureRef == null) {
throw new ArchitectureInstantiationException("Can't find subarchitecture for brick "
+ XadlUtils.getName(xarch, brickRef));
}
ObjRef innerStructureRef = (ObjRef) xarch.get(subStructureRef, "innerStructureLink");
if (innerStructureRef == null) {
throw new ArchitectureInstantiationException("Invalid inner structure link for brick "
+ XadlUtils.getName(xarch, brickRef));
}
for (ObjRef interfaceMappingRef : Iterables.filter(xarch.getAll(subStructureRef, "interfaceMapping"),
ObjRef.class)) {
ObjRef outerInterfaceRef = (ObjRef) xarch.get(interfaceMappingRef, "outerInterfaceLink");
if (outerInterfaceRef == null) {
throw new ArchitectureInstantiationException("Invalid outer interface link for mapping "
+ XadlUtils.getName(xarch, interfaceMappingRef) + " on brick "
+ XadlUtils.getName(xarch, brickRef));
}
ObjRef innerInterfaceRef = (ObjRef) xarch.get(interfaceMappingRef, "innerInterfaceLink");
if (innerInterfaceRef == null) {
throw new ArchitectureInstantiationException("Invalid inner interface link for mapping "
+ XadlUtils.getName(xarch, interfaceMappingRef) + " on brick "
+ XadlUtils.getName(xarch, brickRef));
}
if (outerInterfaceRef.equals(interfaceRef)) {
//This is a mapping for our interface.
ObjRef innerBrickRef = xarch.getParent(innerInterfaceRef);
if (innerBrickRef == null) {
throw new ArchitectureInstantiationException("Missing parent brick for interface "
+ XadlUtils.getName(xarch, innerInterfaceRef));
}
String innerBrickID = XadlUtils.getID(xarch, innerBrickRef);
if (innerBrickID == null) {
throw new ArchitectureInstantiationException("Missing ID on brick "
+ XadlUtils.getName(xarch, innerBrickRef));
}
ObjRef innerInterfaceLookupImplementationRef = XadlUtils.getImplementation(xarch, innerInterfaceRef,
Lookupimplementation_3_0Package.Literals.LOOKUP_IMPLEMENTATION);
if (innerInterfaceLookupImplementationRef == null) {
throw new ArchitectureInstantiationException("Missing lookup implementation on interface "
+ XadlUtils.getName(xarch, innerInterfaceRef));
}
String innerInterfaceLookupImplementationName = (String) xarch.get(
innerInterfaceLookupImplementationRef, "lookup");
if (innerInterfaceLookupImplementationName == null) {
throw new ArchitectureInstantiationException(
"Missing lookup implementation information on interface "
+ XadlUtils.getName(xarch, innerInterfaceRef));
}
aid.internalBrickName = MyxUtils.createName(innerBrickID);
aid.internalBrickInterfaceName = MyxUtils.createName(innerInterfaceLookupImplementationName);
return aid;
}
}
throw new ArchitectureInstantiationException("Could not find matching interface mapping for interface "
+ XadlUtils.getName(xarch, interfaceRef) + " on brick " + XadlUtils.getName(xarch, brickRef));
}
private Map<String, String> getProperties(ObjRef initializationParametersRef) {
Map<String, String> p = Maps.newHashMap();
for (ObjRef initializationParamRef : Iterables.filter(
xarch.getAll(initializationParametersRef, "initializationParameter"), ObjRef.class)) {
String name = (String) xarch.get(initializationParamRef, "key");
String value = (String) xarch.get(initializationParamRef, "value");
if (name != null && value != null) {
p.put(name, value);
}
}
return p;
}
}