package jadex.application;
import jadex.application.model.MApplicationInstance;
import jadex.application.model.MApplicationType;
import jadex.application.model.MComponentInstance;
import jadex.application.model.MComponentType;
import jadex.application.model.MExpressionType;
import jadex.application.model.MProvidedServiceType;
import jadex.application.model.MRequiredServiceType;
import jadex.application.model.MSpaceInstance;
import jadex.application.model.MSpaceType;
import jadex.bridge.Argument;
import jadex.commons.ResourceInfo;
import jadex.commons.SReflect;
import jadex.commons.Tuple;
import jadex.commons.collection.IndexMap;
import jadex.commons.collection.MultiCollection;
import jadex.javaparser.IExpressionParser;
import jadex.javaparser.IParsedExpression;
import jadex.javaparser.SJavaParser;
import jadex.javaparser.javaccimpl.JavaCCExpressionParser;
import jadex.xml.AccessInfo;
import jadex.xml.AttributeConverter;
import jadex.xml.AttributeInfo;
import jadex.xml.IContext;
import jadex.xml.IPostProcessor;
import jadex.xml.IStringObjectConverter;
import jadex.xml.MappingInfo;
import jadex.xml.ObjectInfo;
import jadex.xml.StackElement;
import jadex.xml.SubobjectInfo;
import jadex.xml.TypeInfo;
import jadex.xml.XMLInfo;
import jadex.xml.bean.BeanObjectReaderHandler;
import jadex.xml.reader.ReadContext;
import jadex.xml.reader.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLReporter;
import javax.xml.stream.XMLStreamException;
/**
* Reader for loading Application XML models into a Java representation states.
*/
public class ApplicationXMLReader
{
//-------- attributes --------
/** The reader instance. */
protected Reader reader;
/** The mappings. */
protected Set[] mappings;
//-------- constructors --------
/**
* Create a new reader.
*/
public ApplicationXMLReader(Set[] mappings)
{
this.reader = new Reader(new BeanObjectReaderHandler(getXMLMapping(mappings)), false, false, new XMLReporter()
{
public void report(String msg, String type, Object info, Location location) throws XMLStreamException
{
// System.out.println("XML error: "+msg+", "+type+", "+info+", "+location);
IContext context = (IContext)Reader.READ_CONTEXT.get();
MultiCollection report = (MultiCollection)context.getUserContext();
String pos;
Tuple stack = new Tuple(((ReadContext)context).getStack().toArray());
if(stack.getEntities().length>0)
{
StackElement se = (StackElement)stack.get(stack.getEntities().length-1);
pos = " (line "+se.getLocation().getLineNumber()+", column "+se.getLocation().getColumnNumber()+")";
}
else
{
pos = " (line 0, column 0)";
}
report.put(stack, msg+pos);
report.size();
}
});
}
//-------- methods --------
/**
* Read properties from xml.
* @param info The resource info.
* @param classloader The classloader.
*/
public MApplicationType read(ResourceInfo rinfo, ClassLoader classloader) throws Exception
{
MultiCollection report = new MultiCollection(new IndexMap().getAsMap(), LinkedHashSet.class);
MApplicationType ret = (MApplicationType)reader.read(rinfo.getInputStream(), classloader, report);
ret.setFilename(rinfo.getFilename());
ret.setLastModified(rinfo.getLastModified());
ret.setClassloader(classloader);
ret.initModelInfo(report);
// Exclude IApplicationExternalAccess
Map props = ret.getModelInfo().getProperties();
if(props==null)
{
props = new HashMap();
ret.getModelInfo().setProperties(props);
}
addMethodInfos(props, "remote_excluded", new String[]{"getSpace"});
rinfo.getInputStream().close();
return ret;
}
/**
* Add method info.
*/
public static void addMethodInfos(Map props, String type, String[] names)
{
Object ex = props.get(type);
if(ex!=null)
{
List newex = new ArrayList();
for(Iterator it=SReflect.getIterator(ex); it.hasNext(); )
{
newex.add(it.next());
}
for(int i=0; i<names.length; i++)
{
newex.add(names[i]);
}
}
else
{
props.put(type, names);
}
}
/**
* Get the XML mapping.
*/
public static Set getXMLMapping(Set[] mappings)
{
Set types = new HashSet();
// Convert expression directly into value.
IStringObjectConverter exconv = new IStringObjectConverter()
{
public Object convertString(String val, IContext context)
{
Object ret = null;
try
{
ret = SJavaParser.evaluateExpression((String)val, ((MApplicationType)context.getRootObject()).getAllImports(), null, context.getClassLoader());
}
catch(RuntimeException e)
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, e.toString());
}
return ret;
}
};
// Convert expression into parsed expression object.
IStringObjectConverter pexconv = new IStringObjectConverter()
{
public Object convertString(String val, IContext context)
{
Object ret = null;
try
{
ret = SJavaParser.parseExpression((String)val, ((MApplicationType)context.getRootObject()).getAllImports(), context.getClassLoader());
}
catch(RuntimeException e)
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, e.toString());
}
return ret;
}
};
String uri = "http://jadex.sourceforge.net/jadex-application";
// TypeInfo satype = new TypeInfo(null, new ObjectInfo(MStartable.class),
// new MappingInfo(null, new AttributeInfo[]{
// new AttributeInfo(new AccessInfo("autoshutdown", "autoShutdown")),
// }, null));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "applicationtype")), new ObjectInfo(MApplicationType.class),
new MappingInfo(null, "description", null,
new AttributeInfo[]{
new AttributeInfo(new AccessInfo("autoshutdown", "autoShutdown")),
new AttributeInfo(new AccessInfo(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"), null, AccessInfo.IGNORE_READWRITE))
},
new SubobjectInfo[]{
new SubobjectInfo(new XMLInfo(new QName[]{new QName(uri, "arguments"), new QName(uri, "argument")}), new AccessInfo(new QName(uri, "argument"), "argument")),
new SubobjectInfo(new XMLInfo(new QName[]{new QName(uri, "arguments"), new QName(uri, "result")}), new AccessInfo(new QName(uri, "result"), "result")),
new SubobjectInfo(new XMLInfo(new QName[]{new QName(uri, "services"), new QName(uri, "container")}), new AccessInfo(new QName(uri, "container"), "container"))
})));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "spacetype")), new ObjectInfo(MSpaceType.class)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "application")), new ObjectInfo(MApplicationInstance.class, new IPostProcessor()
{
public Object postProcess(IContext context, Object object)
{
MApplicationInstance app = (MApplicationInstance)object;
MApplicationType mapp = (MApplicationType)context.getRootObject();
List margs = app.getArguments();
for(int i=0; i<margs.size(); i++)
{
try
{
MExpressionType overridenarg = (MExpressionType)margs.get(i);
Argument arg = (Argument)mapp.getModelInfo().getArgument(overridenarg.getName());
if(arg==null)
throw new RuntimeException("Overridden argument not declared in application type: "+overridenarg.getName());
Object val = overridenarg.getParsedValue().getValue(null);
arg.setDefaultValue(app.getName(), val);
}
catch(RuntimeException e)
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, e.toString());
}
}
return null;
}
public int getPass()
{
return 0;
}
}),
new MappingInfo(null, new AttributeInfo[]{
new AttributeInfo(new AccessInfo("type", "typeName")),
new AttributeInfo(new AccessInfo("autoshutdown", "autoShutdown")),
})));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "space")), new ObjectInfo(MSpaceInstance.class)));
types.add(new TypeInfo(new XMLInfo(new QName[]{new QName(uri, "applicationtype"), new QName(uri, "arguments"), new QName(uri, "argument")}), new ObjectInfo(Argument.class),
new MappingInfo(null, "description", new AttributeInfo(new AccessInfo((String)null, "defaultValue"), new AttributeConverter(exconv, null)))));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "import")), new ObjectInfo(String.class)));
types.add(new TypeInfo(new XMLInfo(new QName[]{new QName(uri, "application"), new QName(uri, "arguments"), new QName(uri, "argument")}), new ObjectInfo(MExpressionType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className"))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "componenttype")), new ObjectInfo(MComponentType.class),
new MappingInfo(null, new AttributeInfo[]{
new AttributeInfo(new AccessInfo("autoshutdown", "autoShutdown")),
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "component")), new ObjectInfo(MComponentInstance.class),
new MappingInfo(null, new AttributeInfo[]{
new AttributeInfo(new AccessInfo("type", "typeName")),
new AttributeInfo(new AccessInfo("autoshutdown", "autoShutdown")),
new AttributeInfo(new AccessInfo("number"), new AttributeConverter(pexconv, null))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName[]{new QName(uri, "component"), new QName(uri, "arguments"), new QName(uri, "argument")}), new ObjectInfo(MExpressionType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className"))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "providedservice")), new ObjectInfo(MProvidedServiceType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className")),
new AttributeInfo(new AccessInfo("componentname", "componentName")),
new AttributeInfo(new AccessInfo("componenttype", "componentType"))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "requiredservice")), new ObjectInfo(MRequiredServiceType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className"))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "container")), new ObjectInfo(MExpressionType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className"))
}, null)));
types.add(new TypeInfo(new XMLInfo(new QName(uri, "property")), new ObjectInfo(MExpressionType.class, new ExpressionProcessor()),
new MappingInfo(null, null, "value", new AttributeInfo[]{
new AttributeInfo(new AccessInfo("class", "className"))
}, null)));
for(int i=0; mappings!=null && i<mappings.length; i++)
{
types.addAll(mappings[i]);
}
return types;
}
//-------- helper classes --------
/**
* Parse expression text.
*/
public static class ExpressionProcessor implements IPostProcessor
{
// Hack!!! Should be configurable.
protected static IExpressionParser exp_parser = new JavaCCExpressionParser();
/**
* Parse expression text.
*/
public Object postProcess(IContext context, Object object)
{
MApplicationType app = (MApplicationType)context.getRootObject();
MExpressionType exp = (MExpressionType)object;
String classname = exp.getClassName();
if(classname!=null)
{
try
{
Class clazz = SReflect.findClass(classname, app.getAllImports(), context.getClassLoader());
exp.setClazz(clazz);
}
catch(Exception e)
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, e.toString());
}
}
String lang = exp.getLanguage();
String value = exp.getValue();
if(value!=null)
{
if(lang==null || "java".equals(lang))
{
try
{
IParsedExpression pexp = exp_parser.parseExpression(value, app.getAllImports(), null, context.getClassLoader());
exp.setParsedValue(pexp);
}
catch(RuntimeException e)
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, e.toString());
}
}
else
{
Object se = new Tuple(((ReadContext)context).getStack().toArray());
MultiCollection report = (MultiCollection)context.getUserContext();
report.put(se, "Unknown condition language: "+lang);
}
}
return null;
}
/**
* Get the pass number.
* @return The pass number.
*/
public int getPass()
{
return 0;
}
}
}