001 package toolbus.adapter;
002
003 import java.nio.ByteBuffer;
004
005 import jjtraveler.VisitFailure;
006 import toolbus.IOperations;
007 import toolbus.TBTermFactory;
008 import aterm.AFun;
009 import aterm.ATerm;
010 import aterm.ATermAppl;
011 import aterm.ATermBlob;
012 import aterm.ATermList;
013 import aterm.ATermPlaceholder;
014 import aterm.pure.PureFactory;
015 import aterm.pure.binary.BinaryReader;
016 import aterm.pure.binary.BinaryWriter;
017
018 /**
019 * This class facilitates the functions a tool needs to be able to functions.
020 *
021 * @author Arnold Lankamp
022 */
023 public abstract class AbstractTool implements IOperations{
024 protected final static PureFactory termFactory = TBTermFactory.getInstance();
025
026 public final static String DIRECTTOOL = "direct";
027 public final static String REMOTETOOL = "remote";
028
029 private final static int PACKBUFFERSIZE = 65536;
030 private final static AFun SYMBOL_SAF = termFactory.makeAFun("saf-encoded", 1, false);
031
032 /**
033 * This variable MUST be set before tool interaction can take place.
034 */
035 protected ToolBridge toolBridge = null;
036
037 /**
038 * Default constructor.
039 */
040 public AbstractTool(){
041 super();
042 }
043
044 /**
045 * Connects to the ToolBus.
046 *
047 * @param args
048 * The arguments that contain the required information for running a tool (name + id
049 * and additionally the host + port of the ToolBus, depending on how this tool is
050 * connected to the ToolBus).
051 * @throws Exception
052 * Thrown when something goes wrong during the parsing of the arguments or the
053 * establishing of the connection.
054 */
055 public abstract void connect(String[] args) throws Exception;
056
057 /**
058 * Sets the reference ot the tool bridge we're using.
059 *
060 * @param toolBridge
061 * The reference ot the tool bridge we're using.
062 */
063 public void setToolBridge(ToolBridge toolBridge){
064 this.toolBridge = toolBridge;
065 }
066
067 /**
068 * Returns a reference to the tool bridge that we're using.
069 *
070 * @return A reference to the tool bridge that we're using.
071 */
072 public ToolBridge getToolBridge(){
073 return toolBridge;
074 }
075
076 /**
077 * Returns a reference to the aterm factory.
078 *
079 * @return A reference to the aterm factory.
080 */
081 public static PureFactory getFactory(){
082 return termFactory;
083 }
084
085 /**
086 * Posts an event to the ToolBus.
087 *
088 * @param aTerm
089 * The term that contains the data about the event.
090 */
091 public void sendEvent(ATerm aTerm){
092 toolBridge.postEvent(aTerm);
093 }
094
095 /**
096 * Posts a request to the ToolBus.
097 *
098 * @param aTerm
099 * The term that contains the data about the request.
100 * @return The response.
101 */
102 public ATermAppl sendRequest(ATerm aTerm){
103 return toolBridge.postRequest(aTerm);
104 }
105
106 /**
107 * Sends a disconnect request to the ToolBus.
108 *
109 * @param aTerm
110 * The term that contains information about the event.
111 */
112 public void disconnect(ATerm aTerm){
113 toolBridge.send(DISCONNECT, aTerm);
114 }
115
116 /**
117 * Terminated this Tool.
118 */
119 public void terminate(){
120 toolBridge.terminate();
121 }
122
123 /**
124 * Receives an acknowledgement message.
125 *
126 * @param aTerm
127 * The term containing information about the acknowledgement.
128 */
129 public abstract void receiveAckEvent(ATerm aTerm);
130
131 /**
132 * Receives a termination message.
133 *
134 * @param aTerm
135 * The term containing information about the termination.
136 */
137 public abstract void receiveTerminate(ATerm aTerm);
138
139 /**
140 * Packs the given term.
141 *
142 * @param termData
143 * The term that needs to be packed.
144 * @return
145 * The packed version of the given term.
146 */
147 public static ATerm pack(ATerm termData){
148 ByteBuffer packBuffer = ByteBuffer.allocate(PACKBUFFERSIZE);
149 ATermList chunkList = termFactory.getEmpty();
150 BinaryWriter binaryWriter = new BinaryWriter(termData);
151 do{
152 packBuffer.clear();
153 try{
154 binaryWriter.serialize(packBuffer);
155 }catch(VisitFailure vf){/*Intentionally ignore this useless exception.*/}
156
157 int size = packBuffer.limit();
158 byte[] data = new byte[size];
159 packBuffer.get(data);
160
161 ATermBlob chunk = termFactory.makeBlob(data);
162 chunkList = chunkList.insert(chunk);
163 }while(!binaryWriter.isFinished());
164
165 return termFactory.makeAppl(SYMBOL_SAF, chunkList);
166 }
167
168 /**
169 * Unpacks the given term.
170 *
171 * @param packedTerm
172 * The term that needs to be unpacked.
173 * @return
174 * The unpacked version of the given term.
175 */
176 public static ATerm unpack(ATerm packedTerm){
177 ATerm result;
178
179 ATermList annos = packedTerm.getAnnotations();
180 switch(packedTerm.getType()){
181 case ATerm.INT:
182 case ATerm.REAL:
183 case ATerm.BLOB:
184 result = packedTerm;
185 break;
186
187 case ATerm.PLACEHOLDER:
188 ATerm type = ((ATermPlaceholder) packedTerm).getPlaceholder();
189 ATerm unpacked_type = unpack(type);
190 if(unpacked_type.equals(type)){
191 result = packedTerm;
192 }else{
193 result = termFactory.makePlaceholder(unpacked_type);
194 }
195 break;
196
197 case ATerm.APPL:
198 ATermAppl appl = (ATermAppl)packedTerm;
199 AFun fun = appl.getAFun();
200 if(fun == SYMBOL_SAF){
201 ATermList chunkList = (ATermList) appl.getArgument(0);
202 int nrOfChunks = chunkList.getLength();
203 BinaryReader binaryReader = new BinaryReader(termFactory);
204 do{
205 ATermBlob chunk = (ATermBlob) chunkList.elementAt(--nrOfChunks);
206 byte[] data = chunk.getBlobData();
207 ByteBuffer unpackBuffer = ByteBuffer.wrap(data);
208
209 binaryReader.deserialize(unpackBuffer);
210 }while(nrOfChunks > 0);
211
212 if(!binaryReader.isDone()) throw new RuntimeException("Unpacked term was incomplete.\n");
213
214 result = binaryReader.getRoot();
215 }else{
216 ATermList unpacked_args = termFactory.getEmpty();
217
218 for(int i = fun.getArity() - 1; i >= 0; i--) {
219 unpacked_args = unpacked_args.insert(unpack(appl.getArgument(i)));
220 }
221
222 result = termFactory.makeApplList(fun, unpacked_args);
223 }
224 break;
225
226 case ATerm.LIST:
227 ATermList list = (ATermList) packedTerm;
228 ATermList unpacked_list = termFactory.getEmpty();
229
230 while(!list.isEmpty()){
231 unpacked_list = unpacked_list.insert(unpack(list.getFirst()));
232 list = list.getNext();
233 }
234
235 result = unpacked_list.reverse();
236 break;
237
238 default:
239 throw new RuntimeException("Unkown term type: "+packedTerm.getType());
240 }
241
242 if(annos != null){
243 annos = (ATermList) unpack(annos);
244 result = result.setAnnotations(annos);
245 }
246
247 return result;
248 }
249 }