/* * codjo.net * * Common Apache License 2.0 */ package net.codjo.broadcast.server; import java.math.BigDecimal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import net.codjo.broadcast.common.Context; import net.codjo.broadcast.common.Preferences; import net.codjo.broadcast.common.PreferencesManager; import net.codjo.broadcast.common.columns.FileColumnFactory; import net.codjo.broadcast.common.columns.FileColumnGenerator; import net.codjo.broadcast.common.computed.ComputedField; import net.codjo.database.common.api.DatabaseFactory; import net.codjo.database.common.api.SQLFieldList; import net.codjo.database.common.impl.sqlfield.DefaultSQLFieldList; import net.codjo.sql.builder.FieldInfo; import net.codjo.sql.builder.JoinKey; import net.codjo.sql.builder.TableName; import net.codjo.variable.TemplateInterpreter; import net.codjo.variable.UnknownVariableException; import org.apache.log4j.Logger; /** * Classe Home des colonnes de diffusions. * * @author $Author: galaber $ * @version $Revision: 1.6 $ */ class FileColumnHome { private static final Logger APP = Logger.getLogger(FileColumnHome.class); private static final String QUERY_SELECT = "select * " + "from $column$ broadcast_column " + "inner join $section$ section " + " on broadcast_column.SECTION_ID = section.SECTION_ID " + "inner join $fileContents$ broadcast_contents " + " on broadcast_contents.SECTION_ID = section.SECTION_ID " + "where broadcast_contents.CONTENT_ID = ? " + "order by broadcast_column.COLUMN_NUMBER"; private final DatabaseFactory databaseFactory = new DatabaseFactory(); private FileColumnFactory factory = new FileColumnFactory(); private Map<String, SQLFieldList> tableDefinition = new HashMap<String, SQLFieldList>(); private PreferencesManager preferenceManager; private String loadQuery; /** * Positionne le <code>PreferencesManager</code> pour ce home, et pre-calcul la table de definition. * * @throws IllegalArgumentException si un<code>Preferences</code> est incoherent */ public void init(Connection connection, PreferencesManager preferencesManager) { this.preferenceManager = preferencesManager; Map<String, String> arguments = new HashMap<String, String>(); arguments.put("column", preferenceManager.getColumnsTableName()); arguments.put("section", preferenceManager.getSectionTableName()); arguments.put("fileContents", preferenceManager.getFileContentsTableName()); arguments.put("file", preferenceManager.getFileTableName()); loadQuery = formatQuery(QUERY_SELECT, arguments); try { tableDefinition = determineTableDefinition(connection); } catch (SQLException error) { APP.error("Impossible d'initialiser le HOME des colonnes", error); throw new IllegalArgumentException(error.getLocalizedMessage()); } } /** * DOCUMENT ME! */ protected FieldInfo buildFieldInfo(Map<FieldInfo, FieldInfo> definedFieldInfo, ResultSet rs) throws SQLException { FieldInfo fieldInfo = new FieldInfo(new TableName(rs.getString("DB_TABLE_NAME")), rs.getString("DB_FIELD_NAME"), rs.getInt("COLUMN_NUMBER")); if (definedFieldInfo.containsKey(fieldInfo)) { fieldInfo = definedFieldInfo.get(fieldInfo); } else { definedFieldInfo.put(fieldInfo, fieldInfo); } return fieldInfo; } /** * Charge les FileColumnGenerator d'une section. * * @param connection la connection JDBC * @param contentId Identifiant d'un File content * * @return les FileColumnGenerator d'une section */ public FileColumnGenerator[] loadFileColumns(Connection connection, BigDecimal contentId, Preferences sectionPreferences, Context context) throws SQLException { Map<FieldInfo, FieldInfo> definedFieldInfo = new HashMap<FieldInfo, FieldInfo>(); List<FileColumnGenerator> list = new ArrayList<FileColumnGenerator>(); PreparedStatement loadStatment = connection.prepareStatement(loadQuery); loadStatment.setBigDecimal(1, contentId); ResultSet rs = loadStatment.executeQuery(); try { while (rs.next()) { list.add(newFileColumnGenerator(rs, definedFieldInfo, sectionPreferences, context)); } } finally { rs.close(); } return list.toArray(new FileColumnGenerator[list.size()]); } private SQLFieldList getComputedFieldList(Preferences pref) { SQLFieldList fieldList = new DefaultSQLFieldList(); ComputedField[] fields = pref.getComputedFields(); for (ComputedField field : fields) { fieldList.addField(field.getName(), field.getSqlType()); } return fieldList; } /** * Determine la d�finition des tables utilisables par la diffusion. * * @param connection la connection JDBC * * @return Table de hash (key=TableName, Value=SQLFieldList) * * @throws SQLException Erreur MetaData */ private Map<String, SQLFieldList> determineTableDefinition(Connection connection) throws SQLException { Map<String, SQLFieldList> def = new HashMap<String, SQLFieldList>(); for (Iterator<Preferences> iter = preferenceManager.iterator(); iter.hasNext();) { Preferences prefs = iter.next(); def.putAll(determineTableDefinition(connection, prefs)); } return def; } private Map<String, SQLFieldList> determineTableDefinition(Connection connection, Preferences pref) throws SQLException { HashMap<String, SQLFieldList> def = new HashMap<String, SQLFieldList>(); // Ajoute les computed field def.put(pref.getFamily() + "_" + pref.getComputedTableName(), getComputedFieldList(pref)); // Ajoute de la table maitres def.put(pref.getFamily() + "_" + pref.getBroadcastTableName(), databaseFactory.createSQLFieldList(connection, null, pref.getBroadcastTableName())); // Ajoute les tables non temporaire for (String joinKeyName : pref.getConfig().getJoinKeyMap().keySet()) { if (joinKeyName.startsWith("#")) { continue; } // Pas une Table temporaire JoinKey joinKey = pref.getConfig().getJoinKeyMap().get(joinKeyName); if (joinKey != null) { TableName tab = new TableName(joinKey.getLeftTableName()); if (!def.containsKey(tab.getDBTableName())) { APP.debug("determineTableDefinition " + tab.getDBTableName()); def.put(tab.getDBTableName(), databaseFactory.createSQLFieldList(connection, null, tab.getDBTableName())); } String name = pref.getFamily() + "_" + joinKeyName; if (!def.containsKey(name)) { def.put(name, def.get(tab.getDBTableName())); } } } return def; } private int findSqlType(String joinKeyName, String fieldName, String family) { SQLFieldList fieldList = tableDefinition.get(family + "_" + joinKeyName); if (fieldList == null) { throw new NoSuchElementException("La table >" + joinKeyName + "< ne fait pas partie des tables utilisables " + "pour la diffusion"); } try { return fieldList.getFieldType(fieldName); } catch (NoSuchElementException ex) { throw new NoSuchElementException("La colonne >" + fieldName + "< n'existe pas dans la jointure >" + joinKeyName + "<"); } } private String formatQuery(String queryPattern, Map<String, String> properties) { TemplateInterpreter interpreter = new TemplateInterpreter(); interpreter.addAsVariable(properties); try { return interpreter.evaluate(queryPattern); } catch (UnknownVariableException ex) { throw new IllegalArgumentException(ex.toString()); } } private FileColumnGenerator newFileColumnGenerator(ResultSet rs, Map<FieldInfo, FieldInfo> definedFieldInfo, Preferences section, Context context) throws SQLException { FieldInfo fieldInfo = buildFieldInfo(definedFieldInfo, rs); int sqlType = findSqlType(fieldInfo.getFullDBTableName(), fieldInfo.getDBFieldName(), section.getFamily()); return factory.newFileColumnGenerator(rs, fieldInfo, sqlType, section.createFunctionHolder(context)); } }