📄 oaamapper.java
字号:
// $CALOLSI$
/*
* #=========================================================================
* # Copyright 2004 SRI International. All rights reserved.
* #
* # The material contained in this file is confidential and proprietary to SRI
* # International and may not be reproduced, published, or disclosed to others
* # without authorization from SRI International.
* #
* # DISCLAIMER OF WARRANTIES
* #
* # SRI International MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
* # SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT
* # LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* # PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SRI International SHALL NOT BE
* # LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* # OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
* #=========================================================================
* Author : evans
* Date: May 10, 2004
* Time: 11:07:01 AM
*/
package com.sri.oaa2.mapper;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import com.sri.oaa2.icl.*;
import com.sri.oaa2.lib.LibOaa;
import com.sri.oaa2.lib.OAAEventListener;
import org.apache.log4j.Logger;
/**
* OAAMapper maps OAA solvable calls to Java function calls, and maps the results back.
* It takes an XML OAAMapper mapping file and a set of Java objects that the solvables are
* executed over. It then can act as an OAAEventListener and respond to OAA solvables directly,
* or it can be passed pieces of ICL to act upon.<p>
* <p/>
* Function calls made through the callFunction() or doOAAEvent() methods are not synchronized, so
* Java objects to which these calls are mapped must be thread-safe.
*/
public class OAAMapper
implements OAAEventListener
{
private Logger logger = Logger.getLogger(super.getClass());
private List solvableObjects = new LinkedList();
private IclMapping iclMapping;
private LibOaa libOaa;
/**
* @param iclMapping
*/
public OAAMapper(IclMapping iclMapping)
{
this.iclMapping = iclMapping;
}
/**
* @param mappingFile
* @throws MappingException
*/
public OAAMapper(InputStream mappingFile)
throws MappingException
{
IclMappingParser iclMappingParser = new IclMappingParser();
iclMapping = iclMappingParser.parse(mappingFile);
}
/**
* @param mappingFile
* @throws MappingException
*/
public OAAMapper(Reader mappingFile)
throws MappingException
{
IclMappingParser iclMappingParser = new IclMappingParser();
iclMapping = iclMappingParser.parse(mappingFile);
}
/**
* Adds an object upon which callFunction() and doOAAEvent function calls are invoked.
*
* @param o
*/
public void addSolvableObject(Object o)
{
solvableObjects.add(o);
}
/**
* Creates a proxy object that implements the specified interfaces, translates calls on those
* interfaces into OAA solvable calls, and translates the results into Java objects. The returned object
* can be cast to any of the specified interfaces, and functions on thos interfaces are callable if the
* functions have a mapping in the XML OAAMapper file and if the specified LibOaa object is connected to
* an OAA facilitator.
*
* @param proxyInterfaces
* @param oaaFacilitator
* @return
*/
public Object createOAAProxy(Class[] proxyInterfaces, LibOaa oaaFacilitator)
{
OAAProxy oaaProxy = new OAAProxy(this, oaaFacilitator);
Object proxy = Proxy.newProxyInstance(super.getClass().getClassLoader(), proxyInterfaces, oaaProxy);
return proxy;
}
/**
* Given the result of callFunction, convert it to an OAA answer and append to list o
* answers. Handles the special case where function returns null as a way of signaling
* failure.
*
* @param origGoal the original OAA goal that this function call is solving
* @param result from callFunction
* @param answers Will append the result to this list. Or, if function returns null
* will do nothing.
*/
private void answerFromResult(IclTerm origGoal, FunctionBinding functionBinding, Object result, IclList answers)
throws Exception
{
// this is a hack because .clone() obliterates IclVar names:
IclTerm answer = IclUtils.fromString(origGoal.toString());
if(functionBinding.getFunctionMapping().isReturnsResult())
{
// As a special feature. If function returns a result, it can return null
// as a way of signaling that it found no solutions. So, don't add any
// solution to the return list.
if(result == null)
{
return;
}
if(logger.isDebugEnabled())
logger.debug("Result from " + functionBinding.getFunctionMapping().getFunctionSignature().getName() +
": " + result);
IclTerm iclResult = javaToIcl(result);
ResultSetter resultSetter = new ResultSetter(iclResult);
resultSetter.traverse(functionBinding.getFunctionMapping().getIcl(), answer);
}
answers.add(answer);
}
/**
* Maps an OAA solvable to a function call, and parses and returns the result.
*/
public boolean doOAAEvent(final IclTerm goal, IclList params, IclList answers)
{
try
{
final FunctionBinding functionBinding = findFunctionBinding(goal);
if(logger.isDebugEnabled())
logger.debug("Matched " + goal + " to function " +
functionBinding.getFunctionMapping().getFunctionSignature());
// Oaa Delay returning results and start new thread to call the function
// and return the delayed results when done.
if(functionBinding.getFunctionMapping().isOwnThread())
{
final String oaaSolvableId = "OaaMap" + Long.toString(System.currentTimeMillis());
boolean res = libOaa.oaaDelaySolution(oaaSolvableId);
if(res)
{
new Thread(new Runnable()
{
public void run()
{
try
{
IclList answers = new IclList();
Object result = callFunction(goal, functionBinding);
answerFromResult(goal, functionBinding, result, answers);
if(!libOaa.oaaReturnDelayedSolutions(oaaSolvableId, answers))
{
logger.error("Could not oaaReturnDelayedSolutions for goal: " + goal);
}
}
catch(Exception e)
{
logger.error("Could not call function for goal:" + goal, e);
}
}
}).start();
}
else
{
logger.error("Could not oaaDelaySolution for goal: " + goal);
return false;
}
}
// Just call the function directly. No threads necessary.
else
{
Object result = callFunction(goal, functionBinding);
answerFromResult(goal, functionBinding, result, answers);
}
return true;
}
catch(Exception e)
{
logger.error("Error invoking solvable " + goal, e);
}
return false;
}
/**
* Calls the function indicated by the solvable.
*
* @param goal
* @return
* @throws MappingException
*/
public Object callFunction(IclTerm goal)
throws MappingException
{
FunctionBinding functionBinding = findFunctionBinding(goal);
if(logger.isDebugEnabled())
logger.debug(
"Matched " + goal + " to function " + functionBinding.getFunctionMapping().getFunctionSignature());
return callFunction(goal, functionBinding);
}
public IclTerm createSolvable(Class functionClass, Method functionSignature, Object[] parameters)
throws MappingException
{
try
{
FunctionMapping functionMapping = null;
for(int i = 0; i < iclMapping.getFunctionMappings().length && functionMapping == null; i++)
{
FunctionMapping currentMapping = iclMapping.getFunctionMappings()[i];
if(currentMapping.getFunctionClass().isAssignableFrom(functionClass) &&
currentMapping.getFunctionSignature().equals(functionSignature) &&
currentMapping.getParameters().length == parameters.length)
functionMapping = currentMapping;
}
if(functionMapping == null)
throw new MappingException("No function mapping found for " + functionClass + " " + functionSignature);
// TODO: hack b/c of ICL variable problems;
IclTerm solvable = IclUtils.fromString(functionMapping.getFunctionSignature().toString());
// set parameters:
Map parameterMap = new HashMap();
for(int i = 0; i < functionMapping.getParameters().length; i++) parameterMap.put("Arg" + i, parameters[i]);
PropertySetter propertySetter = new PropertySetter(parameterMap);
propertySetter.traverse(solvable);
return solvable;
}
catch(MappingException me)
{
throw me;
}
catch(Exception e)
{
throw new MappingException(
"Error creating solvable for " + functionClass + " " + functionSignature + ": " + e, e);
}
}
/**
* Maps a Java object to ICL as indicated by the mapping file.
*
* @param value
* @return
* @throws MappingException
*/
public IclTerm javaToIcl(Object value)
throws MappingException
{
try
{
if(value == null) throw new MappingException("Null object cannot be mapped");
else if(value instanceof String)
return new IclStr((String)value);
else if(value instanceof Float)
return new IclFloat((Float)value);
else if(value instanceof Double)
return new IclFloat((Double)value);
else if(value instanceof Integer)
return new IclInt(((Integer)value).intValue());
else if(value instanceof Long)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -