package com.knowgate.clocial;
import java.io.InputStream;
import java.io.IOException;
import java.sql.Types;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.HashMap;
import org.xml.sax.Attributes;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.XMLReaderFactory;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.ParserAdapter;
import org.xml.sax.helpers.ParserFactory;
import com.knowgate.debug.DebugFile;
import com.knowgate.debug.StackTraceUtil;
import com.knowgate.storage.Column;
import com.knowgate.storage.Record;
public final class MetaData extends DefaultHandler {
private static MetaData Schema = new MetaData();
private HashMap<String,LinkedList<Column>> oColumnCatalog;
private HashMap<String,Record> oRecordCatalog;
private String sTableName,sPojoClass,sSchemaName,sPackageName;
private LinkedList<Column> oColDefs;
private int iColPos;
boolean bInitialized;
public MetaData() {
oColumnCatalog = new HashMap<String,LinkedList<Column>>();
oRecordCatalog = new HashMap<String,Record>();
bInitialized = false;
}
private void init() {
if (!bInitialized) {
if (DebugFile.trace) DebugFile.writeln("Begin MetaData.init()");
bInitialized = true;
try {
XMLReader oParser;
Parser oSax1Parser;
try {
oParser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
}
catch (Exception e) {
oSax1Parser = ParserFactory.makeParser("org.apache.xerces.parsers.SAXParser");
oParser = new ParserAdapter(oSax1Parser);
}
oParser.setContentHandler(this);
InputStream oInStm;
if (DebugFile.trace) {
java.net.URL oResUrl = getClass().getResource("MetaData.xml");
if (oResUrl==null)
DebugFile.writeln("Could not get resource MetaData.xml");
else
DebugFile.writeln("Getting resource with URL "+oResUrl.toString());
oInStm = getClass().getResourceAsStream("MetaData.xml");
DebugFile.writeln("parsing");
int i;
char[] c = new char[1];
while ((i=oInStm.read())!=-1) {
c[0] = (char) i;
DebugFile.write(c);
} // wend
DebugFile.writeln("\n");
}
oInStm = getClass().getResourceAsStream("MetaData.xml");
InputSource oInSrc = new InputSource(oInStm);
oParser.parse(oInSrc);
oInStm.close();
} catch (InstantiationException e) {
bInitialized = false;
try {
if (DebugFile.trace) DebugFile.writeln("InstantiationException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (ClassNotFoundException e) {
bInitialized = false;
try {
if (DebugFile.trace) DebugFile.writeln("ClassNotFoundException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (IllegalAccessException e) {
bInitialized = false;
try {
if (DebugFile.trace) DebugFile.writeln("IllegalAccessException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (IOException e) {
bInitialized = false;
try {
if (DebugFile.trace) DebugFile.writeln("IOException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (SAXException e) {
bInitialized = false;
try {
if (DebugFile.trace) DebugFile.writeln("SAXException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
}
if (DebugFile.trace) DebugFile.writeln("End MetaData.init()");
} // fi
}
// -------------------------------------------------------------------------
public static MetaData getDefaultSchema() {
Schema.init();
return Schema;
}
// -------------------------------------------------------------------------
public String getSchemaName() {
init();
return sSchemaName;
}
// -------------------------------------------------------------------------
public String getPackageName() {
init();
return sPackageName;
}
// -------------------------------------------------------------------------
public LinkedList<Column> getColumns(String sTableName)
throws ArrayIndexOutOfBoundsException {
init();
if (oColumnCatalog.containsKey(sTableName))
return oColumnCatalog.get(sTableName);
else if (oRecordCatalog.containsKey(sTableName))
return getColumns(oRecordCatalog.get(sTableName).getTableName());
else
throw new ArrayIndexOutOfBoundsException("No Table nor Record found with name "+sTableName);
}
// -------------------------------------------------------------------------
public HashMap<String,Record> getRecords() {
init();
return oRecordCatalog;
} // getRecords()
// -------------------------------------------------------------------------
public void startDocument() throws SAXException {
init();
} // startDocument
// -------------------------------------------------------------------------
public void startElement(String uri, String local, String raw, Attributes attrs) throws SAXException {
String sDefVal,sName=null,sCheck=null,sForeignKey=null;
int iType = Types.NULL;
int iMaxLength = 0;
Object oDefVal = null;
boolean bNullable=true,bIsPk=false,bIndexed=false;
if (local.equals("Record")) {
oColDefs = new LinkedList<Column>();
sTableName = attrs.getValue("table");
sPojoClass = attrs.getValue("pojo");
if (DebugFile.trace) DebugFile.writeln("Reading definition for "+sTableName);
iColPos = 0;
if (null==sTableName) throw new SAXException("Table name is required");
} else if (local.equals("Column")) {
try {
sName = attrs.getValue("name");
if (null==sName) throw new SAXException("Name for Column at "+sTableName+" is required");
iType = Types.VARCHAR;
String sType = attrs.getValue("type");
if (sType==null) {
iType = Types.VARCHAR;
} else if (sType.equalsIgnoreCase("VARCHAR")) {
iType = Types.VARCHAR;
} else if (sType.equalsIgnoreCase("INT") || sType.equalsIgnoreCase("INTEGER")) {
iType = Types.INTEGER;
} else if (sType.equalsIgnoreCase("BIGINT")) {
iType = Types.BIGINT;
} else if (sType.equalsIgnoreCase("DECIMAL")) {
iType = Types.DECIMAL;
} else if (sType.equalsIgnoreCase("DATETIME") || sType.equalsIgnoreCase("TIMESTAMP")) {
iType = Types.TIMESTAMP;
} else if (sType.equalsIgnoreCase("BOOLEAN")) {
iType = Types.BOOLEAN;
} else if (sType.equalsIgnoreCase("VARBINARY")) {
iType = Types.LONGVARBINARY;
} else if (sType.equalsIgnoreCase("LONGVARCHAR")) {
iType = Types.LONGVARCHAR;
} else if (sType.equalsIgnoreCase("LONGVARBINARY")) {
iType = Types.LONGVARBINARY;
} else if (sType.equalsIgnoreCase("JAVA_OBJECT")) {
iType = Types.JAVA_OBJECT;
} else {
iType = Types.VARCHAR;
}
if (attrs.getValue("maxlength")==null) {
switch (iType) {
case Types.BOOLEAN:
iMaxLength = 5;
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = Boolean.parseBoolean(sDefVal);
break;
case Types.CHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
iMaxLength = 256;
break;
case Types.VARCHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
iMaxLength = 8000;
break;
case Types.LONGVARCHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
iMaxLength = 2147483647;
break;
case Types.SMALLINT:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = new Short(sDefVal);
iMaxLength = 5;
break;
case Types.INTEGER:
sDefVal = attrs.getValue("default");
if (sDefVal!=null)
if (sDefVal.equalsIgnoreCase("SERIAL"))
oDefVal = "SERIAL";
else
oDefVal = new Integer(sDefVal);
iMaxLength = 11;
break;
case Types.BIGINT:
sDefVal = attrs.getValue("default");
if (sDefVal!=null)
if (sDefVal.equalsIgnoreCase("SERIAL"))
oDefVal = "SERIAL";
else
oDefVal = new Long(sDefVal);
iMaxLength = 21;
break;
case Types.DECIMAL:
case Types.NUMERIC:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = new BigDecimal(sDefVal);
iMaxLength = 28;
break;
case Types.DATE:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) {
if (sDefVal.equalsIgnoreCase("current_timestamp") || sDefVal.toLowerCase().startsWith("now")) {
oDefVal = new java.util.Date();
} else {
SimpleDateFormat oFmt = new SimpleDateFormat("yyyy-MM-dd");
try { oDefVal = oFmt.parse(sDefVal); }
catch (ParseException pe) { throw new SAXException(pe.getMessage(),pe); }
}
}
iMaxLength = 10;
break;
case Types.TIMESTAMP:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) {
if (sDefVal.equalsIgnoreCase("current_timestamp") || sDefVal.toLowerCase().startsWith("now")) {
oDefVal = new java.util.Date();
} else {
SimpleDateFormat oFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try { oDefVal = oFmt.parse(sDefVal); }
catch (ParseException pe) { throw new SAXException(pe.getMessage(),pe); }
}
}
iMaxLength = 24;
break;
case Types.VARBINARY:
iMaxLength = 65535;
break;
case Types.LONGVARBINARY:
case Types.JAVA_OBJECT:
iMaxLength = 2147483647;
break;
default:
iMaxLength = 2147483647;
}
} else {
try {
iMaxLength = Integer.parseInt(attrs.getValue("maxlength"));
} catch (NumberFormatException e) {
throw new SAXException("Invalid maxlength attribute for column "+sName);
}
if (iMaxLength<0) {
throw new SAXException("Invalid maxlength attribute for column "+sName+" cannot be a negative integer");
}
switch (iType) {
case Types.BOOLEAN:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = Boolean.parseBoolean(sDefVal);
break;
case Types.CHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
break;
case Types.VARCHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
break;
case Types.LONGVARCHAR:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = sDefVal;
break;
case Types.SMALLINT:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = new Short(sDefVal);
break;
case Types.INTEGER:
sDefVal = attrs.getValue("default");
if (sDefVal!=null)
if (sDefVal.equalsIgnoreCase("SERIAL"))
oDefVal = "SERIAL";
else
oDefVal = new Integer(sDefVal);
break;
case Types.DECIMAL:
case Types.NUMERIC:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) oDefVal = new BigDecimal(sDefVal);
break;
case Types.DATE:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) {
if (sDefVal.equalsIgnoreCase("current_timestamp") || sDefVal.toLowerCase().startsWith("now")) {
oDefVal = new java.util.Date();
} else {
SimpleDateFormat oFmt = new SimpleDateFormat("yyyy-MM-dd");
try { oDefVal = oFmt.parse(sDefVal); }
catch (ParseException pe) { throw new SAXException(pe.getMessage(),pe); }
}
}
break;
case Types.TIMESTAMP:
sDefVal = attrs.getValue("default");
if (sDefVal!=null) {
if (sDefVal.equalsIgnoreCase("current_timestamp") || sDefVal.toLowerCase().startsWith("now")) {
oDefVal = new java.util.Date();
} else {
SimpleDateFormat oFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try { oDefVal = oFmt.parse(sDefVal); }
catch (ParseException pe) { throw new SAXException(pe.getMessage(),pe); }
}
}
break;
}
}
if (attrs.getValue("constraint")==null) {
bIsPk = false;
} else {
bIsPk = attrs.getValue("constraint").equalsIgnoreCase("primary key") ||
attrs.getValue("constraint").equalsIgnoreCase("primarykey");
}
if (attrs.getValue("indexed")==null) {
bIndexed = false;
} else {
bIndexed = Boolean.parseBoolean(attrs.getValue("indexed"));
}
if (attrs.getValue("nullable")==null) {
bNullable = true;
} else {
bNullable = Boolean.parseBoolean(attrs.getValue("nullable"));
}
sForeignKey = attrs.getValue("foreignkey");
sCheck = attrs.getValue("check");
if (iType==Types.TIMESTAMP && sCheck==null)
sCheck = "\\d\\d\\d\\d-[01]\\d-[0123]\\d [012]\\d:[012345]\\d:[012345]\\d";
oColDefs.add(new Column(++iColPos, sName, iType, iMaxLength,
bNullable, bIndexed, sCheck, sForeignKey, oDefVal, bIsPk));
} catch (org.apache.oro.text.regex.MalformedPatternException mpe) {
if (DebugFile.trace) DebugFile.writeln("MalformedPatternException "+attrs.getValue("check")+" for column "+attrs.getValue("name"));
throw new SAXException("Malformed pattern "+attrs.getValue("check")+" for column "+attrs.getValue("name"),mpe);
}
if (DebugFile.trace) DebugFile.writeln("readed definition for column "+sName+" "+Column.typeName(iType)+"("+String.valueOf(iMaxLength)+") "+(bNullable ? "NULL" : "NOT NULL")+" "+(bIsPk ? "PRIMARY KEY" : bIndexed ? "INDEXED" : "")+" DEFAULT "+oDefVal+" CHECK "+sCheck+" REFERENCES "+sForeignKey);
} else if (local.equals("Schema")) {
if (DebugFile.trace) DebugFile.writeln("Reading schema "+attrs.getValue("name")+" with package "+attrs.getValue("package"));
sSchemaName = attrs.getValue("name");
sPackageName = attrs.getValue("package");
}
} // startElement
// -------------------------------------------------------------------------
public void endElement(String uri, String local, String name) throws SAXException {
if (local.equals("Record")) {
try {
if (DebugFile.trace) {
String sColNames = "";
for (Column c : oColDefs) sColNames += " "+c.getName();
DebugFile.writeln("put "+sTableName+" table at columns catalog with columns"+sColNames);
}
oColumnCatalog.put(sTableName, oColDefs);
if (sPojoClass!=null) {
if (sPojoClass.length()>0) {
String sCls = sPojoClass.indexOf('.')>0 ? sPojoClass : sPackageName+"."+sPojoClass;
if (DebugFile.trace) DebugFile.writeln("Getting Class.forName("+sCls+")");
Class oCls = Class.forName(sCls);
if (DebugFile.trace) DebugFile.writeln("Creating new instance of "+sCls+" with default constructor");
oRecordCatalog.put(sCls, (Record) oCls.newInstance());
}
}
if (DebugFile.trace) DebugFile.writeln("Definition for "+sTableName+" readed");
} catch (ClassNotFoundException cnfe) {
if (DebugFile.trace) DebugFile.writeln("ClassNotFoundException "+sPojoClass);
throw new SAXException("Class not found "+sPojoClass, cnfe);
} catch (InstantiationException inse) {
if (DebugFile.trace) DebugFile.writeln("InstantiationException "+sPojoClass);
throw new SAXException("Instantiation exception "+sPojoClass, inse);
} catch (IllegalAccessException ilae) {
if (DebugFile.trace) DebugFile.writeln("IllegalAccessException "+sPojoClass);
throw new SAXException("Illegal access exception "+sPojoClass, ilae);
} finally {
oColDefs = null;
sTableName = null;
}
}
} // endElement
// -------------------------------------------------------------------------
}