View Javadoc
1   package net.sumaris.core.dao.technical.schema;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Core
6    * %%
7    * Copyright (C) 2018 SUMARiS Consortium
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  
26  import com.google.common.base.Preconditions;
27  import com.google.common.collect.Maps;
28  import net.sumaris.core.config.SumarisConfiguration;
29  import org.hibernate.boot.model.relational.QualifiedTableName;
30  import org.hibernate.mapping.*;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import java.sql.DatabaseMetaData;
35  import java.sql.ResultSet;
36  import java.sql.SQLException;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.*;
40  
41  /**
42   * Overrides of the {@link SumarisTableMetadata} with some improvements:
43   * <ul>
44   * <li>Obtains HSQL slect query via {@link #getSelectHQLQuery()}</li>
45   * <li>Use cached JPA data to load index/foreign keys</li>
46   * </ul>
47   * <p/>
48   *
49   * @author Benoit Lavenier <benoit.lavenier@e-is.pro>
50   * @since 1.0
51   */
52  public class SumarisHibernateTableMetadata extends SumarisTableMetadata {
53  
54  	private static final Logger log =
55  			LoggerFactory.getLogger(SumarisHibernateTableMetadata.class);
56  
57  	protected final Table delegate;
58  
59  	protected final PersistentClass persistentClass;
60  
61  	protected String hqlSelectQuery;
62  
63  	protected Map<String, ForeignKey> foreignKeys;
64  
65  	public SumarisHibernateTableMetadata(Table delegate,
66  										 SumarisDatabaseMetadata dbMeta,
67  										 DatabaseMetaData jdbcDbMeta,
68  										 PersistentClass persistentClass) throws SQLException{
69  		this(delegate.getQualifiedTableName(), delegate, dbMeta, jdbcDbMeta, persistentClass);
70  	}
71  
72  	protected SumarisHibernateTableMetadata(QualifiedTableName tableName,
73  											Table delegate,
74  											SumarisDatabaseMetadata dbMeta,
75  											DatabaseMetaData jdbcDbMeta,
76  											PersistentClass persistentClass) throws SQLException{
77  		super(tableName, dbMeta, jdbcDbMeta);
78  		Preconditions.checkNotNull(dbMeta);
79  
80  		this.delegate = delegate;
81  		this.persistentClass = persistentClass;
82  
83  		init(dbMeta, jdbcDbMeta);
84  	}
85  
86  	protected void init(SumarisDatabaseMetadata dbMeta, DatabaseMetaData jdbcDbMeta) throws SQLException {
87  		if (this.delegate == null) return; // skip, when called by inherited constructor
88  
89  		// super init
90  		super.init(dbMeta, jdbcDbMeta);
91  
92  		// Specific to Hibernate
93  		try {
94  
95  			this.foreignKeys = initForeignKeys(delegate);
96  
97  			this.hqlSelectQuery = persistentClass != null ? String.format(QUERY_HQL_SELECT, this.persistentClass.getEntityName()) : null;
98  
99  		} catch (Exception e) {
100 			throw new SQLException("Could not init metadata on table " + tableName.getTableName(), e);
101 		}
102 	}
103 
104 	public String getSelectHQLQuery() {
105 		return hqlSelectQuery;
106 	}
107 
108 	public int getColumnsCount() {
109 		return columns.size();
110 	}
111 
112 	public Map<String, ForeignKey> getForeignKeys() {
113 		return foreignKeys;
114 	}
115 
116 	@Override
117 	protected Set<String> initPrimaryKeys(DatabaseMetaData jdbcDbMeta) {
118 		Preconditions.checkNotNull(delegate);
119 		Map<String, Column> result = Maps.newLinkedHashMap();
120 		for(Iterator propertyIterator = delegate.getPrimaryKey().getColumnIterator();
121 			propertyIterator.hasNext(); ) {
122 			Column column = (Column) propertyIterator.next();
123 			result.put(column.getName(), column);
124 		}
125 
126 		return result.keySet();
127 	}
128 
129 	@Override
130 	protected Map<String, SumarisColumnMetadata> initColumns(QualifiedTableName tableName, DatabaseMetaData jdbcDbMeta) throws SQLException {
131 		Preconditions.checkNotNull(delegate);
132 		Map<String, Column> columns = Maps.newLinkedHashMap();
133 		for (Iterator propertyIterator = delegate.getColumnIterator();
134 			 propertyIterator.hasNext(); ) {
135 			Column column = (Column) propertyIterator.next();
136 			columns.put(column.getName().toLowerCase(), column);
137 		}
138 
139 		Map<String, SumarisColumnMetadata> result = Maps.newLinkedHashMap();
140 		ResultSet rs = jdbcDbMeta.getColumns(getCatalog(), getSchema(), getName().toUpperCase(), "%");
141 
142 		try {
143 			while(rs.next()) {
144 				String columnName = rs.getString("COLUMN_NAME").toLowerCase();
145 				String defaultValue = SumarisConfiguration.getInstance().getColumnDefaultValue(getName(), columnName);
146 
147 				Column column = columns.get(columnName);
148 				if (column != null) {
149 					SumarisHibernateColumnMetadata columnMeta = new SumarisHibernateColumnMetadata(rs, column, defaultValue);
150 					result.put(columnName.toLowerCase(), columnMeta);
151 				}
152 				else {
153 					log.warn(String.format("Column {%s} not mapped in the entity class {%s}", columnName, persistentClass.getEntityName()));
154 					SumarisColumnMetadata columnMeta = new SumarisColumnMetadata(rs, defaultValue);
155 					result.put(columnName.toLowerCase(), columnMeta);
156 				}
157 			}
158 		}
159 		finally {
160 			if (rs != null) {
161 				rs.close();
162 			}
163 		}
164 		if (result.size() == 0) {
165 			throw new RuntimeException("Unable to load columns metadata on table " + delegate.getName());
166 		}
167 
168 		return result;
169 	}
170 
171 	protected Map<String, ForeignKey> initForeignKeys(Table delegate) {
172 		Map<String, ForeignKey> result = Maps.newLinkedHashMap();
173 		for(Iterator foreignKeyIterator = delegate.getForeignKeyIterator();
174 			foreignKeyIterator.hasNext(); ) {
175 			ForeignKey foreignKey = (ForeignKey) foreignKeyIterator.next();
176 
177 			result.put(foreignKey.getName().toLowerCase(), foreignKey);
178 		}
179 
180 		return result;
181 	}
182 }