/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you 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 jlibs.jdbc.annotations.processor; import jlibs.core.annotation.processing.AnnotationError; import jlibs.core.lang.NotImplementedException; import jlibs.core.lang.StringUtil; import jlibs.core.lang.model.ModelUtil; import jlibs.jdbc.JavaType; import jlibs.jdbc.SQLType; import jlibs.jdbc.annotations.Column; import jlibs.jdbc.annotations.Database; import jlibs.jdbc.annotations.Table; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class ConnectionInfo{ static Map<String, ConnectionInfo> ALL = new HashMap<String, ConnectionInfo>(); Connection con; boolean failOnMissingColumns; ConnectionInfo(Connection con, boolean failOnMissingColumns){ this.con = con; this.failOnMissingColumns = failOnMissingColumns; } private String identifier(String identifier) throws SQLException{ DatabaseMetaData metadata = con.getMetaData(); if(!metadata.supportsMixedCaseIdentifiers()){ if(metadata.storesUpperCaseIdentifiers()) return identifier.toUpperCase(); else if(metadata.storesLowerCaseIdentifiers()) return identifier.toLowerCase(); } return identifier; } public void validate(Columns columns) throws SQLException{ try{ ResultSet rs = con.getMetaData().getTables(null, null, identifier(columns.tableName), null); if(!rs.next()) throw new AnnotationError(columns.tableClass, Table.class, "name", columns.tableName+" table doesn't exist in database"); rs.close(); List<String> columnNames = new ArrayList<String>(); rs = con.getMetaData().getColumns(null, null, columns.tableName, null); while(rs.next()) columnNames.add(rs.getString(4)); for(ColumnProperty column: columns){ columnNames.remove(column.columnName()); rs = con.getMetaData().getColumns(null, null, identifier(columns.tableName), identifier(column.columnName())); if(!rs.next()) throw new AnnotationError(column.element, Column.class, "name", column.columnName()+" column doesn't exist in "+columns.tableName+" table"); int type = rs.getInt(5); SQLType sqlType = SQLType.valueOf(type); if(sqlType==null) throw new NotImplementedException("SQLType is not defined for "+type); if(!JavaType.isCompatible(column.javaType(), sqlType)){ Class suggested = JavaType.valueOf(sqlType).clazz; throw new AnnotationError(column.element, Column.class, "name", column.columnName()+" has incompatible java type. "+suggested.getName()+" is suggested"); } rs.close(); } if(columnNames.size()>0){ AnnotationError error = new AnnotationError(columns.tableClass, "column properties are missing for columns " + StringUtil.join(columnNames.iterator(), ", ")); if(failOnMissingColumns) throw error; else error.warn(); } }finally{ con.close(); } } public static void add(PackageElement pakage) throws Exception{ TypeElement tableClass = (TypeElement)((DeclaredType)ModelUtil.getAnnotationValue(pakage, Database.class, "driver")).asElement(); Class.forName(tableClass.getQualifiedName().toString()); String url = ModelUtil.getAnnotationValue(pakage, Database.class, "url"); String user = ModelUtil.getAnnotationValue(pakage, Database.class, "user"); String password = ModelUtil.getAnnotationValue(pakage, Database.class, "password"); Connection con; if(StringUtil.isEmpty(user) && StringUtil.isEmpty(password)) con = DriverManager.getConnection(url); else con = DriverManager.getConnection(url, user, password); boolean failOnMissingColumns = (Boolean)ModelUtil.getAnnotationValue(pakage, Database.class, "failOnMissingColumns"); ALL.put(ModelUtil.getPackage(pakage), new ConnectionInfo(con, failOnMissingColumns)); } public static ConnectionInfo get(Columns columns){ String pakage = ModelUtil.getPackage(columns.tableClass); ConnectionInfo info; while(true){ info = ALL.get(pakage); if(info!=null) break; int dot = pakage.lastIndexOf('.'); if(dot==-1) break; pakage = pakage.substring(0, dot); } return info; } }