/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.topicmaps.query.parser; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.net.URL; import java.util.regex.Pattern; import java.util.regex.Matcher; import net.ontopia.topicmaps.utils.ctm.Template; import net.ontopia.topicmaps.utils.ctm.CTMLexer; import net.ontopia.topicmaps.utils.ctm.CTMParser; import net.ontopia.topicmaps.query.core.InvalidQueryException; import antlr.Token; import antlr.RecognitionException; import antlr.TokenStreamException; import antlr.TokenStreamIOException; import antlr.TokenStreamRecognitionException; /** * INTERNAL: The tolog query parser. */ public class TologParser { protected ParseContextIF context; protected TologOptions options; private static final Pattern insertP = Pattern.compile("(^|\\s+)insert\\s+", Pattern.CASE_INSENSITIVE); private static final Pattern fromP = Pattern.compile("\\s+from\\s+", Pattern.CASE_INSENSITIVE); public TologParser(ParseContextIF context, TologOptions options) { this.context = context; this.options = options; } /** * Returns a parsed SELECT statement. */ public TologQuery parseQuery(String query) throws InvalidQueryException { return parseQuery(new StringReader(query)); } /** * Returns a parsed SELECT statement. */ public TologQuery parseQuery(Reader queryReader) throws InvalidQueryException { try { RealTologParser parser = makeParser(queryReader); parser.setContext(new LocalParseContext(context)); parser.query(); return (TologQuery) parser.getStatement(); } catch (AntlrWrapException ex) { Exception e = ex.getException(); if (e instanceof InvalidQueryException) throw (InvalidQueryException)e; else throw new InvalidQueryException(e); } catch (JFlexWrapException ex) { Exception e = ex.getException(); if (e instanceof InvalidQueryException) throw (InvalidQueryException)e; else throw new InvalidQueryException(e); } catch (RecognitionException ex) { throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamRecognitionException e) { RecognitionException ex = e.recog; throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamIOException ex) { throw new InvalidQueryException(ex.io.toString()); } catch (TokenStreamException ex) { throw new InvalidQueryException("Lexical error: " + ex.getMessage()); } } /** * Returns a parsed INSERT/UPDATE/MERGE/DELETE statement. */ public TologStatement parseStatement(String query) throws InvalidQueryException { if (isInsertStatement(query)) { int insertpos = findInsert(query); int frompos = findFrom(query, insertpos); String ctm; if (frompos != -1) { ctm = query.substring(insertpos + 6, frompos); query = query.substring(0, insertpos + 6) + " " + query.substring(frompos); } else { ctm = query.substring(insertpos + 6); query = query.substring(0, insertpos + 6); } InsertStatement stmt = (InsertStatement) parseStatement(new StringReader(query)); stmt.setCTMPart(ctm, context); return stmt; } else return parseStatement(new StringReader(query)); } /** * Returns a parsed INSERT/UPDATE/MERGE/DELETE statement. */ private TologStatement parseStatement(Reader queryReader) throws InvalidQueryException { try { RealTologParser parser = makeParser(queryReader); parser.setContext(context); parser.updatestatement(); return parser.getStatement(); } catch (AntlrWrapException ex) { Exception e = ex.getException(); if (e instanceof InvalidQueryException) throw (InvalidQueryException)e; else throw new InvalidQueryException(e); } catch (RecognitionException ex) { throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamRecognitionException e) { RecognitionException ex = e.recog; throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamIOException ex) { throw new InvalidQueryException(ex.io.toString()); } catch (TokenStreamException ex) { throw new InvalidQueryException("Lexical error: " + ex.getMessage()); } } public ParseContextIF parseDeclarations(String decls) throws InvalidQueryException { try { ParseContextIF ctxt = new LocalParseContext(context); RealTologParser parser = makeParser(new StringReader(decls)); parser.setContext(ctxt); parser.declarations(); return ctxt; } catch (AntlrWrapException ex) { Exception e = ex.getException(); if (e instanceof InvalidQueryException) throw (InvalidQueryException)e; else throw new InvalidQueryException(e); } catch (RecognitionException ex) { throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamRecognitionException e) { RecognitionException ex = e.recog; throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamIOException ex) { throw new InvalidQueryException(ex.io.toString()); } catch (TokenStreamException ex) { throw new InvalidQueryException("Lexical error: " + ex.getMessage()); } } public void load(String ruleset) throws InvalidQueryException { load(new StringReader(ruleset)); } public void load(Reader reader) throws InvalidQueryException { try { RealTologParser parser = makeParser(reader); parser.setContext(context); parser.ruleset(); } catch (AntlrWrapException ex) { Exception e = ex.getException(); if (e instanceof InvalidQueryException) throw (InvalidQueryException)e; else throw new InvalidQueryException(e); } catch (RecognitionException ex) { throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamRecognitionException e) { RecognitionException ex = e.recog; throw new InvalidQueryException("Lexical error at " /*+ getBaseAddress().getAddress() + ":"*/ + ex.line + ":" + ex.column + ": "+ ex.getMessage()); } catch (TokenStreamIOException ex) { throw new InvalidQueryException(ex.io.toString()); } catch (TokenStreamException ex) { throw new InvalidQueryException("Lexical error: " + ex.getMessage()); } } public ParseContextIF getContext() { return context; } // --- Internal methods private RealTologParser makeParser(Reader reader) throws InvalidQueryException { TologLexer lexer = new TologLexer(reader, options); RealTologParser parser = new RealTologParser(lexer); parser.init(lexer); return parser; } // --- Extra code to deal with INSERT statements private boolean isInsertStatement(String query) { Matcher matcher = insertP.matcher(query); return matcher.find(); } private int findInsert(String query) { Reader reader = new StringReader(query); TologLexer lexer = new TologLexer(reader, options); Token token = lexer.nextToken(); while (token.getType() != RealTologParser.INSERT) token = lexer.nextToken(); return lexer.getStartOfToken(); } private int findFrom(String query, int insertpos) { query = query.substring(insertpos + 6); Reader reader = new StringReader(query); CTMLexer lexer = new CTMLexer(reader); Token token = lexer.nextToken(); while (!(token.getType() == CTMParser.IDENTIFIER && token.getText().equalsIgnoreCase("from")) && token.getType() != CTMParser.EOF) token = lexer.nextToken(); if (token.getType() == CTMParser.EOF) return -1; else return lexer.getStartOfToken() + insertpos + 6; } }