Skip to content
Snippets Groups Projects
Commit be3bd445 authored by cmaeder's avatar cmaeder
Browse files

separate class to populate the database

parent 103f2e5b
Branches
No related tags found
No related merge requests found
/** The superclass of all Errors generated by MMT
* @param shortMsg the error message
*/
abstract class Error(val shortMsg: String) extends java.lang.Exception(shortMsg) {
private var causedBy: Option[java.lang.Throwable] = None
def setCausedBy(e: java.lang.Throwable): this.type = {
causedBy = Some(e); this
}
//def getCausedBy : Option[java.lang.Throwable] = causedBy
private def stackTrace: String = getStackTrace.map(_.toString).mkString("", "\n", "")
def getLongMessage: String = {
val causedByMsg = causedBy match {
case None => ""
case Some(e: Error) => "\n\ncaused by\n" + e.getLongMessage
case Some(e) => "\n\ncaused by\n" + e.getClass + ": " + e.getMessage + e.getStackTrace.map(_.toString).mkString("\n", "\n", "")
}
getMessage + "\ndetected at\n" + stackTrace + causedByMsg
}
override def toString = shortMsg
def toNode: scala.xml.Node = <error type={this.getClass.toString} shortMsg={this.shortMsg}>
{this.getLongMessage}
</error>
}
object Level {
type Level = Int
val Info = 0
val Warning = 1
val Error = 2
val Fatal = 3
}
import Level._
/** other errors that occur during parsing */
case class ParseError(s: String) extends Error("parse error: " + s)
/** errors that occur when parsing a knowledge item */
case class SourceError(
origin: String, ref: SourceRef, mainMessage: String, extraMessages: List[String] = Nil, level: Level = Level.Error
) extends Error("source error (origin) at " + ref.toString + ": " + mainMessage) {
override def getMessage = mainMessage + extraMessages.mkString("\n", "\n", "\n")
override def toNode = <error type={this.getClass.toString} shortMsg={this.shortMsg} level={this.level.toString} sref={ref.region.toString}>
{this.getLongMessage}
</error>
}
/** errors that occur during compiling */
object CompilerError {
def apply(key: String, ref: SourceRef, messageList: List[String], level: Level) =
SourceError(key, ref, messageList.head, messageList.tail, level)
}
/** errors that occur when checking a knowledge item (generated by the Checker classes) */
abstract class Invalid(s: String) extends Error(s)
/** other errors */
case class GeneralError(s: String) extends Error("general error: " + s)
/** errors that occur when adding a knowledge item */
case class AddError(s: String) extends Error("add error: " + s)
/** errors that occur when updating a knowledge item */
case class UpdateError(s: String) extends Error("update error: " + s)
/** errors that occur when deleting a knowledge item */
case class DeleteError(s: String) extends Error("delete error: " + s)
/** errors that occur when retrieving a knowledge item */
case class GetError(s: String) extends Error("get error: " + s)
/** errors that occur when presenting a knowledge item */
case class PresentationError(s: String) extends Error(s)
/** errors that occur when registering extensions */
case class RegistrationError(s: String) extends Error(s)
/** errors that are not supposed to occur, e.g., when input violates the precondition of a method */
case class ImplementationError(s: String) extends Error("implementation error: " + s)
/** base class for errors that are thrown by an extension */
abstract class ExtensionError(prefix: String, s: String) extends Error(prefix + ": " + s)
/**
* the type of continuation functions for error handling
*
* An ErrorHandler is passed in most situations in which a component
* might produce a non-fatal error.
*/
abstract class ErrorHandler {
private var newErrors = false
def mark() {
newErrors = false
}
/** true if new errors occurred since the last call to mark */
def hasNewErrors = newErrors
/**
* registers an error
*
* This should be called exactly once on every error, usually in the order in which they are found.
*/
def apply(e: Error) {
newErrors = true
addError(e)
}
protected def addError(e: Error)
}
/**
* throws errors
*/
object ErrorThrower extends ErrorHandler {
protected def addError(e: Error) {
throw e
}
}
import java.io.File
import org.slf4j.{Logger, LoggerFactory}
import scala.xml._
/**
* Created by maeder on 13.01.15.
* try parsing <error> tags
*/
class ParseXML(db: PopulateDB) {
val log: Logger = LoggerFactory.getLogger(this.getClass)
def readXml(f: File): NodeSeq = {
try {
val xml = XML.loadFile(f.getPath)
xml \\ "error"
} catch {
case e: SAXParseException =>
log.info(f + "\nLine " + e.getLineNumber + ":" + e.getColumnNumber)
Nil
}
}
def getAttrs(attrs: List[String], x: Node): List[String] = {
val as = x.attributes
attrs map (a => as.get(a).getOrElse("").toString)
}
def traverse(dir: File, proc: File => Unit): Unit =
dir.listFiles map (f => if (f.isDirectory) traverse(f, proc) else proc(f))
def procFile(proc: (File, Node) => Unit)(f: File): Unit = {
if (f.canRead && f.getPath.endsWith(".err") && f.length() > 0) {
val errs = readXml(f)
if (errs.isEmpty) log.info("no errors in: " + f)
else errs map (x => procErr(f, x))
}
else log.info("skipped: " + f)
}
def procErr(f: File, x: Node): Unit = {
val elems = x.child filter (c => c.isInstanceOf[Elem])
val List(t, smsg, level) = getAttrs(List("type", "shortMsg", "level"), x)
def infoMessage(msg: String) =
log.info(msg + "\nFile: " + f + "\nNode: " + smsg)
var lvl: Int = 0
if (level.isEmpty) infoMessage("empty error level")
else
try {
lvl = level.toInt
} catch {
case e: NumberFormatException => infoMessage(e.getMessage)
}
db.insertError(List(f.getPath, t, smsg, level, x.text))
if (elems.nonEmpty)
infoMessage("ignored sub-elements")
}
def parseDir(dir: String): Unit =
traverse(new File(dir), procFile(procErr))
}
import java.util
import org.apache.camel.CamelContext
import org.apache.camel.component.sql.SqlComponent
import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.scala.dsl.builder.RouteBuilder
import org.sqlite.SQLiteDataSource
import scala.collection.JavaConverters._
class PopulateDB extends RouteBuilder {
def insertError(vs: List[String]): Unit = {
val hm = new util.HashMap[String, String]((Table.columns zip vs).toMap.asJava)
getContext.createProducerTemplate().sendBody("direct:insertValues", hm)
}
def initTable(): Unit =
getContext.createProducerTemplate().sendBody("direct:createTables", null)
"direct:insertValues" -->
("db:insert into " + Table.name + Table.columns.mkString(" (", ", ", ") values ") +
Table.columns.map(":#" + _).mkString("(", ", ", ")"))
"direct:createTables" --> ("db:drop table if exists " + Table.name) -->
("db:create table " + Table.name +
Table.columns.map(_ + " STRING").mkString(" (id integer primary key, ", ", ", ")"))
}
object PopulateDB {
def main(args: scala.Array[String]): Unit = {
val sqlComponent: SqlComponent = new SqlComponent()
val ds: SQLiteDataSource = new SQLiteDataSource()
val name = if (args.isEmpty) Table.name else args(0)
val dbName = if (name.endsWith(".db")) name else name + ".db"
ds.setDatabaseName(dbName)
ds.setUrl("jdbc:sqlite:" + dbName)
sqlComponent.setDataSource(ds)
val dbBuilder = new PopulateDB()
val context: CamelContext = new DefaultCamelContext()
context.addRoutes(dbBuilder)
context.addComponent("db", sqlComponent)
context.start()
dbBuilder.initTable()
val pa = new ParseXML(dbBuilder)
val dir = if (args.length > 1) args(1) else System.getProperty("user.dir")
pa.parseDir(dir)
}
}
/** region in a source block
* @param start inclusive start position
* @param end inclusive end position
*/
case class SourceRegion(start: SourcePosition, end: SourcePosition) {
/** inverse of SourceRegion.parse */
override def toString = start.toString + ":" + end.toString
/** l.c-l.c */
def twoDimString = start.twoDimString + ":" + end.twoDimString
/** number of characters in this region */
def length = end.offset - start.offset + 1
def contains(that: SourceRegion) = start <= that.start && that.end <= end
}
/** helper object */
object SourceRegion {
/** parses the format start-end */
def parse(s: String): SourceRegion = {
val parts = if (s.contains(':')) s.split(":").toList else s.split("-").toList
if (parts.length == 2) SourceRegion(SourcePosition.parse(parts(0)), SourcePosition.parse(parts(1)))
else throw ParseError("illegal source region: " + s)
}
def ofString(s: String) = SourceRegion(SourcePosition(0, 0, 0), SourcePosition(s.length - 1, 0, s.length - 1))
}
/** position in a source block; both one and two-dimensional coordinates are maintained
* @param offset one-dimensional coordinate, -1 if omitted
* @param line vertical two-dimensional coordinate
* @param column horizontal two-dimensional coordinate
* all coordinates start from 0
*/
case class SourcePosition(offset: Int, line: Int, column: Int) {
/** inverse of SourcePosition.parse */
override def toString = offset + "." + line + "." + column
def twoDimString = line + "." + column
/** same as twoDimString but colums and rows are counted from 1, not 0 */
def twoDimStringFromOne = (line + 1) + "." + (column + 1)
/** the position that is i places later in the same line */
def +(i: Int) = SourcePosition(offset + i, line, column + i)
/** the position after the string s, which starts at the current position (s may contain newlines) */
def after(s: String) = {
var sp = this
s foreach { c =>
if (c == '\n') sp = sp.nl
else sp += 1
}
sp
}
/**
* the position that is i places earlier in the same line
*
* pre: i >= column
*/
def -(i: Int) = SourcePosition(offset - i, line, column - i)
/** the difference between two position */
def -(that: SourcePosition) = this.offset - that.offset
/** the position that is 1 places later at the beginning of the the next line */
def nl = SourcePosition(offset + 1, line + 1, 0)
/** the SourceRegion of lenght 1 at this SourcePosition */
def toRegion = SourceRegion(this, this)
def <=(that: SourcePosition) =
if (offset != -1 && that.offset != -1)
offset <= that.offset
else
line <= that.line && column <= that.column
}
/** helper object */
object SourcePosition {
/** parses the format offset.line.column */
def parse(s: String): SourcePosition = {
val parts = s.split("\\.").toList
if (parts.length == 3) {
val (o, l, c) = try {
(parts(0).toInt, parts(1).toInt, parts(2).toInt)
} catch {
case e: Throwable => throw ParseError("non-integer in source position " + s)
}
SourcePosition(o, l, c)
}
else throw ParseError("illegal source position: " + s)
}
}
/** region in an identified source block
* @param container URI of the source document
* @param region in that document
*/
case class SourceRef(container: URI, region: SourceRegion) {
def toURI = container ## region.toString
override def toString = toURI.toString
def contains(that: SourceRef) = container == that.container && (region contains that.region)
}
object SourceRef {
def fromURI(u: URI) = {
val container = u.copy(fragment = None)
val reg = SourceRegion.parse(u.fragment.getOrElse(""))
SourceRef(container, reg)
}
def toURI(s: SourceRef) = s.toURI
def anonymous(s: String) = {
val reg = SourceRegion.ofString(s)
SourceRef(URI.empty, reg)
}
}
/** Custom implementation of the URI RFC that's better than java.net.URI
*
* @param abs true if the path is absolute (ignored if scheme or authority are present) */
case class URI(scheme: Option[String], authority: Option[String], path: List[String] = Nil, private val abs: Boolean = false, query: Option[String] = None, fragment: Option[String] = None) {
/** true if the path is absolute; automatically set to true if scheme or authority are present */
def absolute = abs || scheme.isDefined || authority.isDefined
/** drop path, query, fragment, append (absolute) path of length 1 */
def !/(n: String): URI = this !/ List(n)
/** drop path, query, fragment, append (absolute) path */
def !/(p: List[String]): URI = {
URI(scheme, authority, p, abs = true, None, None)
}
/** drop query, fragment, append one segment to path */
def /(n: String): URI = this / List(n)
/** drop query, fragment, append to path
* path stays relative/absolute; but URI(_, Some(_), Nil, false, _, _) / _ turns path absolute
* trailing empty segment of this URI is dropped when appending
*/
def /(p: List[String]): URI = URI(scheme, authority, pathNoTrailingSlash ::: p, absolute)
/** drops query and fragment, drop last path segment (if any) */
def ^ : URI = URI(scheme, authority, if (path.isEmpty) Nil else path.init, absolute)
/** drops query and fragment and path */
def ^! : URI = URI(scheme, authority)
/** drop query, fragment, append query */
def ?(q: String) = URI(scheme, authority, path, absolute, Some(q))
/** drop fragment, append fragment */
def ##(f: String) = URI(scheme, authority, path, absolute, query, Some(f))
/** true iff this is a prefix of u */
def <=(u: URI): Boolean = u.toString.startsWith(this.toString)
/** makes a URI relative to this one */
def relativize(u: URI): URI =
if (scheme != u.scheme) u
else if (authority != u.authority) URI(None, u.authority, u.path, u.absolute, u.query, u.fragment)
else if (path != u.path) {
if (absolute == u.absolute && path != Nil) {
val max = path.length - 1
var i = 0
while (i <= max && u.path.startsWith(path.take(i + 1))) i += 1
// now path.take(i) == u.path.take(i)
URI(None, None, Range(0, max - i).toList.map(_ => "..") ::: u.path.drop(i), abs = false, u.query, u.fragment)
} else
URI(None, None, u.path, u.absolute, u.query, u.fragment)
} else if (query != u.query) URI(None, None, Nil, abs = false, u.query, u.fragment)
else if (fragment != u.fragment) URI(None, None, Nil, abs = false, None, u.fragment)
else URI(None, None, Nil, abs = false, None, None)
/**
* changes the (file) extension of the last path segment (if any) to ext
* extension is added if none exists
*/
def setExtension(ext: String) =
if (path.nonEmpty) {
val oldLast = path.last
val posOfDot = oldLast.lastIndexOf(".")
val newLast = (if (posOfDot == -1) oldLast
else
oldLast.substring(0, posOfDot)) + "." + ext
copy(path = path.init ::: List(newLast))
} else
this
/** parses a URI and resolves it against this */
def resolve(s: String): URI = resolve(URI(s))
/** resolves a URI against this one (using the java.net.URI resolution algorithm except when u has no scheme, authority, path) */
def resolve(u: URI): URI = {
//resolve implements old URI RFC, therefore special case for query-only URI needed
if (u.scheme == None && u.authority == None && u.path == Nil)
URI(scheme, authority, path, absolute, u.query, u.fragment)
else
URI(toJava.resolve(u.toJava))
}
/** removes an empty trailing segment, which results from a trailing / */
def pathNoTrailingSlash = if (path.endsWith(List(""))) path.init else path
/** returns the whole path as a string (/-separated, possibly with a leading /) */
def pathAsString: String = {
val tmp = path.mkString(if (absolute) "/" else "", "/", "")
tmp.indexOf(";") match {
case -1 => tmp
case i => tmp.substring(0, i)
}
}
/** convenience: the scheme or null */
def schemeNull: String = scheme.orNull
/** convenience: the authority or null */
def authorityNull: String = authority.orNull
def toJava = new java.net.URI(scheme.orNull, authority.orNull, pathAsString, query.orNull, fragment.orNull)
override def toString = toJava.toString
}
object URI {
private def nullToNone(s: String) = if (s == null) None else Some(s)
private val pattern = java.util.regex.Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?")
// pattern taken from RFC 3986 /** transforms a Java URI into a URI */
def apply(uri: java.net.URI): URI = URI(uri.toString)
/** parses a URI (using the regular expression from the RFC) */
def apply(s: String): URI = {
val m = pattern.matcher(s)
if (!m.matches)
throw new java.net.URISyntaxException(s, "malformed URI reference")
val scheme = nullToNone(m.group(2))
val authority = nullToNone(m.group(4))
val jpath = m.group(5)
val (pathString, absolute) = {
if (jpath.startsWith("/")) (jpath.substring(1), true)
else (jpath, false)
}
var path = pathString.split("/", -1).toList
if (path == List("")) //note: split returns at least List(""), never Nil
path = Nil
val query = nullToNone(m.group(7))
val fragment = nullToNone(m.group(9))
URI(scheme, authority, path, absolute, query, fragment)
}
/** returns a relative URI with scheme and authority only */
def apply(s: String, a: String): URI = URI(Some(s), Some(a))
/** returns an absolute URI with scheme, authority, and path */
def apply(s: String, a: String, p: List[String]): URI = URI(Some(s), Some(a), p, abs = true)
/** returns a URI with scheme, authority, absolute path, and query */
def apply(scheme: String, authority: String, path: List[String], query: String): URI =
(URI(scheme, authority) / path) ? query
/** returns a URI with a scheme only */
def scheme(s: String) = URI(Some(s), None)
def empty = URI(None, None)
/** the URI "file:" */
val file = scheme("file")
/** returns a URI with no scheme or authority and relative path */
def relative(path: String*) = URI(None, None, path.toList, abs = false)
def toJava(u: URI): java.net.URI = u.toJava
def fromJava(u: java.net.URI) = apply(u)
}
/*
//split key=value into (key,value), missing value defaults to ""
def splitKeyVal(p : String) : (String, String) = {
val l = p.split("=",2)
if (l.length == 1)
(l(0), "") else (l(0),l(1))
}
def Unsplit(q : Map[String,String]) = q.elements.map(x => x._1 + "=" + x._2).toList.myFold("")((x,y) => x + ";" + y)
*/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment