Friday, June 26, 2009

Maven: Excluding a Module Artifact from the Deploy Phase

I have a multi-module Maven project where one's module purpose is to create an assembly which is of a good size. I would like the other module's artifacts be deployed to our remote repository when mvn deploy is run, but would like to avoid having the assembled artifact deployed due to its size.

You can configure the maven-deploy-plugin in the POM of a module to exclude it from the deploy:

<build>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
...
</build>
If done, correctly you should see the following after running mvn deploy in your build output:
[INFO] [deploy:deploy]
[INFO] skipping artifact deployement
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Thursday, June 18, 2009

Groovy: Base64 encode/decode with and without Commons Codec

I've been using Apache's Commons Codec to encode and decode base64 data. The Groovy code:
  import org.apache.commons.codec.binary.Base64

def data = "data"
def bytes = data.bytes

Base64 coder = new Base64()

def encodedData = coder.encode(bytes)
def decodedData = coder.decode(encodedData)

println "Original Data: $data"
println "Encoded Data: " + new String(encodedData)
println "Decoded Data: " + new String(decodedData)
Producing:
  Original Data: data
Encoded Data: ZGF0YQ==
Decoded Data: data
But Groovy makes it easy thru its additions to the JDK:
  encodedData = bytes.encodeBase64().toString()  
def decodedBytes = encodedData.decodeBase64()
decodedData = new String(decodedBytes)

println "Groovy Encoded Data: $encodedData"
println "Groovy Decoded Data: $decodedData"
Which produces:
  Groovy Encoded Data: ZGF0YQ==
Groovy Decoded Data: data
Maven coordinates for commons-codec:
  <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
Suggestions for alternative appreciated as always.

Monday, June 15, 2009

Bash: Evaluating a Command from a Variable with a Redirect

In bash, I was assigning a command I wanted to run to a variable while redirecting the output:
  command="mvn clean verify > /tmp/out"
$command
The redirect greater-than sign was being passed to the mvn command. Placing an eval in front of the mvn command does the trick:
  command="eval mvn clean verify > /tmp/out"

Thursday, June 11, 2009

DBUnit & MySQL: DataTypeFactory warning

I've been playing with DBUnit to help setup a database for my integration testing, and the experience has been very good. When my dataset was being loaded into my MySQL database, I found this warning:
    [WARN ] [org.prystasj.myproject.it.MyIntegrationTestCase.setUpDatabase] - Potential problem found: 
The configured data type factory 'class org.dbunit.dataset.datatype.DefaultDataTypeFactory'
might cause problems with the current database 'MySQL' (e.g. some datatypes may not be
supported properly).
In rare cases you might see this message because the list of supported database products is
incomplete (list=[derby]). If so please request a java-class update via the forums.
I found the following DBUnit FAQ Entry on the DBUnit website that helped me out a bunch, the code from the entry:
    IDatabaseConnection connection = new DatabaseConnection(jdbcConnection, schema);
DatabaseConfig config = connection.getConfig();
config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new OracleDataTypeFactory());
My code additions:
    // http://dbunit.sourceforge.net/faq.html#typefactory
def dbConfig = dbConnection.getConfig();
dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory()
And all my Groovy DBUnit related code:
import org.dbunit.database.DatabaseConfig
import org.dbunit.database.DatabaseConnection
import org.dbunit.dataset.xml.XmlDataSet
import org.dbunit.ext.mysql.MySqlDataTypeFactory
import org.dbunit.operation.DatabaseOperation
...

class MyIntegrationTestCase extends GroovyTestCase {

...

def setUpDatabase() {
def connection = getConnection()
def data = getDataSet()

try {
DatabaseOperation.CLEAN_INSERT.execute(connection, data)
}
finally {
connection.close()
}
}

def getConnection() {
Class.forName(jdbcDriver)
def jdbcConnection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword)
def dbConnection = new DatabaseConnection(jdbcConnection)

// http://dbunit.sourceforge.net/faq.html#typefactory
def dbConfig = dbConnection.getConfig();
dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory())

return dbConnection
}

def getDataSet() throws Exception {
def stream = getClass().getClassLoader().getResourceAsStream(DATASET)
def dataset = new XmlDataSet(stream)
return dataset
}

}

Wednesday, June 10, 2009

Groovy & MySQL: ALTER TABLE

I was having trouble executing a query similar to the following with in Groovy against a MySQL database:
    ALTER TABLE MAP AUT0_INCREMENT = 109
The code:
    import groovy.sql.Sql
...
def setAutoIncrement(table, value) {
def sql = Sql.newInstance(jdbcUrl, jdbcUsername, jdbcPassword, jdbcDriver)
def query = "ALTER TABLE $table AUTO_INCREMENT = $value"
sql.execute(query)
}
I was getting the folowing error:
    com.mysql.jdbc.exceptions.MySQLSyntaxErrorException:
You have an error in your SQL syntax; check the manual
that corresponds to your MySQL server version for the right
syntax to use near ''MAP' AUTO_INCREMENT = '109'' at line 1
Seems like Groovy was adding single quotes around the table name and the value. I resolved this by strong-typing the query variable to a String to subvert the GString interpolation:
   String query = "ALTER TABLE $table AUTO_INCREMENT = $value"
Quoting the table and value in MySQL is invalid when running the MySQL command-line tool as well.

Wednesday, May 27, 2009

JPA: Mapping Created and Updated Columns

To quickly follow up on my last post about CREATED and UPDATED columns for an entity named Map in MySQL, I thought I would add the equivalent JPA declarative ORM definition from my orm.xml:
  <entity class="Map" name="Map" access="FIELD">
<table name="MAP"/>
<attributes>
<id name="id">
<column name="ID" nullable="false"/>
<generated-value strategy="SEQUENCE"/>
</id>
<basic name="updated">
<column name="UPDATED" nullable="true"/>
<temporal>DATETIME</temporal>
</basic>
<basic name="updated">
<column name="UPDATED" nullable="true"/>
<temporal>TIMESTAMP</temporal>
</basic>
</entity>

Friday, May 8, 2009

MySQL: Adding Created and Updated Columns

I had a requirement to add a Last-Modified header to GET requests for an entity called Map in a service I was developing. I figured it would be a good idea to track that information in the MySQL database backing the service instead of in the application itself with a column named UPDATED. In other words, I wouldn't have to explicitly set andupdate the values during the lifetime of the Map.

While I was at it, I also thought it would be a good idea to add a CREATEDcolumn to track when the Map came into existence in case that information would be useful later.

At table creation time you can add the columns with the following SQL (which omits any other useful attributes or columns):

  CREATE TABLE MAP (
ID INT NOT NULL AUTO_INCREMENT,
CREATED DATETIME NOT NULL DEFAULT '1900-01-01 00:00:00',
UPDATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
);
The columns can also be added after the table has been created, assigning the defaults to each table row:
  ALTER TABLE MAP ADD CREATED DATETIME NOT NULL DEFAULT '1900-01-01 00:00:00';
ALTER TABLE MAP ADD UPDATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
Finally a trigger can be used, which can be added at anytime, to have the CREATED column be given a value on an INSERT:
  CREATE TRIGGER MAP_CREATED BEFORE INSERT ON MAP
FOR EACH ROW SET NEW.CREATED = NOW();
With the trigger, the default on the CREATED column wouldn't exactly be needed, and in fact the table could be created without it, leaving the NOT NULL clause intact.

The resulting table definition:

mysql> DESCRIBE MAP;
+---------+-----------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+---------------------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| CREATED | datetime | NO | | 1900-01-01 00:00:00 | |
| UPDATED | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+-----------+------+-----+---------------------+----------------+
3 rows in set (0.00 sec)