package jp.ac.do_johodai.j314.sw.je;

import java.io.*;
import java.net.URL;
import java.util.*;

import org.mindswap.pellet.jena.PelletReasonerFactory;

import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.util.*;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.rulesys.Builtin;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.reasoner.rulesys.BuiltinRegistry;
import com.hp.hpl.jena.reasoner.rulesys.RuleReasoner;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.graph.*;
import com.hp.hpl.jena.reasoner.InfGraph;
import com.hp.hpl.jena.db.DBConnection;

//jena.RuleMapのソースコードが参考になる．
/**
 * Jenaの推論エンジンを簡単に使用できるようにするためのクラスです。
 */
public class JenaEngine implements Runnable {
    InfModel infModel;
    ArrayList<JEMessage> requestQueue;
    Timer timer = new Timer();
    boolean enableOWLDL = false;
    boolean trace = false;
    String reasonerMode = "hybrid";
    DBConnection conn = null;
    Thread t;
    boolean stopRequest = false;

    public void destroy() {
        stopRequest = true;
        synchronized (requestQueue) {
            requestQueue.notifyAll();
        }
        while (t.isAlive()) {
            try{Thread.sleep(100);}catch(Exception e){;}
        }
        timer.cancel();
        try {
            if (conn!=null)
                conn.close();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * JenaEngineのコンストラクタで、非同期メソッドに対応 するためのスレッドも走り出すようになってます。
     */
    public JenaEngine() {
        ArrayList rules = new ArrayList();
        Model model = ModelFactory.createDefaultModel();
        infModel = createInfModel(rules,model);
        requestQueue = new ArrayList<JEMessage>();
        t = new Thread(this);
        t.start();
    }
    /**
     * JenaEngineのコンストラクタで、非同期メソッドに対応
     * するためのスレッドも走り出すようになってます。
     * こちらはRDBでデータの永続化をやってます．
     * 引数の例：
     * driver="com.mysql.jdbc.Driver";
     * url="jdbc:mysql://localhost:3306/jena";
     * user="jena";
     * passwd="jenapw";
     * type="MySQL";
     * modelName="MyModel";
     */
    public JenaEngine(String driver,String url,String user,String passwd,String type,String modelName) throws Exception {
        Class.forName(driver);
        ArrayList rules = new ArrayList();
        conn = new DBConnection(url,user,passwd,type);
        ModelMaker maker = ModelFactory.createModelRDBMaker(conn);
        Model model = maker.createModel(modelName);
        infModel = createInfModel(rules,model);
        requestQueue = new ArrayList<JEMessage>();
        t = new Thread(this);
        t.start();
    }

    InfModel createInfModel(List rules,Model model) {
        InfModel retModel = null;
        if (enableOWLDL) {
            Reasoner pelletReasoner = PelletReasonerFactory.theInstance().create();
            model = ModelFactory.createInfModel(pelletReasoner,model);
        }

        GenericRuleReasoner myReasoner = new GenericRuleReasoner(rules);
        if (reasonerMode.equals("hybrid"))
            myReasoner.setMode(GenericRuleReasoner.HYBRID);
        else if (reasonerMode.equals("forward"))
            myReasoner.setMode(GenericRuleReasoner.FORWARD);
        else if (reasonerMode.equals("forwardRETE"))
            myReasoner.setMode(GenericRuleReasoner.FORWARD_RETE);
        else if (reasonerMode.equals("backward"))
            myReasoner.setMode(GenericRuleReasoner.BACKWARD);
        // myReasoner.setOWLTranslation(true);
        // myReasoner.setTransitiveClosureCaching(true);
        retModel = ModelFactory.createInfModel(myReasoner,model);
        Object g = retModel.getGraph();
        if (g instanceof com.hp.hpl.jena.reasoner.rulesys.FBRuleInfGraph)
            ((com.hp.hpl.jena.reasoner.rulesys.FBRuleInfGraph) g)
                    .setTraceOn(trace);
        return retModel;
    }

    /**
     * 使用するビルトインを指定してやって下さい。デフォルトでは
     * Jenaの提供するビルトインしか使えない状態になっています。
     */
    public void registerBuiltin(Builtin b) {
        BuiltinRegistry.theRegistry.register(b);
    }

    /**
     * RDFの入ったファイルのurlの文字列を受け取って、その中身を このJenaEngineに読み込みます。以前読み込まれていたRDF
     * モデルは破棄されて新しく読み込まれます。ルールの内容は受け継がれます。
     */
    public void loadRDF(String s) {
        synchronized (infModel) {
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            Model model = FileManager.get().loadModel(s);
            InfModel newInfModel = createInfModel(rules,model);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * RDFの入ったファイルのurlの文字列を受け取って、その中身を このJenaEngineに読み込みます。以前読み込まれていたRDF
     * モデルも，ルールの内容も受け継がれます。
     */
    public void appendRDF(String s) {
        synchronized (infModel) {
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            Model model = FileManager.get().loadModel(s);
            model.add(infModel);
            InfModel newInfModel = createInfModel(rules,model);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * RDFモデルの内容を引数のURLで指定されたファイルに保存します。
     */
    public void saveRDFAsN3(String s) {
        synchronized (infModel) {
            try {
                URL url = new URL(s);
                FileOutputStream fos = new FileOutputStream(url.getFile());
                infModel.write(fos,"N3");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Jenaのルールが書かれたファイルのURLを受け取って、そのルールを このJenaEngineに読み込みます。以前読み込まれていた
     * ルールは破棄されて新しく読み込まれます。RDFモデルの内容は引き継がれます。
     */
    public void loadRules(String s) {
        try {
            synchronized (infModel) {
                Model m = infModel.getRawModel();
                List rules = Rule.rulesFromURL(s);
                InfModel newInfModel = createInfModel(rules,m);
                newInfModel.prepare();
                infModel = newInfModel;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * これはRDFモデルを空っぽにするメソッド。セットされたルールは引き継がれます。
     */
    public void clearRDF() {
        synchronized (infModel) {
            Model m = ModelFactory.createDefaultModel();
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            InfModel newInfModel = createInfModel(rules,m);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * これはRDFモデルを推論前の状態に戻すメソッド
     */
    public void resetRDF() {
        synchronized (infModel) {
            infModel.reset();
        }
    }

    /**
     * 標準出力にルール実行時にトレース情報を出力するか どうかを変更します。
     */
    public void setTrace(boolean b) {
        synchronized (infModel) {
            trace = b;
            Model m = infModel.getRawModel();
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            InfModel newInfModel = createInfModel(rules,m);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * Reasonerの推論モデルをセットします．セットできるのは次の4つ．
     * "hybrid"，"forward"，"forwardRETE"，"backward"
     * デフォルトは"hybrid"．
     */
    public void setReasonerMode(String mode) {
        synchronized (infModel) {
            reasonerMode = mode;
            Model m = infModel.getRawModel();
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            InfModel newInfModel = createInfModel(rules,m);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * OWL-DLのReasonerを有効にするかどうかセットする。
     * RDFモデルの内容やルールは引き継がれる。
     */
    public void setEnableOWLDL(boolean b) {
        synchronized (infModel) {
            Model m = infModel.getRawModel();
            List rules = ((RuleReasoner)infModel.getReasoner()).getRules();
            enableOWLDL = b;
            InfModel newInfModel = createInfModel(rules,m);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }
    /**
     * Jenaのルールが書かれた文字列を受け取って、そのルールを このJenaEngineに適用します。以前読み込まれていた
     * ルールは破棄されて新しく適用します。Jenaのルールの中に書かれた「@include ...」は正しく機能しないかもしれません。
     */
    public void setRules(String s) {
        synchronized (infModel) {
            Model m = infModel.getRawModel();
            BufferedReader br = new BufferedReader(new StringReader(s));
            Rule.Parser parser = Rule.rulesParserFromReader(br);
            List rules = Rule.parseRules(parser);
            InfModel newInfModel = createInfModel(rules,m);
            newInfModel.prepare();
            infModel = newInfModel;
        }
    }

    /**
     * Notation3表記の文字列を受け取り、その内容を既存の RDFモデルに追加します。追加後、前向き推論が実行される
     * ようにInfModelのprepare()を呼出しています。
     */
    public void addNotation3(String s) {
        try {
            synchronized (infModel) {
                String baseURI = "";
                StringReader sr = new StringReader(s);
                infModel.read(sr, baseURI, "N3");
                // StringBufferInputStream sbis = new
                // StringBufferInputStream(s);
                // infModel.read(sbis,baseURI,"N3");
                infModel.prepare();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Notation3表記の文字列を受け取り、その内容を既存のRDFモデルから削除します。
     * 削除後、前向き推論が実行されるようにInfModelのprepare()を呼び出しています。
     */
    public void deleteNotation3(String s) {
        try {
            synchronized (infModel) {
                String baseURI = "";
                StringReader sr = new StringReader(s);
                Model m = ModelFactory.createDefaultModel();
                m.read(sr,baseURI,"N3");
                infModel.remove(m);
                infModel.prepare();
            }
        }catch (Exception e) {
                e.printStackTrace();
        }
    }

    /**
     * SPARQLのクエリを実行して結果を文字列で返します。 SELECT,ASK,CONSTRUCT,DESCRIBEのクエリ全てに 対応します。
     */
    public String execSPARQL(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            if (query.getQueryType() == Query.QueryTypeAsk) {
                ResultSetFormatter.out(baos, qe.execAsk());
            } else if (query.getQueryType() == Query.QueryTypeConstruct) {
                Model m = qe.execConstruct();
                m.write(baos, "N3");
            } else if (query.getQueryType() == Query.QueryTypeDescribe) {
                Model m = qe.execDescribe();
                m.write(baos, "N3");
            } else if (query.getQueryType() == Query.QueryTypeSelect) {
                ResultSet results = qe.execSelect();
                ResultSetFormatter.out(baos, results, query);
            }
            qe.close();
            String result = null;
            try {
                result = baos.toString("UTF-8");
            } catch(Exception e) {
                result = baos.toString();
            }
            return result;
        }
    }

    /**
     * SPARQLのSELECTの実行結果をResultSetで受け取るための メソッドです。
     */
    public ResultSet execSelect(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            return qe.execSelect();
        }
    }

    /**
     * SPARQLのSELECTの実行結果を文字列の配列で受け取るための メソッドです。
     */
    public String[][] execSelectArray(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            ResultSet rs = qe.execSelect();
            List vars = rs.getResultVars();
            ArrayList<String[]> al1 = new ArrayList<String[]>();
            while(rs.hasNext()) {
                QuerySolution qs = rs.nextSolution();
                ArrayList<String> al2 = new ArrayList<String>();
                Iterator i = vars.iterator();
                while (i.hasNext()) {
                    String varName = (String)i.next();
                    if (qs.contains(varName))
                        al2.add(qs.get(varName).toString());
                    else
                        al2.add("");
                }
                al1.add(al2.toArray(new String[0]));
            }
            return al1.toArray(new String[0][0]);
        }
    }

    /**
     * SPARQLのASKの実行結果をbooleanで受け取るための メソッドです。
     */
    public boolean execAsk(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            return qe.execAsk();
        }
    }

    /**
     * SPARQLのCONSTRUCTの実行結果をModelで受け取るための メソッドです。
     */
    public Model execConstruct(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            return qe.execConstruct();
        }
    }

    /**
     * SPARQLのCONSTRUCTの実行結果を文字列の2次元配列で受け取るための
     * メソッドです。
     */
    public String[][] execConstructArray(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            Model m = qe.execConstruct();
            StmtIterator si = m.listStatements();
            ArrayList<String[]> al = new ArrayList<String[]>();
            while (si.hasNext()) {
                Statement st = si.nextStatement();
                String[] tmp = new String[3];
                tmp[0] = st.getSubject().getURI();
                tmp[1] = st.getPredicate().getURI();
                tmp[2] = st.getObject().toString();
                al.add(tmp);
            }
            return al.toArray(new String[0][0]);
        }
    }

    /**
     * SPARQLのDESCRIBEの実行結果をModelで受け取るための メソッドです。
     */
    public Model execDescribe(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            return qe.execDescribe();
        }
    }

    /**
     * SPARQLのDESCRIBEの実行結果をStringの2次元配列で受け取るための
     * メソッドです。
     */
    public String[][] execDescribeArray(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            Model m = qe.execDescribe();
            StmtIterator si = m.listStatements();
            ArrayList<String[]> al = new ArrayList<String[]>();
            while (si.hasNext()) {
                Statement st = si.nextStatement();
                String[] tmp = new String[3];
                tmp[0] = st.getSubject().getURI();
                tmp[1] = st.getPredicate().getURI();
                tmp[2] = st.getObject().toString();
                al.add(tmp);
            }
            return al.toArray(new String[0][0]);
        }
    }

    /**
     * SPARQLのクエリを実行して結果をObjectで返します。 SELECT,ASK,CONSTRUCT,DESCRIBEのクエリ全てに 対応します。
     * execSPARQLメソッドとの違いは返り値がObjectになっていることだけです。
     */
    public Object execSPARQL2(String s) {
        synchronized (infModel) {
            Query query = QueryFactory.create(s);
            QueryExecution qe = QueryExecutionFactory.create(query, infModel);
            if (query.getQueryType() == Query.QueryTypeAsk) {
                return qe.execAsk();
            } else if (query.getQueryType() == Query.QueryTypeConstruct) {
                return qe.execConstruct();
            } else if (query.getQueryType() == Query.QueryTypeDescribe) {
                return qe.execDescribe();
            } else if (query.getQueryType() == Query.QueryTypeSelect) {
                return qe.execSelect();
            } else {
                return null;
            }
        }
    }

    /**
     * RDFモデルの三つ組を削除するためのメソッド。引数はSPARQLのCONSTRUCTクエリ
     * でなくてはならない。これは空白ノードも指定して削除することができるようにする
     * ためである。空白ノードなどを使用しない場合はCONSTRUCTクエリのWHERE節を空に
     * すれば良い。例:「PREFIX : <http://test.org/> CONSTRUCT {:a :b :c} WHERE{}」
     * 返り値は削除した内容をNotation3形式に変換したものになります。
     */
    public String deleteSPARQL(String s) {
        synchronized (infModel) {
            try {
                Query query = QueryFactory.create(s);
                QueryExecution eq = QueryExecutionFactory.create(query,infModel);
                Model m = eq.execConstruct();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                m.write(baos,"N3");
                String res = baos.toString("UTF-8");
                StmtIterator si = m.listStatements();
                ArrayList<Statement> statements = new ArrayList<Statement>();
                while (si.hasNext()) {
                    Statement st = si.nextStatement();
                    statements.add(st);
                }
                Statement ss[] = statements.toArray(new Statement[0]);
                infModel.remove(ss);
                infModel.prepare();
                return res;
            } catch(Exception e) {
                e.printStackTrace();
                return "error";
            }
        }
    }

    /**
     * RDFモデルの三つ組を追加するためのメソッド。引数はSPARQLのCONSTRUCTクエリ
     * でなくてはならない。これは空白ノードも指定して追加することができるようにする
     * ためである。空白ノードなどを使用しない場合はCONSTRUCTクエリのWHERE節を空に
     * すれば良い。例:「PREFIX : <http://test.org/> CONSTRUCT {:a :b :c} WHERE{}」
     * 返り値は追加した内容をNotation3形式に変換したものになります。
     */
    public String insertSPARQL(String s) {
        synchronized (infModel) {
            try {
                Query query = QueryFactory.create(s);
                QueryExecution eq = QueryExecutionFactory.create(query,infModel);
                Model m = eq.execConstruct();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                m.write(baos,"N3");
                String res = baos.toString("UTF-8");
                StmtIterator si = m.listStatements();
                ArrayList<Statement> statements = new ArrayList<Statement>();
                while (si.hasNext()) {
                    Statement st = si.nextStatement();
                    statements.add(st);
                }
                Statement ss[] = statements.toArray(new Statement[0]);
                infModel.add(ss);
                infModel.prepare();
                return res;
            } catch(Exception e) {
                e.printStackTrace();
                return "error";
            }
        }
    }

    /**
     * RDFモデルをupdateするためのメソッド。実際にはupdateではなくdeleteして
     * からinsertするという処理をする。返り値は成功すればtrue
     * 失敗すればfalse。ためしにトランザクション処理もやらせてます。
     * 本当はSPARQL自体がupdateに対応したものになれば一番良いのだけれどね。
     * http://jena.hpl.hp.com/~afs/SPARQL-Update.html
     */
    public boolean deleteAndInsertSPARQL(String delQuery,String insQuery) {
    	synchronized (infModel) {
    		try {
    			if (infModel.supportsTransactions())
    				infModel.begin();
    			Query query = QueryFactory.create(delQuery);
    			QueryExecution eq = QueryExecutionFactory.create(query,infModel);
    			Model m = eq.execConstruct();
    			StmtIterator si = m.listStatements();
    			ArrayList<Statement> statements = new ArrayList<Statement>();
    			while (si.hasNext()) {
    				Statement st = si.nextStatement();
    				statements.add(st);
    			}
    			Statement ss[] = statements.toArray(new Statement[0]);
    			infModel.remove(ss);
    			infModel.prepare();
    			query = QueryFactory.create(insQuery);
    			eq = QueryExecutionFactory.create(query,infModel);
    			m = eq.execConstruct();
    			si = m.listStatements();
    			statements = new ArrayList<Statement>();
    			while (si.hasNext()) {
    				Statement st = si.nextStatement();
    				statements.add(st);
    			}
    			ss = statements.toArray(new Statement[0]);
    			infModel.add(ss);
    			if (infModel.supportsTransactions())
    				infModel.commit();
    			infModel.prepare();
    			return true;
    		} catch(Exception e) {
    			e.printStackTrace();
    			if (infModel.supportsTransactions())
    				infModel.abort();
    			return false;
    		}
    	}
    }
    /**
     * RDFモデルからリストを取り出すためのメソッド。特定のリストを
     * 指定するためにSPARQLのSELECTを使うことにする。
     * SELECTで指定した(最初の)変数にマッチした最初のリストを
     * java.util.Listで返す。
     */
    public List getList(String s) {
    	synchronized (infModel) {
    		try {
    			Query query = QueryFactory.create(s);
    			QueryExecution eq = QueryExecutionFactory.create(query,infModel);
    			ResultSet rs = eq.execSelect();
    			List vars = rs.getResultVars();
    			QuerySolution qs = rs.nextSolution();
    			RDFNode n = qs.get((String)vars.iterator().next());
    			return getListR(n);
    		} catch(Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    }
    private List getListR(RDFNode n) {
    	Property first = infModel.createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#first");
    	Property rest = infModel.createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#rest");
    	Resource nil = infModel.createResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
    	List al = new ArrayList();
    	RDFNode tmpN = n;
    	while (!tmpN.equals(nil)) {
    		RDFNode e = infModel.getProperty((Resource)tmpN, first).getObject();
    		if (e.isAnon())
    			al.add(getListR(e));
    		else
    		    al.add(e.toString());
    		tmpN = infModel.getProperty((Resource)tmpN,rest).getObject();
    	}
    	return al;
    }

    boolean timerEnabled = false;
    long timerInterval = 1000;
    /**
     * タイマーをセットするためのメソッド。trueでセット。
     * falseで解除。
     */
    public boolean setTimer(boolean b) {
        synchronized (infModel) {
            if (b) {
                if (!timerEnabled) {
                    timerEnabled = true;
                    setTimer();
                }
                return true;
            } else {
                timerEnabled = false;
                timer.cancel();
                timer.purge();
                timer = new Timer();
                return false;
            }
        }
    }

    /**
     * タイマーのインターバルをセットするためのメソッド。
     */
    public void setTimerInterval(long l) {
        timerInterval = l;
    }

    /**
     * タイマーのインターバルをセットするためのメソッド。
     */
    public long getTimerInterval() {
        return timerInterval;
    }

    void setTimer() {
        Resource r = infModel.createResource("http://timer.org/namespace#timer");
        Property p = infModel.createProperty("http://timer.org/namespace#timerp");
        Statement s = null;
        while ((s = infModel.getProperty(r, p)) != null) {
            //infModel.remove(s);
            Triple triple = s.asTriple();
            InfGraph inf = (InfGraph)infModel.getGraph();
            Graph raw = inf.getRawGraph();
            Graph deductions = inf.getDeductionsGraph();
            raw.delete(triple);
            deductions.delete(triple);
        } 
        Long t = new Long(System.currentTimeMillis());
        Literal l = infModel.createTypedLiteral(t);
        infModel.add(r, p, l);
        infModel.prepare();
        System.out.print("timer! ");
        if (timerEnabled)
            timer.schedule(new MyTimerTask(this), timerInterval);
    }

    class MyTimerTask extends TimerTask {
        JenaEngine engine;

        MyTimerTask(JenaEngine e) {
            engine = e;
        }

        public void run() {
            engine.setTimer();
        }
    }

    public void setInput(String input) {
    	//Resource r = infModel.createResource("http://input.org/namespace#input");
    	Resource r = infModel.createResource();
        //Property p = infModel.createProperty("http://input.org/namespace#inputp");
        Property p = infModel.createProperty("http://input.org/namespace#input");
        Statement s = null;
        //while ((s = infModel.getProperty(r, p)) != null) {
        while ((s = infModel.getProperty(null, p)) != null) {
            //infModel.remove(s);
            Triple triple = s.asTriple();
            InfGraph inf = (InfGraph)infModel.getGraph();
            Graph raw = inf.getRawGraph();
            Graph deductions = inf.getDeductionsGraph();
            raw.delete(triple);
            deductions.delete(triple);
        } 
        Literal l = infModel.createTypedLiteral(input);
        infModel.add(r, p, l);
        infModel.prepare();
        //System.out.print("input! ");
    }
    // --------------------------------------
    // 以下非同期用のメソッドです。

    /**
     * 非同期のメソッド呼び出しは、すべてこのメソッドから行う。
     * 処理内容は引数のJEMessageの第1引数にセットし、処理の受け取りオブジェクトを
     * 第2引数で指定して、処理に必要な引数は第三引数以降で指定する。
     */
    public void recieveRequest(JEMessage m) {
        synchronized (requestQueue) {
            requestQueue.add(m);
            requestQueue.notifyAll();
        }
    }

    public void run() {
        while (true) {
            try {
                processRequest();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (stopRequest==true)
                return;
        }
    }

    void processRequest() {
        JEMessage m = null;
        while (true) {
            synchronized (requestQueue) {
                if (requestQueue.size() != 0) {
                    m = requestQueue.get(0);
                    requestQueue.remove(0);
                    break;
                } else {
                    try {
                        if (stopRequest==false)
                            requestQueue.wait();
                        else
                            return;
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        if (m.type == JEMessage.Type.SPARQL)
            processSPARQL(m);
        else if (m.type == JEMessage.Type.INSERT_N3)
            processINSERT_N3(m);
        else if (m.type == JEMessage.Type.DELETE_N3)
            processDELETE_N3(m);
        else if (m.type == JEMessage.Type.SET_TIMER)
            processSET_TIMER(m);
        else if (m.type == JEMessage.Type.SET_RULES)
            processSET_RULE(m);
        else if (m.type == JEMessage.Type.LOAD_RDF)
            processLOAD_RDF(m);
        else if (m.type == JEMessage.Type.DEL_SPARQL)
            processDEL_SPARQL(m);
        else if (m.type == JEMessage.Type.INS_SPARQL)
            processINS_SPARQL(m);
        else if (m.type == JEMessage.Type.SET_INPUT)
            processSET_INPUT(m);
        else if (m.type == JEMessage.Type.DEL_INS_SPARQL)
        	processDEL_INS_SPARQL(m);
        else
            System.err.println("JenaEngine Error(NO TYPE).");
        if (m.listener != null)
            m.listener.performResultMessage(m);
    }

    void processSPARQL(JEMessage m) {
        m.result = execSPARQL2((String)m.args[0]);
    }

    void processINSERT_N3(JEMessage m) {
        String s = (String) m.args[0];
        addNotation3(s);
        m.result = new Boolean(true);
    }

    void processDELETE_N3(JEMessage m) {
        String s = (String) m.args[0];
        deleteNotation3(s);
        m.result = new Boolean(true);
    }

    void processDEL_SPARQL(JEMessage m) {
        String s = (String) m.args[0];
        String res = deleteSPARQL(s);
        m.result = res;
    }

    void processINS_SPARQL(JEMessage m) {
        String s = (String) m.args[0];
        String res = insertSPARQL(s);
        m.result = res;
    }

    void processSET_TIMER(JEMessage m) {
        boolean b = ((Boolean)m.args[0]).booleanValue();
        timerInterval = ((Long) m.args[1]).longValue();
        setTimer(b);
        m.result = new Boolean(b);
    }

    void processSET_RULE(JEMessage m) {
        String s = (String) m.args[0];
        setRules(s);
        m.result = new Boolean(true);
    }

    void processLOAD_RDF(JEMessage m) {
        String s = (String) m.args[0];
        loadRDF(s);
        m.result = new Boolean(true);
    }

    void processSET_INPUT(JEMessage m) {
        String s = (String) m.args[0];
        setInput(s);
        m.result = s;
    }

    void processDEL_INS_SPARQL(JEMessage m) {
    	String delQuery = (String) m.args[0];
    	String insQuery = (String) m.args[1];
    	boolean b = deleteAndInsertSPARQL(delQuery,insQuery);
    	m.result = b;
    }
}
