Flex 3.5 compile error

I encountered the following flex compile-time errors (using flex sdk 3.5.x):

1046: Type was not found or was not a compile-time constant: ModelLocator.

1120: Access of undefined property be.

while trying to compile an ActionScript3 file containing:

...
private var model1:be.myPackage1.ModelLocator = 
   be.myPackage1.ModelLocator.getInstance();		
private var model2:be.myPackage2.ModelLocator = 
   be.myPackage2.ModelLocator.getInstance();
...


I had to import these classes explicitly in order to make the error go away.

...
import be.myPackage1.ModelLocator
import be.myPackage2.ModelLocator
...

The weird thing is that I copied the variable assignments from a class that does compile, even without the explicit imports.

DbUnit NoSuchColumnException using Oracle with synonym chain.

I stumbled on the is problem using DbUnit 2.4.8 and Oracle driver 11.1.0.6.0 for table names that are actually synonyms pointing to an other synonym pointing to a view in an other schema. (long story...)

WARN [2011-08-24 08:30:40] [user=] (DatabaseTableMetaData.java:getColumns:348) - No columns found for table 'XXX_TABLE' that are supported by dbunit. Will return an empty column list

org.dbunit.dataset.NoSuchColumnException: XXX_TABLE.XXX_ID -  (Non-uppercase input column: XXX_ID) in ColumnNameToIndexes cache map. Note that the map's column names are NOT case sensitive.
	at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)
	at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:89)
	at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:140)


It looks like OracleDatabaseMetaData doesn't take into account chained synonyms, even with "SYNONYM" included in the dbUnit table types config property (DatabaseConfig.PROPERTY_TABLE_TYPE).

To work around this problem, I extended the DefaultMetadataHandler to resolve the actual schema_name/table_name when needed.

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.dbunit.database.DefaultMetadataHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * Solves the problem where Dbunit throws a NoSuchColumnException because it cannot resolve the column names through
 * a chain of synonyms.
 */
public class OracleSynonymAwareMetaDataHandler extends DefaultMetadataHandler {

    public static final Logger logger = LoggerFactory.getLogger(OracleSynonymAwareMetaDataHandler.class);

    private final Map<TableInfo, TableInfo> synonymMap;
    private final SimpleJdbcOperations simpleJdbcOperations;

    private static final String SQL_SELECT_USER_SYNONYM =
            "\n with filter1 as (  " +
                    "\n select connect_by_root synonym_name root_synonym_name,  " +
                    "\n 	   connect_by_root table_owner root_table_owner,  " +
                    "\n 	   level lvl,  " +
                    "\n 	   syn.*  " +
                    "\n from user_synonyms syn  " +
                    "\n connect by synonym_name = prior table_name and (table_owner != prior table_owner)  " +
                    "\n start with synonym_name = :p_synonym_name and table_owner = :p_schema_name   " +
                    "\n ), filter2 as (  " +
                    "\n select filter1.*,  " +
                    "\n 	   max(lvl) over (PARTITION BY root_synonym_name, root_table_owner) max_lvl  " +
                    "\n from filter1  " +
                    "\n )  " +
                    "\n select table_owner,  " +
                    "\n 	   table_name  " +
                    "\n from filter2  " +
                    "\n where lvl = max_lvl  ";


    public OracleSynonymAwareMetaDataHandler(SimpleJdbcOperations simpleJdbcOperations) {
        synonymMap = new HashMap<TableInfo, TableInfo>();
        this.simpleJdbcOperations = simpleJdbcOperations;
    }

    @Override
    public ResultSet getColumns(final DatabaseMetaData databaseMetaData,
                                final String schemaName,
                                final String tableName)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.getColumns(databaseMetaData, tableInfo.getSchemaName(), 
                                tableInfo.getTableName());
    }

    @Override
    public boolean matches(ResultSet columnsResultSet,
                           String catalog,
                           String schemaName,
                           String tableName,
                           String column,
                           boolean caseSensitive)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.matches(columnsResultSet, catalog, tableInfo.getSchemaName(), 
                             tableInfo.getTableName(), column, caseSensitive);
    }

    @Override
    public ResultSet getPrimaryKeys(DatabaseMetaData metaData,
                                    String schemaName,
                                    String tableName)
            throws SQLException {

        final TableInfo tableInfo = getTableInfo(schemaName, tableName);

        return super.getPrimaryKeys(metaData, tableInfo.getSchemaName(), 
                                    tableInfo.getTableName());
    }

    /**
     * returns the ACTUAL schemaName and tableName for the provided values
     */
    private TableInfo getTableInfo(final String schemaName, final String tableName) {

        logger.debug("getTableInfo - schemaName: {}, tableName: {}", schemaName, tableName);

        TableInfo requestTableInfo = new TableInfo(schemaName, tableName);

        if (synonymMap.containsKey(requestTableInfo)) {
            return synonymMap.get(requestTableInfo);
        } else {
            TableInfo actualTableInfo = (TableInfo) DataAccessUtils.singleResult(
                simpleJdbcOperations.getNamedParameterJdbcOperations().query(
                    SQL_SELECT_USER_SYNONYM,
                    new HashMap<String, Object>() {{
                        put("p_synonym_name", tableName);
                        put("p_schema_name", schemaName);
                    }},
                    new ParameterizedRowMapper<tableinfo>() {
                        @Override
                        public TableInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
                            int ndx = 0;
                            return new TableInfo(
                                    rs.getString(++ndx)
                                    , rs.getString(++ndx)
                            );
                        }
                    }
            ));

            if (actualTableInfo == null) {
                actualTableInfo = requestTableInfo;
            }

            synonymMap.put(requestTableInfo, actualTableInfo);

            return actualTableInfo;
        }
    }


    private static class TableInfo {
        private final String schemaName;
        private final String tableName;

        private TableInfo(String schemaName, String tableName) {
            this.schemaName = schemaName;
            this.tableName = tableName;
        }

        public String getSchemaName() {
            return schemaName;
        }

        public String getTableName() {
            return tableName;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof TableInfo)) return false;

            TableInfo that = (TableInfo) o;

            return EqualsBuilder.reflectionEquals(this, that);
        }

        @Override
        public int hashCode() {
            return HashCodeBuilder.reflectionHashCode(this);
        }

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
        }
    }
}


This OracleSynonymAwareMetaDataHandler class can be configured into dbUnit using the DatabaseConfig.PROPERTY_METADATA_HANDLER config property.

iDatabaseConnection.getConfig()
    .setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, 
        oracleSynonymAwareMetaDataHandlerInstance );




The hierarchical (oracle) query I wrote is a bit tricky, but it returns the 'deepest' synonym on the fly. The same result could be achieved by recursively retrieving a single synonym at a time until no result is found.

with filter1 as (
select connect_by_root synonym_name root_synonym_name,
	   connect_by_root table_owner root_table_owner,
	   level lvl,	   	    
	   syn.*	     
from user_synonyms syn
connect by synonym_name = prior table_name and (table_owner != prior table_owner)
start with synonym_name = :p_synonym_name and table_owner = :p_schema_name 
), filter2 as (
select filter1.*,
	   max(lvl) over (PARTITION BY root_synonym_name, root_table_owner) max_lvl
from filter1
)
select table_owner,
	   table_name
from filter2
where lvl = max_lvl

Installing eclipse 3.7 (indigo) on Ubuntu

Installing an alternative eclipse as the one provided through the software center is not that difficult.

Go the the eclipse download page, and download the package that suits you most. I went for the 64 bit JEE version: eclipse-jee-indigo-linux-gtk-x86_64.tar.gz.

Next, open a terminal and execute the folowing commands:

tar zxfv eclipse-jee-indigo-linux-gtk-x86_64.tar.gz

mv eclipse eclipse-3.7

sudo mv eclipse-3.7 /opt

cd /opt

sudo chown -R root:root eclipse-3.7

sudo ln -s /opt/eclipse-3.7/eclipse /usr/bin/eclipse

The same procedure works for other versions as well.

Maven archetype-plugin

I wanted to try-out Maven 3 and Appfuse 2.1 today. Unfortunatly, I lost some time due to a problem with the Archetype-plugin, and me being behind proxy.

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-spring-archetype -DarchetypeVersion=2.1.0-M2-SNAPSHOT -DgroupId=be.fatsu -DartifactId=test1 -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse


as generated by the appfuse quickstart page fails with TransferFailedException: Error transferring file.

The Archetype plugin apparently doesn't take into account the proxy configuration from the maven settings, as explained in the related issue: ARCHETYPE-202.

The easiest way around this is by setting system variables:

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes -DarchetypeArtifactId=appfuse-modular-spring-archetype -DarchetypeVersion=2.1.0-M2-SNAPSHOT -DgroupId=be.fatsu -DartifactId=test1 -DarchetypeRepository=http://oss.sonatype.org/content/repositories/appfuse -Dhttp.proxyHost=xxx.xxx.xxx.xxx -Dhttp.proxyPort=xxxx -Dhttp.proxyUser=xxxxxxx -Dhttp.proxyPassword=xxxxxxx

Specific Cobertura version in Maven-cobertura-plugin

I found this blog post by Brian Fox explaining how to override a plugin's dependencies.
This allowed me to configure the maven-cobertura-plugin to use a specific cobertura version (1.9.1.1 being the latest one available in the central maven repository), instead of the one configured by the plugin itself (1.9).
As stated by Brian, as long as the newly introduced version's API is compatible with the original one, there should be no problem.

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>net.sourceforge.cobertura</groupId>
<artifactId>cobertura</artifactId>
<version>1.9.1.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
</plugins>
</reporting>

Maven: Spring-Test 2.5.x & JUnit 4

I ran into this weird problem today while setting up an integration-testing module in my maven project: The Surefire-plugin seemed to ignore the JUnit4 annotations.
I found a Maven-Surefire issue (SUREFIRE-448) describing the same problem, but it is marked as irreproducible and proposes no solution.
After looking into the debug information (mvn clean test -X > log.txt), it turns out that Spring-Test has a dependency on JUnit 3.8.1, and this is causing my test classes to run as JUnit3 instead of JUnit4.
To fix this, simply exclude JUnit from the Spring-Test dependency:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>2.5.6</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>

initializing static final Collection/Map in one statement

Initializing a static final (unmodifiable) Map:

private final static Map<String,String> map = Collections.unmodifiableMap(new HashMap<String,String>() {
{
put("key1", "value1");
put("key2", "value2");
}
});



Initializing a static final (unmodifiable) Collection:

private final static Set<String> set = Collections.unmodifiableSet(new HashSet<String>() {
{
add("value1");
add("value2");
}
});