00001 /* 00002 * Copyright (c) 2010, Moritz Tenorth 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 package edu.tum.cs.ias.knowrob.json_prolog; 00031 00032 import java.text.SimpleDateFormat; 00033 import java.util.ArrayList; 00034 import java.util.Date; 00035 import java.util.Iterator; 00036 import java.util.NoSuchElementException; 00037 00038 import ros.RosException; 00039 import ros.pkg.json_prolog_msgs.srv.PrologFinish; 00040 import ros.pkg.json_prolog_msgs.srv.PrologNextSolution; 00041 import ros.pkg.json_prolog_msgs.srv.PrologQuery; 00042 00048 public class PrologQueryProxy implements Iterable<PrologBindings> { 00049 00050 boolean finished_; 00051 Prolog prolog_; 00052 String query_id_; 00053 ArrayList<PrologBindings> bindings_; 00054 QueryIterator q_it; 00055 00056 00064 public PrologQueryProxy(Prolog prolog, String query_str) { 00065 00066 this.query_id_ = makeQueryID(); 00067 this.prolog_ = prolog; 00068 this.finished_ = false; 00069 this.bindings_ = new ArrayList<PrologBindings>(); 00070 00071 PrologQuery.Request req = new PrologQuery.Request(); 00072 PrologQuery.Response resp = new PrologQuery.Response(); 00073 00074 req.id = query_id_; 00075 req.query = query_str; 00076 00077 00078 try{ 00079 00080 resp=prolog_.prolog_query.call(req); 00081 00082 } catch (RosException e) { 00083 throw(new QueryError("Service call '" + prolog_.prolog_query.getService() + "' failed")); 00084 } 00085 00086 if(resp.ok == false) { 00087 throw(new QueryError("Prolog query failed: " + resp.message)); 00088 } 00089 00090 00091 // Instantiate the first solution 00092 q_it = new QueryIterator(this); 00093 //q_it.requestNextSolution(); 00094 00095 } 00096 00100 public Iterator<PrologBindings> iterator() { 00101 return q_it; 00102 } 00103 00104 00108 public boolean isFinished() { 00109 return finished_; 00110 } 00111 00112 00116 public void finish() { 00117 00118 PrologFinish.Request req = new PrologFinish.Request(); 00119 00120 req.id = query_id_; 00121 try{ 00122 00123 prolog_.prolog_finish.call(req); 00124 00125 } catch (RosException e) { 00126 throw(new QueryError("Service call '" + prolog_.prolog_finish.getService() + "' failed")); 00127 } 00128 finished_ = true; 00129 } 00130 00131 00140 class QueryIterator implements Iterator<PrologBindings> { 00141 00142 Iterator<PrologBindings> data_; 00143 PrologQueryProxy query_; 00144 00145 00146 public QueryIterator(PrologQueryProxy proxy) { 00147 query_ = proxy; 00148 data_=proxy.bindings_.iterator(); // initialize iterator to the first element in the bindings list 00149 } 00150 00151 00156 @Override 00157 public boolean hasNext() { 00158 return requestNextSolution(); 00159 } 00160 00161 00166 @Override 00167 public PrologBindings next() { 00168 00169 if(query_==null) 00170 throw( new NullPointerException()); 00171 00172 // just return the next element if there are still some in bindings_ 00173 if(data_.hasNext()) { 00174 data_ = query_.bindings_.listIterator(query_.bindings_.size()-1); 00175 return data_.next(); 00176 } 00177 00178 // return last element if the query is finished 00179 if(query_.finished_) { 00180 data_ = query_.bindings_.listIterator(query_.bindings_.size()-1); 00181 return data_.next(); 00182 } 00183 00184 else throw( new NoSuchElementException()); 00185 } 00186 00187 00188 00189 @Override 00190 public void remove() { 00191 // do nothing: we do not remove elements from the result set 00192 00193 return; 00194 } 00195 00196 00203 protected boolean requestNextSolution() { 00204 00205 // just return the next element if there are still some in bindings_ 00206 if(data_.hasNext()) { 00207 return true; 00208 } 00209 00210 PrologNextSolution.Request req = new PrologNextSolution.Request(); 00211 PrologNextSolution.Response resp = new PrologNextSolution.Response(); 00212 00213 req.id = query_.query_id_; 00214 00215 try{ 00216 00217 resp=prolog_.next_solution.call(req); 00218 00219 } catch (RosException e) { 00220 throw(new QueryError("Service call '" + prolog_.next_solution.getService() + "' failed")); 00221 } 00222 00223 switch(resp.status) { 00224 00225 case PrologNextSolution.Response.NO_SOLUTION: 00226 finish(); 00227 data_ = query_.bindings_.listIterator(query_.bindings_.size()); 00228 query_.finished_ = true; 00229 return false; 00230 00231 case PrologNextSolution.Response.WRONG_ID: 00232 finish(); 00233 query_.finished_ = true; 00234 throw(new PrologQueryProxy.QueryError("Wrong id. Maybe the server is already processing a query.")); 00235 00236 case PrologNextSolution.Response.QUERY_FAILED: 00237 finish(); 00238 query_.finished_ = true; 00239 throw(new PrologQueryProxy.QueryError("Prolog query failed: " + resp.solution)); 00240 00241 case PrologNextSolution.Response.OK: 00242 query_.bindings_.add(PrologBindings.parseJSONBindings(resp.solution)); 00243 return true; 00244 00245 default: 00246 finish(); 00247 query_.finished_ = true; 00248 throw(new PrologQueryProxy.QueryError("Unknow query status.")); 00249 } 00250 } 00251 }; 00252 00253 00258 protected String makeQueryID() { 00259 SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd_HH-mm-ss-SSS"); 00260 return "JAVA_QUERY_"+sdf.format(new Date()); 00261 } 00262 00263 00268 class QueryError extends RuntimeException { 00269 private static final long serialVersionUID = 1190356215893161319L; 00270 public QueryError(String msg) { 00271 super(msg); 00272 } 00273 }; 00274 00275 00276 }