926 lines
29 KiB
Java
926 lines
29 KiB
Java
|
|
//This file is part of SECONDO.
|
||
|
|
|
||
|
|
//Copyright (C) 2021, University in Hagen, Department of Computer Science,
|
||
|
|
//Database Systems for New Applications.
|
||
|
|
|
||
|
|
//SECONDO is free software; you can redistribute it and/or modify
|
||
|
|
//it under the terms of the GNU General Public License as published by
|
||
|
|
//the Free Software Foundation; either version 2 of the License, or
|
||
|
|
//(at your option) any later version.
|
||
|
|
|
||
|
|
//SECONDO is distributed in the hope that it will be useful,
|
||
|
|
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
//GNU General Public License for more details.
|
||
|
|
|
||
|
|
//You should have received a copy of the GNU General Public License
|
||
|
|
//along with SECONDO; if not, write to the Free Software
|
||
|
|
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
|
||
|
|
import java.io.*;
|
||
|
|
import java.net.*;
|
||
|
|
import java.util.*;
|
||
|
|
|
||
|
|
|
||
|
|
import org.jpl7.*;
|
||
|
|
import java.nio.charset.Charset;
|
||
|
|
import java.util.SortedMap;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
public class OptimizerServer extends Thread{
|
||
|
|
|
||
|
|
static {
|
||
|
|
System.loadLibrary( "jpl" );
|
||
|
|
System.loadLibrary( "regSecondo" );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public static native int registerSecondo();
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/** shows a prompt at the console
|
||
|
|
*/
|
||
|
|
private static void showPrompt(){
|
||
|
|
cout.print("\n opt-server > ");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/** init prolog
|
||
|
|
* register the secondo predicate
|
||
|
|
* loads the optimizer prolog code
|
||
|
|
*/
|
||
|
|
private boolean initialize(){
|
||
|
|
// later here is to invoke the init function which
|
||
|
|
// registers the Secondo(command,Result) predicate to prolog
|
||
|
|
if(registerSecondo()!=0){
|
||
|
|
System.err.println("error in registering the secondo predicate ");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
//cout.println("registerSecondo successful");
|
||
|
|
try{
|
||
|
|
|
||
|
|
String[] plargs = {"--stack-limit=256M"};
|
||
|
|
boolean ok = JPL.init(plargs);
|
||
|
|
|
||
|
|
// VTA - 18.09.2006
|
||
|
|
// I added this piece of code in order to run with newer versions
|
||
|
|
// of prolog. Without this code, the libraries (e.g. lists.pl) are
|
||
|
|
// not automatically loaded. It seems that something in our code
|
||
|
|
// (auxiliary.pl and calloptimizer.pl) prevents them to be
|
||
|
|
// automatically loaded. In order to solve this problem I added
|
||
|
|
// a call to 'member(x, [x]).' so that the libraries are loaded
|
||
|
|
// before running our scripts.
|
||
|
|
Term[] args = new Term[2];
|
||
|
|
args[0] = new Atom("x");
|
||
|
|
args[1] = org.jpl7.Util.termArrayToList( new Term[] { new Atom("x") } );
|
||
|
|
Query q = new Query("member",args);
|
||
|
|
if(!q.hasSolution()){
|
||
|
|
cout.println("error in the member call'");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
args = new Term[1];
|
||
|
|
args[0] = new Atom("auxiliary");
|
||
|
|
q = new Query("consult",args);
|
||
|
|
if(!q.hasSolution()){
|
||
|
|
cout.println("error in loading 'auxiliary.pl'");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
args = new Term[1];
|
||
|
|
args[0] = new Atom("calloptimizer");
|
||
|
|
q = new Query("consult",args);
|
||
|
|
if(!q.hasSolution()){
|
||
|
|
cout.println("error in loading 'calloptimizer.pl'");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
} catch(Exception e){
|
||
|
|
cout.println("Exception in initialization "+e);
|
||
|
|
e.printStackTrace();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
public static boolean halt(){
|
||
|
|
try{
|
||
|
|
Query q = new Query("halt");
|
||
|
|
boolean res = command(q,null);
|
||
|
|
return res;
|
||
|
|
} catch(Exception e){
|
||
|
|
System.err.println(" error in shutting down the prolog engine");
|
||
|
|
e.printStackTrace();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** invokes a prolog predicate
|
||
|
|
* all terms in variables must be contained in arguments
|
||
|
|
* variables and results can be null if no result is desired
|
||
|
|
*/
|
||
|
|
synchronized private static boolean command(Query pl_query, Vector results){
|
||
|
|
if(pl_query==null)
|
||
|
|
return false;
|
||
|
|
try{
|
||
|
|
if(trace){
|
||
|
|
cout.println("execute query: "+pl_query);
|
||
|
|
}
|
||
|
|
String ret ="";
|
||
|
|
int number =0; // the number of solutions
|
||
|
|
if(results!=null)
|
||
|
|
results.clear();
|
||
|
|
while(pl_query.hasMoreSolutions()){
|
||
|
|
number++;
|
||
|
|
Map<String, Term> solution = pl_query.nextSolution();
|
||
|
|
if(results!=null){
|
||
|
|
ret = "";
|
||
|
|
if(solution.size()<=0){
|
||
|
|
results.add("yes");
|
||
|
|
} else{
|
||
|
|
Set<String> vars = solution.keySet();
|
||
|
|
Iterator<String> it = vars.iterator();
|
||
|
|
int varnum =0;
|
||
|
|
while(it.hasNext()){
|
||
|
|
String k = it.next();
|
||
|
|
if (varnum>0) ret += " $$$ ";
|
||
|
|
ret += ( k + " = " + solution.get(k));
|
||
|
|
varnum++;
|
||
|
|
}
|
||
|
|
results.add(ret);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(number == 0){
|
||
|
|
if(trace)
|
||
|
|
cout.println("no solution found for' "+pl_query.goal() +"/"+pl_query.goal().arity());
|
||
|
|
return false;
|
||
|
|
} else{
|
||
|
|
// check if the used database is changed
|
||
|
|
Query dbQuery = new Query("databaseName(X)");
|
||
|
|
if(dbQuery.hasMoreSolutions()){
|
||
|
|
Map<String, Term> sol = dbQuery.nextSolution();
|
||
|
|
String v = sol.keySet().iterator().next();
|
||
|
|
String name = ""+sol.get(v);
|
||
|
|
if(!name.equals(openedDatabase)){
|
||
|
|
if(trace){
|
||
|
|
cout.println("use database "+ name);
|
||
|
|
}
|
||
|
|
openedDatabase=name;
|
||
|
|
}
|
||
|
|
|
||
|
|
} else{ // no database open
|
||
|
|
openedDatabase = "";
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} catch(Exception e){
|
||
|
|
if(trace){
|
||
|
|
cout.println("exception in calling the "+pl_query.goal()+"-predicate"+e);
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/** analyzed the given string and extract the command and the argumentlist
|
||
|
|
* <br> then the given command is executed
|
||
|
|
* all Solutions are stored into the Vector Solution
|
||
|
|
*/
|
||
|
|
private synchronized static boolean execute(String command,Vector Solution){
|
||
|
|
if(Solution!=null)
|
||
|
|
Solution.clear();
|
||
|
|
|
||
|
|
// clients should not have the possibility
|
||
|
|
// to shut down the Optimizer-Server
|
||
|
|
command = command.trim();
|
||
|
|
if(command.startsWith("halt ") || command.equals("halt"))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
Vector TMPVars = new Vector();
|
||
|
|
if(trace){
|
||
|
|
cout.println("analyse command: "+command);
|
||
|
|
}
|
||
|
|
command = encode(command);
|
||
|
|
try{
|
||
|
|
Query pl_query = new Query(command);
|
||
|
|
if(pl_query==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("error in parsing command: "+command);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
boolean res = command(pl_query,Solution);
|
||
|
|
|
||
|
|
if(res & trace & Solution!=null){ // successful
|
||
|
|
if(Solution.size()==0)
|
||
|
|
cout.println("Yes");
|
||
|
|
else
|
||
|
|
for(int i=0;i<Solution.size();i++){
|
||
|
|
cout.println("*** Solution "+(i+1)+" ****");
|
||
|
|
cout.println(Solution.get(i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return res;
|
||
|
|
} catch(Exception e){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Exception occured " + e);
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/** return the optimized query
|
||
|
|
* if no optimization is found, query is returned
|
||
|
|
* otherwise the result will be the best query plan
|
||
|
|
*/
|
||
|
|
private synchronized String optimize(String query){
|
||
|
|
//cout.println("optimize called with argument \""+query+"\"");
|
||
|
|
try{
|
||
|
|
if(trace){
|
||
|
|
cout.println("\n optimization-input : "+query+"\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
// switch off check for number of linebreaks
|
||
|
|
Query lb_query = new Query("style_check(-atom)");
|
||
|
|
while(lb_query.hasMoreSolutions()){
|
||
|
|
lb_query.nextSolution();
|
||
|
|
}
|
||
|
|
if(trace){
|
||
|
|
cout.println("style check switched off successfully");
|
||
|
|
}
|
||
|
|
|
||
|
|
String query2 = encode(query);
|
||
|
|
|
||
|
|
if(trace) {
|
||
|
|
System.out.println("encoded Query: " + query2);
|
||
|
|
if(query.equals(query2)){
|
||
|
|
cout.println("original query and encoded query are equal");
|
||
|
|
} else {
|
||
|
|
cout.println("encoded query and original one differ");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Query pl_query=null;
|
||
|
|
try{
|
||
|
|
query2 = query2.replaceAll("'","\\\\'");
|
||
|
|
pl_query = new Query("sqlToPlan('"+query2+"', X )");
|
||
|
|
} catch(Exception e){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Could not translate query");
|
||
|
|
cout.println(e);
|
||
|
|
}
|
||
|
|
return "";
|
||
|
|
}
|
||
|
|
|
||
|
|
if(trace){
|
||
|
|
System.out.println("text could be translated into a query");
|
||
|
|
}
|
||
|
|
|
||
|
|
String ret1 = "";
|
||
|
|
String allret = "";
|
||
|
|
int number =0;
|
||
|
|
|
||
|
|
while(pl_query.hasMoreSolutions()){
|
||
|
|
number++;
|
||
|
|
if(number > 1){
|
||
|
|
allret += "\n";
|
||
|
|
}
|
||
|
|
Map<String,Term> solution = pl_query.nextSolution();
|
||
|
|
if(solution.size()!=1){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Error: optimization returns more than a single binding");
|
||
|
|
}
|
||
|
|
return query;
|
||
|
|
}
|
||
|
|
Iterator<String> it = solution.keySet().iterator();
|
||
|
|
while(it.hasNext()){
|
||
|
|
allret += "" + solution.get(it.next());
|
||
|
|
}
|
||
|
|
if(number==1){
|
||
|
|
ret1 = allret;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(number>1){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Error: optimization returns more than one solution");
|
||
|
|
cout.println("Solutions are \n" + allret);
|
||
|
|
}
|
||
|
|
ret1 = ret1.trim();
|
||
|
|
if(ret1.startsWith("'") && ret1.endsWith("'")){
|
||
|
|
if(ret1.length()==2){
|
||
|
|
ret1 = "";
|
||
|
|
} else{
|
||
|
|
ret1 = ret1.substring(1,ret1.length()-1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return decode(ret1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(number==0){
|
||
|
|
if(trace)
|
||
|
|
cout.println("optimization failed - no solution found");
|
||
|
|
return query;
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
if(trace)
|
||
|
|
cout.println("\n optimization-result : "+allret+"\n");
|
||
|
|
|
||
|
|
// free ret from enclosing ''
|
||
|
|
allret = allret.trim();
|
||
|
|
if(allret.startsWith("'") && allret.endsWith("'")){
|
||
|
|
if(allret.length()==2){
|
||
|
|
allret = "";
|
||
|
|
} else{
|
||
|
|
allret = allret.substring(1,allret.length()-1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return decode(allret);
|
||
|
|
}
|
||
|
|
} catch(Exception e){
|
||
|
|
if(trace) {
|
||
|
|
cout.println("\n Exception :"+e);
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
showPrompt();
|
||
|
|
return query;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
/** if Name is not the database currenty used,
|
||
|
|
* the opened database is closed and the database
|
||
|
|
* Name is opened
|
||
|
|
*/
|
||
|
|
private synchronized boolean useDatabase(String Name){
|
||
|
|
if(openedDatabase.equals(Name)){
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
Term[] arg = new Term[1];
|
||
|
|
if(!openedDatabase.equals("")){
|
||
|
|
if(trace)
|
||
|
|
cout.println("close the opened database");
|
||
|
|
Query Q = new Query("secondo('close database')");
|
||
|
|
command(Q,null);
|
||
|
|
}
|
||
|
|
|
||
|
|
Query Q_open = new Query("secondo('open database "+Name+"')");
|
||
|
|
showPrompt();
|
||
|
|
boolean res = command(Q_open,null);
|
||
|
|
openedDatabase = res?Name:"";
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/** a class for communicate with a client */
|
||
|
|
private class Server extends Thread{
|
||
|
|
|
||
|
|
/** creates a new Server from given socket */
|
||
|
|
public Server(Socket S){
|
||
|
|
this.S = S;
|
||
|
|
//cout.println("requesting from client");
|
||
|
|
try{
|
||
|
|
// communication with client, always use UTF-8 encoding
|
||
|
|
try{
|
||
|
|
in = new BufferedReader(new InputStreamReader(S.getInputStream(),"UTF-8"));
|
||
|
|
} catch(UnsupportedEncodingException e){
|
||
|
|
System.err.println("Encoding UTF-8 not supported");
|
||
|
|
in = new BufferedReader(new InputStreamReader(S.getInputStream()));
|
||
|
|
}
|
||
|
|
try{
|
||
|
|
out = new BufferedWriter(new OutputStreamWriter(S.getOutputStream(),"UTF-8"));
|
||
|
|
} catch(UnsupportedEncodingException e){
|
||
|
|
System.err.println("Encoding UTF-8 not supported");
|
||
|
|
out = new BufferedWriter(new OutputStreamWriter(S.getOutputStream()));
|
||
|
|
}
|
||
|
|
String First = in.readLine();
|
||
|
|
//cout.println("receive :"+First);
|
||
|
|
if(First==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection broken");
|
||
|
|
showPrompt();
|
||
|
|
running=false;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if(First.equals("<who>")){
|
||
|
|
out.write("<optimizer>\n",0,12);
|
||
|
|
out.flush();
|
||
|
|
running = true;
|
||
|
|
}else{
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol-error , close connection (expect: <who>, received :"+First);
|
||
|
|
showPrompt();
|
||
|
|
running = false;
|
||
|
|
}
|
||
|
|
}catch(Exception e){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Exception occured "+e);
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
showPrompt();
|
||
|
|
running = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** disconnect this server from a client */
|
||
|
|
private void disconnect(){
|
||
|
|
// close Connection if possible
|
||
|
|
try{
|
||
|
|
if(S!=null)
|
||
|
|
S.close();
|
||
|
|
}catch(Exception e){
|
||
|
|
if(trace){
|
||
|
|
cout.println("Exception in closing connection "+e);
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
OptimizerServer.Clients--;
|
||
|
|
if(trace){
|
||
|
|
cout.println("\nbye client");
|
||
|
|
cout.println("number of clients is :"+ OptimizerServer.Clients);
|
||
|
|
}
|
||
|
|
if((OptimizerServer.Clients==0) && OptimizerServer.quitAfterDisconnect){
|
||
|
|
// OptimizerServer.halt(); // not allowed from this tread
|
||
|
|
System.exit(0);
|
||
|
|
}
|
||
|
|
showPrompt();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/** processes requests from clients until the client
|
||
|
|
* finish the connection or an error occurs
|
||
|
|
*/
|
||
|
|
public void run(){
|
||
|
|
if(!running){
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
boolean execFlag=false; // flags for control execute or optimize request
|
||
|
|
try{
|
||
|
|
String input = in.readLine();
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
while(!input.equals("<end connection>")){
|
||
|
|
|
||
|
|
if(!input.equals("<optimize>") && !input.equals("<execute>") ){ // protocol_error
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol error( expect: <optimize> or <execute> , found:"+input);
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
execFlag = input.equals("<execute>");
|
||
|
|
// read the database name
|
||
|
|
input = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if(!input.equals("<database>")){ // protocol_error
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol error( expect: <database> , found:"+input);
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
String Database = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+Database+" from client");
|
||
|
|
|
||
|
|
if(Database==null){
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}else {
|
||
|
|
Database = Database.trim();
|
||
|
|
}
|
||
|
|
input = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}else{
|
||
|
|
input = input.trim();
|
||
|
|
}
|
||
|
|
if(!input.equals("</database>")){ // protocol error
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol error( expect: </database> , found:"+input);
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
input = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}else{
|
||
|
|
input = input.trim();
|
||
|
|
}
|
||
|
|
if(!input.equals("<query>")){ // protocol error
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol error( expect: <query> , found:"+input);
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
StringBuffer res = new StringBuffer();
|
||
|
|
// build the query from the next lines
|
||
|
|
input = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
//cout.println("receive"+input);
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
while(!input.equals("</query>")){
|
||
|
|
res.append(input + "\n");
|
||
|
|
input = in.readLine();
|
||
|
|
//cout.println("receive"+input);
|
||
|
|
if(input==null){
|
||
|
|
if(trace)
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
input = in.readLine();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
if(input==null){
|
||
|
|
cout.println("connection is broken");
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(! (input.equals("</optimize>") & !execFlag) & !(input.equals("</execute>") & execFlag)){ //protocol-error
|
||
|
|
if(trace)
|
||
|
|
cout.println("protocol error( expect: </optimize> or </execute>, found:"+input);
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
String Request = res.toString().trim();
|
||
|
|
|
||
|
|
//cout.println("Request is " + Request );
|
||
|
|
|
||
|
|
Vector V = new Vector();
|
||
|
|
synchronized(SyncObj){
|
||
|
|
useDatabase(Database);
|
||
|
|
if(!execFlag){
|
||
|
|
String opt = OptimizerServer.this.optimize(Request);
|
||
|
|
if(!opt.equals(Request))
|
||
|
|
V.add(opt);
|
||
|
|
}else{
|
||
|
|
execute(Request,V);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
showPrompt();
|
||
|
|
|
||
|
|
out.write("<answer>\n",0,9);
|
||
|
|
String answer;
|
||
|
|
for(int i=0;i<V.size();i++){
|
||
|
|
answer = (String) V.get(i);
|
||
|
|
out.write(answer+"\n",0,answer.length()+1);
|
||
|
|
}
|
||
|
|
out.write("</answer>\n",0,10);
|
||
|
|
out.flush();
|
||
|
|
input = in.readLine().trim();
|
||
|
|
|
||
|
|
//cout.println("receive "+input+" from client");
|
||
|
|
|
||
|
|
if (input==null){
|
||
|
|
cout.println("connection broken");
|
||
|
|
showPrompt();
|
||
|
|
disconnect();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
} // while
|
||
|
|
cout.println("connection ended normally");
|
||
|
|
showPrompt();
|
||
|
|
}catch(IOException e){
|
||
|
|
cout.println("error in socket-communication" + e);
|
||
|
|
|
||
|
|
disconnect();
|
||
|
|
showPrompt();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
disconnect();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private BufferedReader in;
|
||
|
|
private BufferedWriter out;
|
||
|
|
private boolean running;
|
||
|
|
private Socket S;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/** creates the server process */
|
||
|
|
private boolean createServer(){
|
||
|
|
SS=null;
|
||
|
|
try{
|
||
|
|
SS = new ServerSocket(PortNr);
|
||
|
|
} catch(java.net.BindException be){
|
||
|
|
cout.println("BindException occured");
|
||
|
|
cout.println("check if the port "+PortNr+" is already in use");
|
||
|
|
return false;
|
||
|
|
} catch(Exception e){
|
||
|
|
cout.println("unable to create a ServerSocket" + e);
|
||
|
|
e.printStackTrace();
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** waits for request from clients
|
||
|
|
* for each new client a new socket communicationis created
|
||
|
|
*/
|
||
|
|
public void run(){
|
||
|
|
cout.println("\nwaiting for requests");
|
||
|
|
showPrompt();
|
||
|
|
while(running){
|
||
|
|
try{
|
||
|
|
Socket S = SS.accept();
|
||
|
|
Clients++;
|
||
|
|
if(trace){
|
||
|
|
cout.println("\na new client is connected");
|
||
|
|
cout.println("number of clients :"+Clients);
|
||
|
|
showPrompt();
|
||
|
|
}
|
||
|
|
(new Server(S)).start();
|
||
|
|
} catch(Exception e){
|
||
|
|
cout.println("error in communication" + e);
|
||
|
|
showPrompt();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private static void showUsage(){
|
||
|
|
cout.println("java -classpath .:<jplclasses> OptimizerServer PORT [options] ");
|
||
|
|
cout.println("<jplclasses> : jar file containing the JPL (prolog) API");
|
||
|
|
cout.println("PORT : port for the server");
|
||
|
|
cout.println("[Options can be :");
|
||
|
|
cout.println(" -autoquit : exits the server if the last client disconnects");
|
||
|
|
cout.println(" -trace_methods : enables tracing of method calls (for debugging)");
|
||
|
|
cout.println(" -trace_instructions : enables tracing of instructions (for debugging)");
|
||
|
|
cout.println(" -trace_commands : enables tracing of input/output");
|
||
|
|
cout.println(" -encoding enc : switch the output encoding");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/** creates a new server object
|
||
|
|
* process inputs from the user
|
||
|
|
* available commands are
|
||
|
|
* client : prints out the number of connected clients
|
||
|
|
* quit : shuts down the server
|
||
|
|
*/
|
||
|
|
public static void main(String[] args){
|
||
|
|
cout = System.out;
|
||
|
|
if(args.length<1){
|
||
|
|
showUsage();
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
// process options
|
||
|
|
Runtime rt = Runtime.getRuntime();
|
||
|
|
int pos = 1;
|
||
|
|
String console_enc = "utf-8"; // standard
|
||
|
|
while(pos<args.length){
|
||
|
|
if(args[pos].equals("-autoquit")){
|
||
|
|
quitAfterDisconnect=true;
|
||
|
|
cout.println("auto quit enabled");
|
||
|
|
pos++;
|
||
|
|
} else if(args[pos].equals("-encoding")){
|
||
|
|
if(pos+1>=args.length){
|
||
|
|
showUsage();
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
console_enc = args[pos+1];
|
||
|
|
pos++;
|
||
|
|
pos++;
|
||
|
|
} else if(args[pos].equals("-trace_commands")){
|
||
|
|
trace=true;
|
||
|
|
pos++;
|
||
|
|
} else {
|
||
|
|
cout.println("unknown option " + args[pos]);
|
||
|
|
showUsage();
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!console_enc.equals("utf-8")){
|
||
|
|
SortedMap available = Charset.availableCharsets();
|
||
|
|
if(!available.containsKey(console_enc)){
|
||
|
|
cout.println("encoding " + console_enc + " unknown");
|
||
|
|
cout.println(" Available encodinga are : ");
|
||
|
|
cout.println(available.keySet());
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
cout = new PrintStream(System.out, true, console_enc);
|
||
|
|
} catch(Exception e){
|
||
|
|
cout = System.out;
|
||
|
|
cout.println("Problem in changing output encoding, use utf-8");
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
cout.println("\n\n");
|
||
|
|
printLicence(cout);
|
||
|
|
cout.println("\n");
|
||
|
|
String arg = args[0];
|
||
|
|
OptimizerServer OS = new OptimizerServer();
|
||
|
|
try{
|
||
|
|
int P = java.lang.Integer.parseInt(arg);
|
||
|
|
if(P<=0){
|
||
|
|
System.err.println("the Portnumber must be greater then zero");
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
OS.PortNr=P;
|
||
|
|
}catch(Exception e){
|
||
|
|
System.err.println("the Portnumber must be an integer");
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
try{
|
||
|
|
Class.forName("org.jpl7.fli.Prolog"); // ensure to load the jpl library
|
||
|
|
} catch(Exception e){
|
||
|
|
System.err.println("loading prolog class failed");
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(! OS.initialize()){
|
||
|
|
cout.println("initialization failed");
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
if(!OS.createServer()){
|
||
|
|
cout.println("creating Server failed");
|
||
|
|
System.exit(1);
|
||
|
|
}
|
||
|
|
OS.running = true;
|
||
|
|
OS.start();
|
||
|
|
try{
|
||
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||
|
|
cout.print("optserver >");
|
||
|
|
String command = "";
|
||
|
|
Vector ResVector = new Vector();
|
||
|
|
while(!command.equals("quit")){
|
||
|
|
command = in.readLine();
|
||
|
|
if(command==null){
|
||
|
|
command = "";
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
command = command.trim();
|
||
|
|
if(command.equals("clients")){
|
||
|
|
cout.println("Number of Clients: "+ Clients);
|
||
|
|
}else if(command.equals("quit")){
|
||
|
|
if( Clients > 0){
|
||
|
|
cout.print("clients exists ! shutdown anyway (y/n) >");
|
||
|
|
String answer = in.readLine().trim().toLowerCase();
|
||
|
|
if(!answer.startsWith("y"))
|
||
|
|
command="";
|
||
|
|
}
|
||
|
|
} else if(command.equals("trace-on")){
|
||
|
|
trace=true;
|
||
|
|
cout.println("tracing is activated");
|
||
|
|
} else if(command.equals("trace-off")){
|
||
|
|
trace=false;
|
||
|
|
cout.println("tracing is deactivated");
|
||
|
|
} else if(command.equals("help") | command.equals("?") ){
|
||
|
|
cout.println("quit : quits the server ");
|
||
|
|
cout.println("clients : prints out the number of connected clients");
|
||
|
|
cout.println("trace-on : prints out messages about command, optimized command, open database");
|
||
|
|
cout.println("trace-off : disable messages");
|
||
|
|
} else if(command.startsWith("exec")){
|
||
|
|
String cmdline = command.substring(4,command.length()).trim();
|
||
|
|
execute(cmdline,ResVector);
|
||
|
|
}else if(!command.equals("")){
|
||
|
|
cout.println("unknow command, try help show a list of valid commands");
|
||
|
|
}
|
||
|
|
if(!command.equals("quit"))
|
||
|
|
showPrompt();
|
||
|
|
|
||
|
|
}
|
||
|
|
OS.running = false;
|
||
|
|
}catch(Exception e){
|
||
|
|
OS.running = false;
|
||
|
|
cout.println("error in reading commands");
|
||
|
|
if(trace)
|
||
|
|
e.printStackTrace();
|
||
|
|
}
|
||
|
|
try{
|
||
|
|
Query q = new Query("halt");
|
||
|
|
command(q,null);
|
||
|
|
} catch(Exception e){
|
||
|
|
System.err.println(" error in shutting down the prolog engine");
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/** Prints out the licence information of this software **/
|
||
|
|
public static void printLicence(PrintStream out){
|
||
|
|
cout.println(" Copyright (C) 2021, University in Hagen, ");
|
||
|
|
cout.println(" Faculty of Mathematics and Computer Science, ");
|
||
|
|
cout.println(" Database Systems for New Applications. \n");
|
||
|
|
|
||
|
|
cout.println(" This is free software; see the source for copying conditions.");
|
||
|
|
cout.println(" There is NO warranty; not even for MERCHANTABILITY or FITNESS ");
|
||
|
|
cout.println(" FOR A PARTICULAR PURPOSE.");
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Converts a string into OS_pl_encoding **/
|
||
|
|
private static String encode(String src){
|
||
|
|
if(OS_pl_encoding==null){
|
||
|
|
return src;
|
||
|
|
}
|
||
|
|
try{
|
||
|
|
byte[] encodedBytes = src.getBytes(OS_pl_encoding);
|
||
|
|
return new String(encodedBytes, "UTF-8");
|
||
|
|
} catch(Exception e){
|
||
|
|
System.err.println("Used encoding not supported\n" + e);
|
||
|
|
return src;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Converts a string from OS_pl_encoding **/
|
||
|
|
private static String decode(String src){
|
||
|
|
if(OS_pl_encoding==null){
|
||
|
|
return src;
|
||
|
|
}
|
||
|
|
try{
|
||
|
|
byte[] encodedBytes = src.getBytes("UTF-8");
|
||
|
|
return new String(encodedBytes, OS_pl_encoding);
|
||
|
|
} catch(Exception e){
|
||
|
|
System.err.println("Used encoding not supported\n" + e);
|
||
|
|
return src;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
private static String OS_pl_encoding = null;
|
||
|
|
|
||
|
|
|
||
|
|
private boolean optimizer_loaded = false;
|
||
|
|
private int PortNr = 1235;
|
||
|
|
private static int Clients = 0;
|
||
|
|
private static boolean quitAfterDisconnect = false;
|
||
|
|
private ServerSocket SS;
|
||
|
|
private boolean running;
|
||
|
|
private static String openedDatabase ="";
|
||
|
|
private static boolean trace = true;
|
||
|
|
private static Object SyncObj = new Object();
|
||
|
|
private static PrintStream cout;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|