/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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 org.apereo.portal.tools.dbloader; import java.lang.reflect.Field; import java.sql.Types; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; import org.hibernate.MappingException; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Mappings; import org.hibernate.dialect.Dialect; import org.hibernate.mapping.Column; import org.hibernate.mapping.Index; import org.hibernate.mapping.PrimaryKey; import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** * Builds an object model of Hibernate mapping objects for tables based on an XML definition file. * Once parsing is complete the generated objects are availabe via {@link #getTables()} * */ public class TableXmlHandler extends BaseDbXmlHandler implements ITableDataProvider { private final Mappings mappings = new Configuration().createMappings(); private final Dialect dialect; public TableXmlHandler(Dialect dialect) { this.dialect = dialect; } @Override public Map<String, Table> getTables() { return this.tables; } @Override public Map<String, Map<String, Integer>> getTableColumnTypes() { return tableColumnTypes; } private Map<String, Table> tables = new LinkedHashMap<String, Table>(); private Map<String, Map<String, Integer>> tableColumnTypes = new TreeMap<String, Map<String, Integer>>(String.CASE_INSENSITIVE_ORDER); private Table currentTable = null; private Map<String, Column> currentColumns = null; private Map<String, Integer> currentColumnTypes = null; private Column currentColumn = null; private PrimaryKey primaryKey = null; private Index currentIndex = null; private UniqueKey currentUnique = null; /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { if ("table".equals(name)) { this.currentColumns = new LinkedHashMap<String, Column>(); this.currentColumnTypes = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER); } else if ("index".equals(name)) { this.currentIndex = new Index(); this.currentIndex.setTable(this.currentTable); } else if ("unique".equals(name)) { this.currentUnique = new UniqueKey(); this.currentUnique.setTable(this.currentTable); } this.chars = new StringBuilder(); } /* (non-Javadoc) * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ @Override public void endElement(String uri, String localName, String name) throws SAXException { if ("table".equals(name)) { for (final Column column : this.currentColumns.values()) { this.currentTable.addColumn(column); } if (this.primaryKey != null) { this.currentTable.setPrimaryKey(this.primaryKey); } this.tables.put(this.currentTable.getName(), this.currentTable); this.tableColumnTypes.put(this.currentTable.getName(), this.currentColumnTypes); this.primaryKey = null; this.currentColumns = null; this.currentColumnTypes = null; this.currentTable = null; } else if ("column".equals(name)) { this.currentColumns.put(this.currentColumn.getName(), this.currentColumn); this.currentColumn = null; } else if ("name".equals(name)) { final String itemName = this.chars.toString().trim(); if (this.currentIndex != null) { this.currentIndex.setName(itemName); } else if (this.currentUnique != null) { this.currentUnique.setName(itemName); } else if (this.currentTable == null) { this.currentTable = new Table(itemName); } else if (this.currentColumn == null) { this.currentColumn = new Column(itemName); } } else if ("type".equals(name)) { final String sqlTypeName = this.chars.toString().trim(); final int sqlType = this.getSqlType(sqlTypeName); this.currentColumnTypes.put(this.currentColumn.getName(), sqlType); final String hibType = this.getHibernateType(sqlType); final SimpleValue value = new SimpleValue(this.mappings, this.currentTable); value.setTypeName(hibType); this.currentColumn.setValue(value); } else if ("param".equals(name)) { final String param = this.chars.toString().trim(); final Integer length = Integer.valueOf(param); this.currentColumn.setLength(length); } else if ("primary-key".equals(name)) { final String columnName = this.chars.toString().trim(); if (this.primaryKey == null) { this.primaryKey = new PrimaryKey(); } final Column column = this.currentColumns.get(columnName); this.primaryKey.addColumn(column); } else if ("not-null".equals(name)) { final String columnName = this.chars.toString().trim(); final Column column = this.currentColumns.get(columnName); column.setNullable(false); } else if ("column-ref".equals(name)) { final String columnName = this.chars.toString().trim(); final Column column = this.currentColumns.get(columnName); if (this.currentIndex != null) { this.currentIndex.addColumn(column); } else if (this.currentUnique != null) { this.currentUnique.addColumn(column); } } else if ("index".equals(name)) { this.currentTable.addIndex(this.currentIndex); this.currentIndex = null; } else if ("unique".equals(name)) { this.currentTable.addUniqueKey(this.currentUnique); this.currentUnique = null; } else if ("key".equals(name)) { this.logger.warn( "the 'key' element is ignored, use the table level 'primary-key' element instead"); } this.chars = null; } protected int getSqlType(final String sqlTypeName) { try { final Field sqlTypeField = Types.class.getField(sqlTypeName); return sqlTypeField.getInt(null); } catch (SecurityException e) { throw new RuntimeException( "Cannot access field '" + sqlTypeName + "' on " + Types.class + " for column '" + this.currentColumn.getName() + "'", e); } catch (NoSuchFieldException e) { throw new IllegalArgumentException( "No SQL Type field '" + sqlTypeName + "' on " + Types.class + " for column '" + this.currentColumn.getName() + "'", e); } catch (IllegalArgumentException e) { throw new RuntimeException( "Cannot access field '" + sqlTypeName + "' on " + Types.class + " for column '" + this.currentColumn.getName() + "'", e); } catch (IllegalAccessException e) { throw new RuntimeException( "Cannot access field '" + sqlTypeName + "' on " + Types.class + " for column '" + this.currentColumn.getName() + "'", e); } } protected String getHibernateType(final int sqlType) { final String hibType; try { hibType = this.dialect.getHibernateTypeName(sqlType); } catch (MappingException e) { throw new IllegalArgumentException( "No mapped hibernate type found for '" + sqlType + "' Types value=" + sqlType + " for column '" + this.currentColumn.getName() + "'", e); } return hibType; } }