package com.knowgate.storage;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.net.URL;
import java.net.URLDecoder;
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.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;
public final class SchemaMetaData extends DefaultHandler {
private HashMap<String,LinkedList<Column>> oColumnCatalog;
private LinkedList<String> oRecordCatalog;
private LinkedList<String> oTableCatalog;
private String sTableName,sPojoClass,sSchemaName,sPackageName;
private LinkedList<Column> oColDefs;
private int iColPos;
public SchemaMetaData() {
oColumnCatalog = new HashMap<String,LinkedList<Column>>();
oRecordCatalog = new LinkedList<String>();
oTableCatalog = new LinkedList<String>();
}
public SchemaMetaData(String sPackagePath) throws FileNotFoundException, IOException, ClassNotFoundException {
oColumnCatalog = new HashMap<String,LinkedList<Column>>();
oRecordCatalog = new LinkedList<String>();
oTableCatalog = new LinkedList<String>();
load(new File(SchemaMetaData.getAbsolutePath(sPackagePath)+"tables"));
}
protected static String getAbsolutePath(String sPackagePath)
throws FileNotFoundException, ClassNotFoundException {
URL oPackURL;
if (sPackagePath.endsWith("com/knowgate/clocial")) {
Class oModMan = Class.forName("com.knowgate.clocial.ModelManager");
oPackURL = oModMan.getResource("/com/knowgate/clocial");
} else {
oPackURL = ClassLoader.class.getResource(sPackagePath.startsWith("/") ? sPackagePath : "/" + sPackagePath);
}
if (null==oPackURL)
throw new FileNotFoundException("Could not find "+sPackagePath+" at CLASSPATH");
String sAbsolutePath = URLDecoder.decode(oPackURL.toString());
if (sAbsolutePath.startsWith("file:")) sAbsolutePath = sAbsolutePath.substring(5);
if (sAbsolutePath.matches("/\\w:[/\\x5C]\\w.+")) sAbsolutePath = sAbsolutePath.substring(1);
if (!sAbsolutePath.endsWith(File.separator)) sAbsolutePath += File.separator;
return sAbsolutePath;
} //
public void load(InputStream oInStm) {
if (DebugFile.trace) DebugFile.writeln("Begin MetaData.load()");
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);
InputSource oInSrc = new InputSource(oInStm);
oParser.parse(oInSrc);
oInStm.close();
} catch (InstantiationException e) {
try {
if (DebugFile.trace) DebugFile.writeln("InstantiationException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (ClassNotFoundException e) {
try {
if (DebugFile.trace) DebugFile.writeln("ClassNotFoundException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (IllegalAccessException e) {
try {
if (DebugFile.trace) DebugFile.writeln("IllegalAccessException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (IOException e) {
try {
if (DebugFile.trace) DebugFile.writeln("IOException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
} catch (SAXException e) {
try {
if (DebugFile.trace) DebugFile.writeln("SAXException "+e.getMessage()+"\n"+StackTraceUtil.getStackTrace(e));
} catch (IOException ignore) {}
}
if (DebugFile.trace) DebugFile.writeln("End MetaData.load()");
}
// -------------------------------------------------------------------------
public void load(File oFle) throws FileNotFoundException, IOException {
if (!oFle.exists()) throw new FileNotFoundException("File "+oFle.getAbsolutePath()+" not found");
if (oFle.isDirectory()) {
File[] aFiles = oFle.listFiles();
for (int f=0; f<aFiles.length; f++) {
FileInputStream oFin = new FileInputStream(aFiles[f]);
load(oFin);
oFin.close();
} // next
} else {
FileInputStream oFin = new FileInputStream(oFle);
load(oFin);
oFin.close();
}
}
// -------------------------------------------------------------------------
public String getSchemaName() {
return sSchemaName;
}
// -------------------------------------------------------------------------
public String getPackageName() {
return sPackageName;
}
// -------------------------------------------------------------------------
public LinkedList<Column> getColumns(String sTableName)
throws ArrayIndexOutOfBoundsException {
if (oColumnCatalog.containsKey(sTableName))
return oColumnCatalog.get(sTableName);
else
throw new ArrayIndexOutOfBoundsException("No Table nor Record found with name "+sTableName);
}
// -------------------------------------------------------------------------
public LinkedList<String> getRecordsClassNames() {
return oRecordCatalog;
}
// -------------------------------------------------------------------------
public LinkedList<String> getTablesNames() {
return oTableCatalog;
}
// -------------------------------------------------------------------------
public void startDocument() throws SAXException {
} // 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);
oTableCatalog.add(sTableName);
if (sPojoClass!=null) {
if (sPojoClass.length()>0) {
String sCls = sPojoClass.indexOf('.')>0 ? sPojoClass : sPackageName+"."+sPojoClass;
if (DebugFile.trace) DebugFile.writeln("Getting Class.forName("+sCls+")");
@SuppressWarnings("unused")
Class oCls = Class.forName(sCls);
oColumnCatalog.put(sCls, oColDefs);
oRecordCatalog.add(sCls);
}
}
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);
} finally {
oColDefs = null;
sTableName = null;
}
}
} // endElement
// -------------------------------------------------------------------------
}