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 }