public class IdentitySchema {

  private static final String IDENTITY_TABLE_PREFIX = "JBPM_ID_";

  Configuration configuration = null;
  Properties properties = null;
  Dialect dialect = null;
  Mapping mapping = null;
  String[] createSql = null;
  String[] dropSql = null;
  String[] cleanSql = null;

  ConnectionProvider connectionProvider = null;
  Connection connection = null;
  Statement statement = null;

  public IdentitySchema(Configuration configuration) {
    this.configuration = configuration;
    this.properties = configuration.getProperties();
    this.dialect = Dialect.getDialect(properties);
    try {
      // get the mapping field via reflection :-(
      Field mappingField = Configuration.class.getDeclaredField("mapping");
      mappingField.setAccessible(true);
      this.mapping = (Mapping) mappingField.get(configuration);
    } catch (Exception e) {
      throw new RuntimeException("couldn't get the hibernate mapping", e);
    }
  }

  // scripts lazy initializations /////////////////////////////////////////////

  public String[] getCreateSql() {
    if (createSql == null) {
      createSql = configuration.generateSchemaCreationScript(dialect);
    }
    return createSql;
  }

  public String[] getDropSql() {
    if (dropSql == null) {
      dropSql = configuration.generateDropSchemaScript(dialect);
    }
    return dropSql;
  }

  public String[] getCleanSql() {
    if (cleanSql == null) {
      // loop over all foreign key constraints
      List dropForeignKeysSql = new ArrayList();
      List createForeignKeysSql = new ArrayList();
      Iterator iter = configuration.getTableMappings();
      while (iter.hasNext()) {
        Table table = (Table) iter.next();
        if (table.isPhysicalTable()) {
          Iterator subIter = table.getForeignKeyIterator();
          while (subIter.hasNext()) {
            ForeignKey fk = (ForeignKey) subIter.next();
            if (fk.isPhysicalConstraint()) {
              // collect the drop key constraint
              dropForeignKeysSql.add(
                  fk.sqlDropString(
                      dialect,
                      properties.getProperty(Environment.DEFAULT_CATALOG),
                      properties.getProperty(Environment.DEFAULT_SCHEMA)));
              createForeignKeysSql.add(
                  fk.sqlCreateString(
                      dialect,
                      mapping,
                      properties.getProperty(Environment.DEFAULT_CATALOG),
                      properties.getProperty(Environment.DEFAULT_SCHEMA)));
            }
          }
        }
      }

      List deleteSql = new ArrayList();
      iter = configuration.getTableMappings();
      while (iter.hasNext()) {
        Table table = (Table) iter.next();
        deleteSql.add("delete from " + table.getName());
      }

      List cleanSqlList = new ArrayList();
      cleanSqlList.addAll(dropForeignKeysSql);
      cleanSqlList.addAll(deleteSql);
      cleanSqlList.addAll(createForeignKeysSql);

      cleanSql = (String[]) cleanSqlList.toArray(new String[cleanSqlList.size()]);
    }
    return cleanSql;
  }

  // runtime table detection //////////////////////////////////////////////////

  public boolean hasIdentityTables() {
    return (getIdentityTables().size() > 0);
  }

  public List getIdentityTables() {
    // delete all the data in the jbpm tables
    List jbpmTableNames = new ArrayList();
    try {
      createConnection();
      ResultSet resultSet = connection.getMetaData().getTables("", "", null, null);
      while (resultSet.next()) {
        String tableName = resultSet.getString("TABLE_NAME");
        if ((tableName != null)
            && (tableName.length() > 5)
            && (IDENTITY_TABLE_PREFIX.equalsIgnoreCase(tableName.substring(0, 5)))) {
          jbpmTableNames.add(tableName);
        }
      }
    } catch (SQLException e) {
      throw new RuntimeException("couldn't get the jbpm table names");
    } finally {
      closeConnection();
    }
    return jbpmTableNames;
  }

  // script execution methods /////////////////////////////////////////////////

  public void dropSchema() {
    execute(getDropSql());
  }

  public void createSchema() {
    execute(getCreateSql());
  }

  public void cleanSchema() {
    execute(getCleanSql());
  }

  public void saveSqlScripts(String dir, String prefix) {
    try {
      new File(dir).mkdirs();
      saveSqlScript(dir + "/" + prefix + ".drop.sql", getDropSql());
      saveSqlScript(dir + "/" + prefix + ".create.sql", getCreateSql());
      saveSqlScript(dir + "/" + prefix + ".clean.sql", getCleanSql());
      new SchemaExport(configuration)
          .setDelimiter(getSqlDelimiter())
          .setOutputFile(dir + "/" + prefix + ".drop.create.sql")
          .create(true, false);
    } catch (Exception e) {
      throw new RuntimeException("couldn't generate scripts", e);
    }
  }

  // main /////////////////////////////////////////////////////////////////////

  public static void main(String[] args) {
    try {
      if ((args != null) && (args.length == 1) && ("create".equalsIgnoreCase(args[0]))) {
        new IdentitySchema(IdentitySessionFactory.createConfiguration()).createSchema();
      } else if ((args != null) && (args.length == 1) && ("drop".equalsIgnoreCase(args[0]))) {
        new IdentitySchema(IdentitySessionFactory.createConfiguration()).dropSchema();
      } else if ((args != null) && (args.length == 1) && ("clean".equalsIgnoreCase(args[0]))) {
        new IdentitySchema(IdentitySessionFactory.createConfiguration()).cleanSchema();
      } else if ((args != null) && (args.length == 3) && ("scripts".equalsIgnoreCase(args[0]))) {
        new IdentitySchema(IdentitySessionFactory.createConfiguration())
            .saveSqlScripts(args[1], args[2]);
      } else {
        System.err.println("syntax: JbpmSchema create");
        System.err.println("syntax: JbpmSchema drop");
        System.err.println("syntax: JbpmSchema clean");
        System.err.println("syntax: JbpmSchema scripts <dir> <prefix>");
      }
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException(e);
    }
  }

  private void saveSqlScript(String fileName, String[] sql) throws FileNotFoundException {
    FileOutputStream fileOutputStream = new FileOutputStream(fileName);
    PrintStream printStream = new PrintStream(fileOutputStream);
    for (int i = 0; i < sql.length; i++) {
      printStream.println(sql[i] + getSqlDelimiter());
    }
  }

  // sql script execution /////////////////////////////////////////////////////

  public void execute(String[] sqls) {
    String sql = null;
    String showSqlText = properties.getProperty("hibernate.show_sql");
    boolean showSql = ("true".equalsIgnoreCase(showSqlText));

    try {
      createConnection();
      statement = connection.createStatement();

      for (int i = 0; i < sqls.length; i++) {
        sql = sqls[i];
        String delimitedSql = sql + getSqlDelimiter();

        if (showSql) log.debug(delimitedSql);
        statement.executeUpdate(delimitedSql);
      }

    } catch (SQLException e) {
      e.printStackTrace();
      throw new RuntimeException("couldn't execute sql '" + sql + "'", e);
    } finally {
      closeConnection();
    }
  }

  private void closeConnection() {
    try {
      if (statement != null) statement.close();
      if (connection != null) {
        JDBCExceptionReporter.logWarnings(connection.getWarnings());
        connection.clearWarnings();
        connectionProvider.closeConnection(connection);
        connectionProvider.close();
      }
    } catch (Exception e) {
      System.err.println("Could not close connection");
      e.printStackTrace();
    }
  }

  private void createConnection() throws SQLException {
    connectionProvider = ConnectionProviderFactory.newConnectionProvider(properties);
    connection = connectionProvider.getConnection();
    if (!connection.getAutoCommit()) {
      connection.commit();
      connection.setAutoCommit(true);
    }
  }

  public Properties getProperties() {
    return properties;
  }

  // sql delimiter ////////////////////////////////////////////////////////////

  private static String sqlDelimiter = null;

  private synchronized String getSqlDelimiter() {
    if (sqlDelimiter == null) {
      sqlDelimiter = properties.getProperty("jbpm.sql.delimiter", ";");
    }
    return sqlDelimiter;
  }

  // logger ///////////////////////////////////////////////////////////////////

  private static final Log log = LogFactory.getLog(IdentitySchema.class);
}
Example #2
0
/** @author Javier Paniza */
public abstract class ModelMapping implements java.io.Serializable {

  private static Log log = LogFactory.getLog(ModelMapping.class);

  private static boolean codeGenerationTime;
  private static boolean codeGenerationTimeObtained = false;
  private MetaComponent metaComponent;
  private String table;
  private Map propertyMappings = new HashMap();
  private Map referenceMappings;
  private Collection modelProperties = new ArrayList(); // of String
  private Collection tableColumns = new ArrayList(); // of String
  private Collection referenceMappingsWithConverter; // of ReferenceMapping
  private boolean databaseMetadataLoaded = false;
  private boolean supportsSchemasInDataManipulation = true;
  private boolean supportsYearFunction = false;
  private boolean supportsMonthFunction = false;
  private boolean supportsTranslateFunction = false;
  private boolean referencePropertyWithFormula = false;

  public abstract String getModelName() throws XavaException;

  public abstract MetaModel getMetaModel() throws XavaException;

  /** Util specially to find out the type of properties that are not in model, only in mapping. */
  public Class getType(String propertyName) throws XavaException {
    try {
      return getMetaModel().getMetaProperty(propertyName).getType();
    } catch (ElementNotFoundException ex) {
      // Try to obtain it from primary key
      if (!(getMetaModel() instanceof MetaEntity)) return java.lang.Object.class;
      throw ex;
    }
  }

  public String getTable() {
    // Change this if by polymorphism ?
    if (isCodeGenerationTime()) return table;
    if (XavaPreferences.getInstance().isJPAPersistence()
        && getSchema() == null
        && !Is.emptyString(XPersistence.getDefaultSchema())) {
      return XPersistence.getDefaultSchema() + "." + table;
    } else if (XavaPreferences.getInstance().isHibernatePersistence()
        && getSchema() == null
        && !Is.emptyString(XHibernate.getDefaultSchema())) {
      return XHibernate.getDefaultSchema() + "." + table;
    }
    return table;
  }

  private static boolean isCodeGenerationTime() {
    if (!codeGenerationTimeObtained) {
      codeGenerationTimeObtained = true;
      try {
        // Class.forName("CodeGenerator");
        ClassLoaderUtil.forName(ModelMapping.class, "CodeGenerator");
        codeGenerationTime = true;
      } catch (Exception ex) {
        codeGenerationTime = false;
      }
    }
    return codeGenerationTime;
  }

  public void setTable(String tabla) {
    this.table = tabla;
  }

  public String getSchema() {
    int idx = table.indexOf('.');
    if (idx < 0) return null;
    return table.substring(0, idx);
  }

  public String getUnqualifiedTable() {
    int idx = table.indexOf('.');
    if (idx < 0) return table;
    return table.substring(idx + 1);
  }

  public String getTableToQualifyColumn() {
    return supportsSchemasInDataManipulation() ? getTable() : getUnqualifiedTable();
  }

  public void addPropertyMapping(PropertyMapping propertyMapping) throws XavaException {
    propertyMappings.put(propertyMapping.getProperty(), propertyMapping);
    modelProperties.add(propertyMapping.getProperty());
    // To keep order
    tableColumns.add(propertyMapping.getColumn());
    if (propertyMapping.hasFormula() && !getMetaModel().isAnnotatedEJB3()) {
      propertyMapping.getMetaProperty().setReadOnly(true);
    }
  }

  public void addReferenceMapping(ReferenceMapping referenceMapping) throws XavaException {
    if (referenceMappings == null) referenceMappings = new HashMap();
    referenceMappings.put(referenceMapping.getReference(), referenceMapping);
    referenceMapping.setContainer(this);
  }

  /** @return Not null */
  public ReferenceMapping getReferenceMapping(String name)
      throws XavaException, ElementNotFoundException {

    ReferenceMapping r =
        referenceMappings == null ? null : (ReferenceMapping) referenceMappings.get(name);
    if (r == null) {
      throw new ElementNotFoundException("reference_mapping_not_found", name, getModelName());
    }
    return r;
  }

  /** @return Not null */
  public PropertyMapping getPropertyMapping(String name)
      throws XavaException, ElementNotFoundException {
    int i = name.indexOf('.');
    if (i >= 0) {
      String rName = name.substring(0, i);
      String pName = name.substring(i + 1);

      if (isReferenceNameInReferenceMappings(rName)) {
        return getReferenceMapping(rName).getReferencedMapping().getPropertyMapping(pName);
      } else {
        // by embedded references: address.city -> address_city
        return getPropertyMapping(name.replace(".", "_"));
      }
    }

    PropertyMapping p =
        propertyMappings == null ? null : (PropertyMapping) propertyMappings.get(name);
    if (p == null) {
      throw new ElementNotFoundException("property_mapping_not_found", name, getModelName());
    }
    return p;
  }

  private boolean isReferenceNameInReferenceMappings(String referenceName) {
    Collection<ReferenceMapping> col = getReferenceMappings();
    for (ReferenceMapping rm : col) if (rm.getReference().equals(referenceName)) return true;
    return false;
  }

  /**
   * In the order that they was added.
   *
   * @return Collection of <tt>String</tt>.
   */
  public Collection getModelProperties() {
    return modelProperties;
  }

  /**
   * In the order that they was added.
   *
   * @return Collection of <tt>String</tt>.
   */
  public Collection getColumns() {
    return tableColumns;
  }

  public String getKeyColumnsAsString() throws XavaException {
    StringBuffer r = new StringBuffer();
    Collection columns = new HashSet();
    for (Iterator it = getMetaModel().getAllKeyPropertiesNames().iterator(); it.hasNext(); ) {
      String pr = (String) it.next();
      String column = getColumn(pr);
      if (columns.contains(column)) continue;
      columns.add(column);
      r.append(column);
      r.append(' ');
    }
    return r.toString().trim();
  }

  private boolean supportsSchemasInDataManipulation() {
    loadDatabaseMetadata();
    return supportsSchemasInDataManipulation;
  }

  /** Wraps the column name with the SQL function for extracting the year from a date. */
  public String yearSQLFunction(String column) {
    if (supportsYearFunction()) return "year(" + column + ")";
    return "extract (year from " + column + ")";
  }

  /** Wraps the column name with the SQL function for extracting the month from a date. */
  public String monthSQLFunction(String column) {
    if (supportsMonthFunction()) return "month(" + column + ")";
    return "extract (month from " + column + ")";
  }

  /**
   * To ignore accents: just to search 'cami�n' or 'camion'
   *
   * <p>Good performance using 'translate' but is very slow when it use 'replace...'
   *
   * @since v4m6
   */
  public String translateSQLFunction(String column) {
    if (supportsTranslateFunction()) return "translate(" + column + ",'aeiouAEIOU','áéíóúÁÉÍÓÚ')";
    return "replace(replace(replace(replace(replace(replace(replace(replace(replace(replace("
        + column
        + ", 'Ú', 'U'), 'ú', 'u'), 'Ó', 'O'), 'ó', 'o'), 'Í', 'I'), "
        + "'í', 'i'), 'É', 'E'), 'é', 'e'), 'Á', 'A'), 'á', 'a')";
  }

  private boolean supportsYearFunction() {
    loadDatabaseMetadata();
    return supportsYearFunction;
  }

  private boolean supportsMonthFunction() {
    loadDatabaseMetadata();
    return supportsMonthFunction;
  }

  /** @since v4m6 */
  private boolean supportsTranslateFunction() {
    loadDatabaseMetadata();
    return supportsTranslateFunction;
  }

  private void loadDatabaseMetadata() {
    if (!databaseMetadataLoaded) {
      String componentName = "UNKNOWN";
      Connection con = null;
      try {
        componentName = getMetaComponent().getName();

        con = DataSourceConnectionProvider.getByComponent(componentName).getConnection();
        DatabaseMetaData metaData = con.getMetaData();
        supportsSchemasInDataManipulation = metaData.supportsSchemasInDataManipulation();
        Collection timeDateFunctions =
            Strings.toCollection(metaData.getTimeDateFunctions().toUpperCase());

        //
        // another solution instead of the use of 'if' would be to use a xml with
        //	the information of the functions from each BBDD
        if ("DB2 UDB for AS/400".equals(metaData.getDatabaseProductName())
            || "Oracle".equals(metaData.getDatabaseProductName())
            || "PostgresSQL".equals(metaData.getDatabaseProductName())) {
          supportsTranslateFunction = true;
        }
        if ("Oracle".equals(metaData.getDatabaseProductName())
            || "PostgreSQL".equals(metaData.getDatabaseProductName())) {
          supportsYearFunction = supportsMonthFunction = false;
        } else {
          supportsYearFunction = timeDateFunctions.contains("YEAR");
          supportsMonthFunction = timeDateFunctions.contains("MONTH");
        }
        databaseMetadataLoaded = true;
      } catch (Exception ex) {
        log.warn(XavaResources.getString("load_database_metadata_warning"));
      } finally {
        try {
          if (con != null) {
            con.close();
          }
        } catch (SQLException e) {
          log.warn(XavaResources.getString("close_connection_warning"));
        }
      }
    }
  }

  public String getQualifiedColumn(String modelProperty) throws XavaException {
    PropertyMapping propertyMapping = (PropertyMapping) propertyMappings.get(modelProperty);
    if (propertyMapping != null && propertyMapping.hasFormula()) return getColumn(modelProperty);

    String tableColumn = getTableColumn(modelProperty, true);
    if (Is.emptyString(tableColumn)) return "'" + modelProperty + "'";
    if (referencePropertyWithFormula) {
      referencePropertyWithFormula = false;
      return tableColumn;
    }
    // for calculated fields or created by multiple converter

    if (modelProperty.indexOf('.') >= 0) {
      if (tableColumn.indexOf('.') < 0) return tableColumn;
      String reference = modelProperty.substring(0, modelProperty.lastIndexOf('.'));
      if (tableColumn.startsWith(getTableToQualifyColumn() + ".")) {
        String member = modelProperty.substring(modelProperty.lastIndexOf('.') + 1);
        if (getMetaModel().getMetaReference(reference).getMetaModelReferenced().isKey(member))
          return tableColumn;
      }

      // The next code uses the alias of the table instead of its name. In order to
      // support multiple references to the same model
      if (reference.indexOf('.') >= 0) {
        if (getMetaModel().getMetaProperty(modelProperty).isKey()) {
          reference = reference.substring(0, reference.lastIndexOf('.'));
        }
        reference = reference.replaceAll("\\.", "_");
      }
      return "T_" + reference + tableColumn.substring(tableColumn.lastIndexOf('.'));
    } else {
      return getTableToQualifyColumn() + "." + tableColumn;
    }
  }

  /** Support the use of references with dots, this is: myreference.myproperty. */
  public String getColumn(String modelProperty) throws ElementNotFoundException, XavaException {
    return getTableColumn(modelProperty, false);
  }

  private String getTableColumn(String modelProperty, boolean qualifyReferenceMappingColumn)
      throws XavaException {

    PropertyMapping propertyMapping = (PropertyMapping) propertyMappings.get(modelProperty);
    if (propertyMapping == null) {
      int idx = modelProperty.indexOf('.');
      if (idx >= 0) {
        String referenceName = modelProperty.substring(0, idx);
        String propertyName = modelProperty.substring(idx + 1);
        if (getMetaModel().getMetaReference(referenceName).isAggregate()
            && !Strings.firstUpper(referenceName).equals(getMetaModel().getContainerModelName())) {
          propertyMapping =
              (PropertyMapping) propertyMappings.get(referenceName + "_" + propertyName);
          if (propertyMapping == null) {
            int idx2 = propertyName.indexOf('.');
            if (idx2 >= 0) {
              String referenceName2 = propertyName.substring(0, idx2);
              String propertyName2 = propertyName.substring(idx2 + 1);
              return getTableColumn(
                  referenceName + "_" + referenceName2 + "." + propertyName2,
                  qualifyReferenceMappingColumn);
            } else {
              throw new ElementNotFoundException(
                  "property_mapping_not_found", referenceName + "_" + propertyName, getModelName());
            }
          }
          return propertyMapping.getColumn();
        }
        ReferenceMapping referenceMapping = getReferenceMapping(referenceName);

        if (referenceMapping.hasColumnForReferencedModelProperty(propertyName)) {
          if (qualifyReferenceMappingColumn) {
            return getTableToQualifyColumn()
                + "."
                + referenceMapping.getColumnForReferencedModelProperty(propertyName);
          } else {
            return referenceMapping.getColumnForReferencedModelProperty(propertyName);
          }
        } else {
          ModelMapping referencedMapping = referenceMapping.getReferencedMapping();

          String tableName = referencedMapping.getTableToQualifyColumn();
          boolean secondLevel = propertyName.indexOf('.') >= 0;
          String columnName = referencedMapping.getTableColumn(propertyName, secondLevel);
          boolean hasFormula = referencedMapping.getPropertyMapping(propertyName).hasFormula();

          if (qualifyReferenceMappingColumn && !secondLevel && !hasFormula) {
            return tableName + "." + columnName;
          } else if (hasFormula) {
            String formula = referencedMapping.getPropertyMapping(propertyName).getFormula();
            referencePropertyWithFormula = true;
            return qualifyFormulaWithReferenceName(
                formula, referencedMapping.getModelName(), modelProperty);
          } else {
            return columnName;
          }
        }
      }
      throw new ElementNotFoundException(
          "property_mapping_not_found", modelProperty, getModelName());
    }
    if (propertyMapping.hasFormula()) return propertyMapping.getFormula();
    return propertyMapping.getColumn();
  }

  /**
   * @exception ElementNotFoundException If property does not exist.
   * @exception XavaException Any problem
   * @return nulo If property exists but it does not have converter.
   */
  public IConverter getConverter(String modelProperty)
      throws ElementNotFoundException, XavaException {
    return getPropertyMapping(modelProperty).getConverter();
  }

  /**
   * @exception ElementNotFoundException If property does not exist.
   * @exception XavaException Any problem
   * @return nulo If property exists but it does not have converter.
   */
  public IMultipleConverter getMultipleConverter(String modelProperty)
      throws ElementNotFoundException, XavaException {
    return getPropertyMapping(modelProperty).getMultipleConverter();
  }

  /** If the property exists and has converter. */
  public boolean hasConverter(String propertyName) {
    try {
      return getPropertyMapping(propertyName).hasConverter();
    } catch (XavaException ex) {
      return false;
    }
  }

  public MetaComponent getMetaComponent() {
    return metaComponent;
  }

  public void setMetaComponent(MetaComponent componente) throws XavaException {
    this.metaComponent = componente;
    setupDefaultConverters();
  }

  /**
   * Change the properties inside ${ } by the database qualified(schema + table) columns. Also if
   * the property inside ${ } is a model name it changes by the table name
   *
   * <p>For example, it would change:
   *
   * <pre>
   * select ${number}, ${name} from ${Tercero}
   * </pre>
   *
   * by
   *
   * <pre>
   * select G4GENBD.GENTGER.TGRCOD, G4GENBD.GENTGER.TGRDEN from G4GENBD.GENTGER
   * </pre>
   */
  public String changePropertiesByColumns(String source) throws XavaException {
    return changePropertiesByColumns(source, true);
  }

  /**
   * Change the properties inside ${ } by the database columns without table and schema as prefix.
   * Also if the property inside ${ } is a model name it changes by the table name.
   *
   * <p>For example, it would change:
   *
   * <pre>
   * select ${number}, ${name} from ${Tercero}
   * </pre>
   *
   * by
   *
   * <pre>
   * select TGRCOD, TGRDEN
   * from G4GENBD.GENTGER
   * </pre>
   */
  public String changePropertiesByNotQualifiedColumns(String source) throws XavaException {
    return changePropertiesByColumns(source, false);
  }

  private String changePropertiesByColumns(String source, boolean qualified) throws XavaException {
    StringBuffer r = new StringBuffer(source);
    int i = r.toString().indexOf("${");
    int f = 0;
    while (i >= 0) {
      f = r.toString().indexOf("}", i + 2);
      if (f < 0) break;
      String property = r.substring(i + 2, f);
      String column = "0"; // thus it remained if it is calculated
      if (!getMetaModel().isCalculated(property)) {
        column =
            Strings.isModelName(property)
                ? getTable(property)
                : qualified ? getQualifiedColumn(property) : getColumn(property);
      }
      r.replace(i, f + 1, column);
      i = r.toString().indexOf("${");
    }
    return r.toString();
  }

  /** @since 4.1 */
  private String getTable(String name) {
    return MetaComponent.get(name).getEntityMapping().getTable();
  }

  public String changePropertiesByCMPAttributes(String source) throws XavaException {
    StringBuffer r = new StringBuffer(source);
    int i = r.toString().indexOf("${");
    int f = 0;
    while (i >= 0) {
      f = r.toString().indexOf("}", i + 2);
      if (f < 0) break;
      String property = r.substring(i + 2, f);
      String cmpAttribute = null;
      if (property.indexOf('.') >= 0) {
        cmpAttribute = "o._" + Strings.firstUpper(Strings.change(property, ".", "_"));
      } else {
        MetaProperty metaProperty = getMetaModel().getMetaProperty(property);
        if (metaProperty.getMapping().hasConverter()) {
          cmpAttribute = "o._" + Strings.firstUpper(property);
        } else {
          cmpAttribute = "o." + property;
        }
      }
      r.replace(i, f + 1, cmpAttribute);
      i = r.toString().indexOf("${");
    }
    return r.toString();
  }

  public boolean hasPropertyMapping(String memberName) {
    return propertyMappings.containsKey(memberName);
  }

  private void setupDefaultConverters() throws XavaException {
    Iterator it = propertyMappings.values().iterator();
    while (it.hasNext()) {
      PropertyMapping propertyMapping = (PropertyMapping) it.next();
      propertyMapping.setDefaultConverter();
    }
  }

  public boolean hasReferenceMapping(MetaReference metaReference) {
    if (referenceMappings == null) return false;
    return referenceMappings.containsKey(metaReference.getName());
  }

  public boolean isReferenceOverlappingWithSomeProperty(
      String reference, String propertiesOfReference) throws XavaException {
    String column =
        getReferenceMapping(reference).getColumnForReferencedModelProperty(propertiesOfReference);
    return containsColumn(getColumns(), column);
  }

  public boolean isReferenceOverlappingWithSomeProperty(String reference) throws XavaException {
    Iterator it = getReferenceMapping(reference).getDetails().iterator();
    while (it.hasNext()) {
      ReferenceMappingDetail d = (ReferenceMappingDetail) it.next();
      if (containsColumn(getColumns(), d.getColumn())) {
        String property = getMappingForColumn(d.getColumn()).getProperty();
        if (!property.startsWith(reference + "_")) {
          return true;
        }
      }
    }
    return false;
  }

  public boolean isReferencePropertyOverlappingWithSomeProperty(String qualifiedProperty)
      throws XavaException {
    int idx = qualifiedProperty.indexOf('.');
    if (idx < 0) return false;
    String ref = qualifiedProperty.substring(0, idx);
    String pr = qualifiedProperty.substring(idx + 1);
    return isReferenceOverlappingWithSomeProperty(ref, pr);
  }

  /** @throws XavaException If it does not have a overlapped property, or any other problem. */
  public String getOverlappingPropertyForReference(String reference, String propertyOfReference)
      throws XavaException {
    String column =
        getReferenceMapping(reference).getColumnForReferencedModelProperty(propertyOfReference);
    if (propertyMappings == null) {
      throw new XavaException("reference_property_not_overlapped", propertyOfReference, reference);
    }
    Iterator it = propertyMappings.values().iterator();
    while (it.hasNext()) {
      PropertyMapping mapping = (PropertyMapping) it.next();
      if (column.equalsIgnoreCase(mapping.getColumn())) return mapping.getProperty();
    }
    throw new XavaException("reference_property_not_overlapped", propertyOfReference, reference);
  }

  /** @return Of <tt>String</tt> and not null. */
  public Collection getOverlappingPropertiesOfReference(String reference) throws XavaException {
    Collection overlappingPropertiesOfReference = new ArrayList();
    Iterator it = getReferenceMapping(reference).getDetails().iterator();
    while (it.hasNext()) {
      ReferenceMappingDetail d = (ReferenceMappingDetail) it.next();
      if (containsColumn(getColumns(), d.getColumn())) {
        String property = getMappingForColumn(d.getColumn()).getProperty();
        if (!property.startsWith(reference + "_")) {
          overlappingPropertiesOfReference.add(d.getReferencedModelProperty());
        }
      }
    }
    return overlappingPropertiesOfReference;
  }

  private boolean containsColumn(Collection columns, String column) {
    if (columns.contains(column)) return true;
    for (Iterator it = columns.iterator(); it.hasNext(); ) {
      if (((String) it.next()).equalsIgnoreCase(column)) return true;
    }
    return false;
  }

  private PropertyMapping getMappingForColumn(String column) throws XavaException {
    if (propertyMappings == null) {
      throw new ElementNotFoundException("mapping_not_found_no_property_mappings", column);
    }
    Iterator it = propertyMappings.values().iterator();
    while (it.hasNext()) {
      PropertyMapping propertyMapping = (PropertyMapping) it.next();
      if (propertyMapping.getColumn().equalsIgnoreCase(column)) {
        return propertyMapping;
      }
    }
    throw new ElementNotFoundException("mapping_for_column_not_found", column);
  }

  String getCMPAttributeForColumn(String column) throws XavaException {
    PropertyMapping mapping = getMappingForColumn(column);
    if (!mapping.hasConverter()) return Strings.change(mapping.getProperty(), ".", "_");
    return "_" + Strings.change(Strings.firstUpper(mapping.getProperty()), ".", "_");
  }

  private Collection getPropertyMappings() {
    return propertyMappings.values();
  }

  public Collection getPropertyMappingsNotInModel() throws XavaException {
    Collection names = new ArrayList(getModelProperties());
    names.removeAll(getMetaModel().getPropertiesNames());
    if (names.isEmpty()) return Collections.EMPTY_LIST;
    Collection result = new ArrayList();
    for (Iterator it = names.iterator(); it.hasNext(); ) {
      String name = (String) it.next();
      if (name.indexOf('_') < 0) {
        result.add(getPropertyMapping(name));
      }
    }
    return result;
  }

  private Collection getReferenceMappings() {
    return referenceMappings == null ? Collections.EMPTY_LIST : referenceMappings.values();
  }

  public Collection getCmpFields() throws XavaException {
    Collection r = new ArrayList();
    Collection mappedColumns = new HashSet();
    for (Iterator it = getPropertyMappings().iterator(); it.hasNext(); ) {
      PropertyMapping pMapping = (PropertyMapping) it.next();
      r.addAll(pMapping.getCmpFields());
      mappedColumns.add(pMapping.getColumn());
    }
    for (Iterator it = getReferenceMappings().iterator(); it.hasNext(); ) {
      ReferenceMapping rMapping = (ReferenceMapping) it.next();
      for (Iterator itFields = rMapping.getCmpFields().iterator(); itFields.hasNext(); ) {
        CmpField field = (CmpField) itFields.next();
        if (!mappedColumns.contains(field.getColumn())) {
          r.add(field);
          mappedColumns.add(field.getColumn());
        }
      }
    }

    return r;
  }

  public boolean hasReferenceConverters() {
    return !getReferenceMappingsWithConverter().isEmpty();
  }

  public Collection getReferenceMappingsWithConverter() {
    if (referenceMappingsWithConverter == null) {
      referenceMappingsWithConverter = new ArrayList();
      Iterator it = getReferenceMappings().iterator();
      while (it.hasNext()) {
        ReferenceMapping referenceMapping = (ReferenceMapping) it.next();
        Collection mrd = referenceMapping.getDetails();
        Iterator itd = mrd.iterator();
        while (itd.hasNext()) {
          ReferenceMappingDetail referenceMappingDetail = (ReferenceMappingDetail) itd.next();
          if (referenceMappingDetail.hasConverter()) {
            referenceMappingsWithConverter.add(referenceMapping);
          }
        }
      }
    }
    return referenceMappingsWithConverter;
  }

  /**
   * Find the columns name in the formula and replace its by qualify columns name: 'name' ->
   * 't_reference.name'
   */
  private String qualifyFormulaWithReferenceName(
      String formula, String referenceName, String modelProperty) {
    EntityMapping em = MetaComponent.get(referenceName).getEntityMapping();

    Iterator<String> it = em.getColumns().iterator();
    while (it.hasNext()) {
      String column = it.next();
      if (formula.contains(column)) {
        formula =
            formula.replace(
                column, getQualifyColumnName(modelProperty, referenceName + "." + column));
      }
    }

    return formula;
  }

  private String getQualifyColumnName(String modelProperty, String tableColumn) {
    if (modelProperty.indexOf('.') >= 0) {
      if (tableColumn.indexOf('.') < 0) return tableColumn;
      String reference = modelProperty.substring(0, modelProperty.lastIndexOf('.'));
      if (tableColumn.startsWith(getTableToQualifyColumn() + ".")) {
        String member = modelProperty.substring(modelProperty.lastIndexOf('.') + 1);
        if (getMetaModel().getMetaReference(reference).getMetaModelReferenced().isKey(member))
          return tableColumn;
      }

      // The next code uses the alias of the table instead of its name. In order to
      // support multiple references to the same model
      if (reference.indexOf('.') >= 0) {
        if (getMetaModel().getMetaProperty(modelProperty).isKey()) {
          reference = reference.substring(0, reference.lastIndexOf('.'));
        }
        reference = reference.substring(reference.lastIndexOf('.') + 1);
      }
      return "T_" + reference + tableColumn.substring(tableColumn.lastIndexOf('.'));
    } else {
      return getTableToQualifyColumn() + "." + tableColumn;
    }
  }
}
/**
 * 領域マスタデータアクセスクラス。 ID RCSfile="$RCSfile: MasterRyouikiInfoDao.java,v $" Revision="$Revision: 1.1 $"
 * Date="$Date: 2007/06/28 02:06:50 $"
 */
public class MasterRyouikiInfoDao {

  // ---------------------------------------------------------------------
  // Static data
  // ---------------------------------------------------------------------

  /** ログ */
  protected static final Log log = LogFactory.getLog(MasterRyouikiInfoDao.class);

  // ---------------------------------------------------------------------
  // Instance data
  // ---------------------------------------------------------------------

  /** 実行するユーザ情報 */
  private UserInfo userInfo = null;

  // ---------------------------------------------------------------------
  // Constructors
  // ---------------------------------------------------------------------

  /**
   * コンストラクタ。
   *
   * @param userInfo 実行するユーザ情報
   */
  public MasterRyouikiInfoDao(UserInfo userInfo) {
    this.userInfo = userInfo;
  }

  // ---------------------------------------------------------------------
  // Public Methods
  // ---------------------------------------------------------------------

  /**
   * 領域の一覧(コンポボックス用)を取得する。
   *
   * @param connection コネクション
   * @return 事業情報
   * @throws ApplicationException
   */
  public static List selectRyouikiKubunInfoList(Connection connection)
      throws ApplicationException, NoDataFoundException {

    // -----------------------
    // SQL文の作成
    // -----------------------
    String select =
        "SELECT"
            + " A.RYOIKI_NO"
            + ",A.RYOIKI_RYAKU"
            + " FROM MASTER_RYOIKI A"
            + " ORDER BY RYOIKI_NO";
    StringBuffer query = new StringBuffer(select);

    if (log.isDebugEnabled()) {
      log.debug("query:" + query);
    }

    // -----------------------
    // リスト取得
    // -----------------------
    try {
      return SelectUtil.select(connection, query.toString());
    } catch (DataAccessException e) {
      throw new ApplicationException("領域情報検索中にDBエラーが発生しました。", new ErrorInfo("errors.4004"), e);
    } catch (NoDataFoundException e) {
      throw new NoDataFoundException("領域マスタに1件もデータがありません。", e);
    }
  }

  /**
   * 領域マスタの1レコードをMap形式で返す。 引数には主キー値を渡す。
   *
   * @param connection
   * @param labelKubun
   * @param value
   * @return
   * @throws NoDataFoundException
   * @throws DataAccessException
   */
  public static Map selectRecord(Connection connection, String ryouikiNo)
      throws NoDataFoundException, DataAccessException {
    // -----------------------
    // SQL文の作成
    // -----------------------
    String select =
        "SELECT"
            + " A.RYOIKI_NO"
            + ",A.RYOIKI_RYAKU"
            + ",A.KOMOKU_NO"
            // 2006/06/26 苗 修正ここから
            + ",A.SETTEI_KIKAN" // 設定期間
            + ",A.SETTEI_KIKAN_KAISHI" // 設定期間(開始年度)
            + ",A.SETTEI_KIKAN_SHURYO" // 設定期間(終了年度)
            // 2006/06/26 苗 修正ここまで
            + ",A.BIKO"
            + " FROM MASTER_RYOIKI A"
            + " WHERE RYOIKI_NO = ? ";

    if (log.isDebugEnabled()) {
      log.debug("query:" + select);
    }

    // -----------------------
    // レコード取得
    // -----------------------
    List result = SelectUtil.select(connection, select, new String[] {ryouikiNo});
    if (result.isEmpty()) {
      throw new NoDataFoundException("当該レコードは存在しません。領域No=" + ryouikiNo);
    }
    return (Map) result.get(0);
  }

  /**
   * 領域マスタの1レコードをMap形式で返す。 引数には主キー値を渡す。
   *
   * @param connection
   * @param labelKubun
   * @param value
   * @return
   * @throws NoDataFoundException
   * @throws DataAccessException
   */
  public static Map selectRecord(Connection connection, RyouikiInfoPk pkInfo)
      throws NoDataFoundException, DataAccessException {
    return selectRecord(connection, pkInfo, "0");
  }

  /**
   * 領域マスタの1レコードをMap形式で返す。 引数には主キー値を渡す。
   *
   * @param connection
   * @param labelKubun
   * @param value
   * @return
   * @throws NoDataFoundException
   * @throws DataAccessException
   */
  public static Map selectRecord(Connection connection, RyouikiInfoPk pkInfo, String ryoikiKbn)
      throws NoDataFoundException, DataAccessException {
    // -----------------------
    // SQL文の作成
    // -----------------------
    String select =
        "SELECT"
            + " A.RYOIKI_NO"
            + ",A.RYOIKI_RYAKU"
            + ",A.KOMOKU_NO"
            // 2006/07/04 苗 修正ここから
            + ",A.SETTEI_KIKAN" // 設定期間
            + ",A.SETTEI_KIKAN_KAISHI" // 設定期間(開始年度)
            + ",A.SETTEI_KIKAN_SHURYO" // 設定期間(終了年度)
            // 2006/07/04 苗 修正ここまで
            + " FROM MASTER_RYOIKI A"
            + " WHERE RYOIKI_NO = ? "
            + " AND KOMOKU_NO = ? ";

    // 計画研究の場合
    if ("1".equals(ryoikiKbn)) {
      select = select + " AND KEIKAKU_FLG = '1'";
    }
    // 公募研究の場合
    else if ("2".equals(ryoikiKbn)) {
      select = select + " AND KOUBO_FLG = '1'";
    }

    if (log.isDebugEnabled()) {
      log.debug("query:" + select);
    }

    // -----------------------
    // レコード取得
    // -----------------------
    List result =
        SelectUtil.select(
            connection, select, new String[] {pkInfo.getRyoikiNo(), pkInfo.getKomokuNo()});
    if (result.isEmpty()) {
      throw new NoDataFoundException("当該レコードは存在しません。");
    }
    return (Map) result.get(0);
  }

  /**
   * 領域情報を登録する。
   *
   * @param connection コネクション
   * @param addInfo 登録するキーワード情報
   * @throws DataAccessException 登録中に例外が発生した場合。
   * @throws DuplicateKeyException キーに一致するデータが既に存在する場合。
   */
  public void insertRyoikiInfo(Connection connection, RyouikiInfo addInfo)
      throws DataAccessException, DuplicateKeyException {
    // 重複チェック
    try {
      selectRecord(connection, addInfo);
      // NG
      throw new DuplicateKeyException("'" + addInfo + "'は既に登録されています。");
    } catch (NoDataFoundException e) {
      // OK
    }

    String query =
        "INSERT INTO MASTER_RYOIKI "
            + "("
            + " RYOIKI_NO" // 領域番号
            + ",RYOIKI_RYAKU" // 領域略称名
            + ",KOMOKU_NO" // 研究項目番号
            + ",KOUBO_FLG" // 公募フラグ
            + ",KEIKAKU_FLG" // 計画研究フラグ
            // add start liuyi 2006/06/30
            + ",ZENNENDO_OUBO_FLG" // 前年度応募フラグ
            + ",SETTEI_KIKAN_KAISHI" // 設定期間(開始年度)
            + ",SETTEI_KIKAN_SHURYO" // 設定期間(終了年度)
            + ",SETTEI_KIKAN" // 設定期間
            // add end liuyi 2006/06/30
            + ",BIKO" // 備考
            + ")"
            + "VALUES "
            + "(?,?,?,?,?,?,?,?,?,?)";
    PreparedStatement preparedStatement = null;
    try {
      // 登録
      preparedStatement = connection.prepareStatement(query);
      int i = 1;
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getRyoikiNo());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getRyoikiName());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getKomokuNo());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getKobou());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getKeikaku());
      // add start liuyi 2006/06/30
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getZennendoOuboFlg());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getSettelKikanKaishi());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getSettelKikanShuryo());
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getSettelKikan());
      // add end liuyi 2006/06/30
      DatabaseUtil.setParameter(preparedStatement, i++, addInfo.getBiko());

      DatabaseUtil.executeUpdate(preparedStatement);
    } catch (SQLException ex) {
      log.error("領域マスタ情報登録中に例外が発生しました。 ", ex);
      throw new DataAccessException("領域マスタ情報登録中に例外が発生しました。 ", ex);
    } finally {
      DatabaseUtil.closeResource(null, preparedStatement);
    }
  }

  /**
   * コード一覧作成用メソッド。<br>
   * 領域番号と領域名称の一覧を取得する。 領域番号順にソートする。
   *
   * @param connection コネクション
   * @return
   * @throws ApplicationException
   */
  public static List selectRyoikiInfoList(Connection connection, String kubun)
      throws ApplicationException {

    // -----------------------
    // SQL文の作成
    // -----------------------
    String select =
        "SELECT"
            + " RYOIKI_NO," // 領域番号
            + " RYOIKI_RYAKU" // 領域名称
            + " FROM MASTER_RYOIKI";

    if ("1".equals(kubun)) {
      select = select + " WHERE KEIKAKU_FLG = '1'";
    } else {
      select = select + " WHERE KOUBO_FLG = '1'";
    }
    select = select + " GROUP BY RYOIKI_NO, RYOIKI_RYAKU" + " ORDER BY RYOIKI_NO";

    if (log.isDebugEnabled()) {
      log.debug("query:" + select);
    }

    // -----------------------
    // リスト取得
    // -----------------------
    try {
      return SelectUtil.select(connection, select);
    } catch (DataAccessException e) {
      throw new ApplicationException("領域情報検索中にDBエラーが発生しました。", new ErrorInfo("errors.4004"), e);
    } catch (NoDataFoundException e) {
      throw new SystemException("領域マスタに1件もデータがありません。", e);
    }
  }
  // 2006/06/26 苗 追加ここから
  /**
   * 領域番号の件数を取得する。 領域番号順にソートする。
   *
   * @param connection コネクション
   * @param ryoikoNo 領域番号
   * @return
   * @throws ApplicationException
   * @throws DataAccessException
   */
  public String selectRyoikiNoCount(Connection connection, String ryoikoNo)
      throws ApplicationException, DataAccessException {

    String strCount = null;
    ResultSet recordSet = null;
    PreparedStatement preparedStatement = null;

    // -----------------------
    // SQL文の作成
    // -----------------------

    StringBuffer select = new StringBuffer();
    select.append("SELECT COUNT(RYOIKI_NO) ");
    select.append(ISystemServise.STR_COUNT);
    select.append(" FROM");
    select.append(" (SELECT MR.RYOIKI_NO FROM MASTER_RYOIKI MR WHERE MR.ZENNENDO_OUBO_FLG = '1' ");
    select.append("  AND MR.RYOIKI_NO = '");
    select.append(EscapeUtil.toSqlString(ryoikoNo));
    select.append("')");

    if (log.isDebugEnabled()) {
      log.debug("query:" + select.toString());
    }
    try {
      preparedStatement = connection.prepareStatement(select.toString());
      recordSet = preparedStatement.executeQuery();

      if (recordSet.next()) {
        strCount = recordSet.getString(ISystemServise.STR_COUNT);
      } else {
        throw new NoDataFoundException("領域マスタデータテーブルに該当するデータが見つかりません。");
      }
    } catch (SQLException ex) {
      throw new DataAccessException("領域マスタデータテーブルの検索中に例外が発生しました。", ex);
    } catch (NoDataFoundException ex) {
      throw new NoDataFoundException("該当する領域番号が存在しません。", ex);
    }

    return strCount;
  }
  // 2006/06/26 苗 追加ここまで
  // 2006/07/24 苗 追加ここから
  /**
   * コード一覧(新規領域)作成用メソッド。<br>
   * 領域番号と領域名称の一覧を取得する。 領域番号順にソートする。
   *
   * @param connection コネクション
   * @return  List
   * @throws ApplicationException
   */
  public static List selectRyoikiSinnkiInfoList(Connection connection) throws ApplicationException {

    // -----------------------
    // SQL文の作成
    // -----------------------
    StringBuffer select = new StringBuffer();

    select.append("SELECT DISTINCT");
    select.append(" RYOIKI_NO,"); // 領域番号
    select.append(" RYOIKI_RYAKU,"); // 領域名称
    select.append(" SETTEI_KIKAN"); // 設定期間
    select.append(" FROM MASTER_RYOIKI");
    select.append(" WHERE ZENNENDO_OUBO_FLG = '1'");
    select.append(" ORDER BY RYOIKI_NO");

    if (log.isDebugEnabled()) {
      log.debug("query:" + select);
    }

    // -----------------------
    // リスト取得
    // -----------------------
    try {
      return SelectUtil.select(connection, select.toString());
    } catch (DataAccessException e) {
      throw new ApplicationException("領域情報検索中にDBエラーが発生しました。", new ErrorInfo("errors.4004"), e);
    } catch (NoDataFoundException e) {
      throw new SystemException("領域マスタに1件もデータがありません。", e);
    }
  }
  // 2006/07/24 苗 追加ここまで
}