From: <fg...@us...> - 2007-07-12 09:30:26
|
Revision: 360 http://svn.sourceforge.net/openutils/?rev=360&view=rev Author: fgiust Date: 2007-07-12 02:30:27 -0700 (Thu, 12 Jul 2007) Log Message: ----------- [maven-release-plugin] copy for tag openutils-dbmigration-0.7.1 Added Paths: ----------- tags/openutils-dbmigration-0.7.1/ tags/openutils-dbmigration-0.7.1/pom.xml tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java Removed Paths: ------------- tags/openutils-dbmigration-0.7.1/pom.xml tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java Copied: tags/openutils-dbmigration-0.7.1 (from rev 353, trunk/openutils-dbmigration) Deleted: tags/openutils-dbmigration-0.7.1/pom.xml =================================================================== --- trunk/openutils-dbmigration/pom.xml 2007-07-03 22:04:13 UTC (rev 353) +++ tags/openutils-dbmigration-0.7.1/pom.xml 2007-07-12 09:30:27 UTC (rev 360) @@ -1,87 +0,0 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>net.sourceforge.openutils</groupId> - <artifactId>openutils</artifactId> - <version>3</version> - <relativePath>..</relativePath> - </parent> - <artifactId>openutils-dbmigration</artifactId> - <name>openutils db migration framework</name> - <version>0.8-SNAPSHOT</version> - <description /> - <dependencies> - <dependency> - <groupId>commons-lang</groupId> - <artifactId>commons-lang</artifactId> - <version>2.3</version> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>1.3</version> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-jdbc</artifactId> - <version>2.0.1</version> - <exclusions> - <exclusion> - <groupId>avalon-framework</groupId> - <artifactId>avalon-framework</artifactId> - </exclusion> - <exclusion> - <groupId>logkit</groupId> - <artifactId>logkit</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-beans</artifactId> - <version>2.0.1</version> - <exclusions> - <exclusion> - <groupId>avalon-framework</groupId> - <artifactId>avalon-framework</artifactId> - </exclusion> - <exclusion> - <groupId>logkit</groupId> - <artifactId>logkit</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-core</artifactId> - <version>2.0.1</version> - <exclusions> - <exclusion> - <groupId>avalon-framework</groupId> - <artifactId>avalon-framework</artifactId> - </exclusion> - <exclusion> - <groupId>logkit</groupId> - <artifactId>logkit</artifactId> - </exclusion> - </exclusions> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - <version>1.2</version> - </dependency> - <dependency> - <groupId>poi</groupId> - <artifactId>poi</artifactId> - <version>2.5.1-final-20040804</version> - <optional>true</optional> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.0</version> - <scope>test</scope> - </dependency> - </dependencies> -</project> \ No newline at end of file Copied: tags/openutils-dbmigration-0.7.1/pom.xml (from rev 359, trunk/openutils-dbmigration/pom.xml) =================================================================== --- tags/openutils-dbmigration-0.7.1/pom.xml (rev 0) +++ tags/openutils-dbmigration-0.7.1/pom.xml 2007-07-12 09:30:27 UTC (rev 360) @@ -0,0 +1,93 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sourceforge.openutils</groupId> + <artifactId>openutils</artifactId> + <version>3</version> + <relativePath>..</relativePath> + </parent> + <artifactId>openutils-dbmigration</artifactId> + <name>openutils db migration framework</name> + <version>0.7.1</version> + <description /> + <dependencies> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.3</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-jdbc</artifactId> + <version>2.0.1</version> + <exclusions> + <exclusion> + <groupId>avalon-framework</groupId> + <artifactId>avalon-framework</artifactId> + </exclusion> + <exclusion> + <groupId>logkit</groupId> + <artifactId>logkit</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-beans</artifactId> + <version>2.0.1</version> + <exclusions> + <exclusion> + <groupId>avalon-framework</groupId> + <artifactId>avalon-framework</artifactId> + </exclusion> + <exclusion> + <groupId>logkit</groupId> + <artifactId>logkit</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + <version>2.0.1</version> + <exclusions> + <exclusion> + <groupId>avalon-framework</groupId> + <artifactId>avalon-framework</artifactId> + </exclusion> + <exclusion> + <groupId>logkit</groupId> + <artifactId>logkit</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>poi</groupId> + <artifactId>poi</artifactId> + <version>2.5.1-final-20040804</version> + <optional>true</optional> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.0</version> + <scope>test</scope> + </dependency> + </dependencies> + + <scm> + <connection>scm:svn:https://openutils.svn.sourceforge.net/svnroot/openutils/tags/openutils-dbmigration-0.7.1</connection> + <developerConnection>scm:svn:https://openutils.svn.sourceforge.net/svnroot/openutils/tags/openutils-dbmigration-0.7.1</developerConnection> + <url>http://openutils.svn.sourceforge.net/viewcvs.cgi/openutils/tags/openutils-dbmigration-0.7.1</url> + </scm> +</project> \ No newline at end of file Deleted: tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java =================================================================== --- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/DbSetupManagerImpl.java 2007-07-03 22:04:13 UTC (rev 353) +++ tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java 2007-07-12 09:30:27 UTC (rev 360) @@ -1,203 +0,0 @@ -/* - * Copyright (c) Openmind. All rights reserved. http://www.openmindonline.it - */ -package it.openutils.migration; - -import it.openutils.migration.task.setup.DbTask; -import it.openutils.migration.task.update.DbUpdate; - -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.dao.DataAccessException; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; -import org.springframework.transaction.support.TransactionTemplate; - - -/** - * DB setup manager: handles db setup and upgrade. - * @author fgiust - * @version $Id$ - */ -public class DbSetupManagerImpl implements DbSetupManager -{ - - /** - * Logger. - */ - private static Logger log = LoggerFactory.getLogger(DbSetupManagerImpl.class); - - private List<DbTask> setupTasks; - - private List<DbUpdate> updateTasks; - - private DataSource dataSource; - - private DbVersionManager versionManager; - - private TransactionTemplate transactionTemplate; - - private boolean enabled = true; - - /** - * Sets the enabled. - * @param enabled the enabled to set - */ - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - /** - * Sets the versionManager. - * @param versionManager the versionManager to set - */ - public void setVersionManager(DbVersionManager versionManager) - { - this.versionManager = versionManager; - } - - /** - * Sets the transactionTemplate. - * @param transactionTemplate the transactionTemplate to set - */ - public void setTransactionTemplate(TransactionTemplate transactionTemplate) - { - this.transactionTemplate = transactionTemplate; - } - - /** - * Setter for <code>dataSource</code>. - * @param dataSource The dataSource to set. - */ - public void setDataSource(DataSource dataSource) - { - this.dataSource = dataSource; - } - - /** - * Sets the tasks. - * @param setupTasks the tasks to set - */ - public void setSetupTasks(List<DbTask> setupTasks) - { - this.setupTasks = setupTasks; - } - - /** - * Sets the updateTasks. - * @param updateTasks the updateTasks to set - */ - public void setUpdateTasks(List<DbUpdate> updateTasks) - { - this.updateTasks = updateTasks; - } - - /** - * @see it.openutils.dbupdate.DbSetupManager#updateDDL() - */ - public void updateDDL() - { - - if (!enabled) - { - log.info("DB migration is disabled, not running tasks."); - return; - } - - transactionTemplate.execute(new TransactionCallbackWithoutResult() - { - - @Override - protected void doInTransactionWithoutResult(TransactionStatus status) - { - if (setupTasks != null) - { - executeSetupTasks(); - } - if (updateTasks != null) - { - executeUpdateTasks(); - } - } - }); - - } - - /** - * - */ - private void executeSetupTasks() - { - log.info("Preparing db, checking {} setup tasks.", setupTasks.size()); - for (DbTask task : setupTasks) - { - log.info(task.getDescription()); - task.execute(dataSource); - } - - } - - /** - * - */ - private void executeUpdateTasks() - { - - int initialVersion = versionManager.getCurrentVersion(); - int currentVersion = initialVersion; - - Set<DbUpdate> sortedMigrations = new TreeSet<DbUpdate>(new Comparator<DbUpdate>() - { - - public int compare(DbUpdate o1, DbUpdate o2) - { - return o1.getVersion() - o2.getVersion(); - } - - }); - sortedMigrations.addAll(updateTasks); - - log.info("Found {} migrations, looking for updates to run...", updateTasks.size()); - for (DbUpdate update : sortedMigrations) - { - if (update.getVersion() > currentVersion) - { - currentVersion = update.getVersion(); - - log.info("Preparing migration to version {}. {}", update.getVersion(), update.getDescription()); - try - { - update.execute(dataSource); - } - catch (DataAccessException e) - { - log.error("\n***********\n\n\nDatabase upgrade from version " - + initialVersion - + " to version " - + currentVersion - + " FAILED!\n\n\n***********\n", e); - } - versionManager.setNewVersion(currentVersion); - } - } - if (currentVersion != initialVersion) - { - log.info("Database upgraded from version {} to version {}", initialVersion, currentVersion); - } - else - { - log.info("No Database upgrade is needed. Current version is {} ", initialVersion); - } - // org.springframework.jdbc.BadSqlGrammarException: - // java.sql.SQLException: ORA-00959: tablespace 'XDM_DATA' inesistente - - } -} Copied: tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java (from rev 357, trunk/openutils-dbmigration/src/main/java/it/openutils/migration/DbSetupManagerImpl.java) =================================================================== --- tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java (rev 0) +++ tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/DbSetupManagerImpl.java 2007-07-12 09:30:27 UTC (rev 360) @@ -0,0 +1,203 @@ +/* + * Copyright (c) Openmind. All rights reserved. http://www.openmindonline.it + */ +package it.openutils.migration; + +import it.openutils.migration.task.setup.DbTask; +import it.openutils.migration.task.update.DbUpdate; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.dao.DataAccessException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + + +/** + * DB setup manager: handles db setup and upgrade. + * @author fgiust + * @version $Id$ + */ +public class DbSetupManagerImpl implements DbSetupManager +{ + + /** + * Logger. + */ + private static Logger log = LoggerFactory.getLogger(DbSetupManagerImpl.class); + + private List<DbTask> setupTasks; + + private List<DbUpdate> updateTasks; + + private DataSource dataSource; + + private DbVersionManager versionManager; + + private TransactionTemplate transactionTemplate; + + private boolean enabled = true; + + /** + * Sets the enabled. + * @param enabled the enabled to set + */ + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + /** + * Sets the versionManager. + * @param versionManager the versionManager to set + */ + public void setVersionManager(DbVersionManager versionManager) + { + this.versionManager = versionManager; + } + + /** + * Sets the transactionTemplate. + * @param transactionTemplate the transactionTemplate to set + */ + public void setTransactionTemplate(TransactionTemplate transactionTemplate) + { + this.transactionTemplate = transactionTemplate; + } + + /** + * Setter for <code>dataSource</code>. + * @param dataSource The dataSource to set. + */ + public void setDataSource(DataSource dataSource) + { + this.dataSource = dataSource; + } + + /** + * Sets the tasks. + * @param setupTasks the tasks to set + */ + public void setSetupTasks(List<DbTask> setupTasks) + { + this.setupTasks = setupTasks; + } + + /** + * Sets the updateTasks. + * @param updateTasks the updateTasks to set + */ + public void setUpdateTasks(List<DbUpdate> updateTasks) + { + this.updateTasks = updateTasks; + } + + /** + * @see it.openutils.dbupdate.DbSetupManager#updateDDL() + */ + public void updateDDL() + { + + if (!enabled) + { + log.info("DB migration is disabled, not running tasks."); + return; + } + + transactionTemplate.execute(new TransactionCallbackWithoutResult() + { + + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) + { + if (setupTasks != null) + { + executeSetupTasks(); + } + if (updateTasks != null) + { + executeUpdateTasks(); + } + } + }); + + } + + /** + * + */ + private void executeSetupTasks() + { + log.info("Preparing db, checking {} setup tasks.", setupTasks.size()); + for (DbTask task : setupTasks) + { + log.debug(task.getDescription()); + task.execute(dataSource); + } + + } + + /** + * + */ + private void executeUpdateTasks() + { + + int initialVersion = versionManager.getCurrentVersion(); + int currentVersion = initialVersion; + + Set<DbUpdate> sortedMigrations = new TreeSet<DbUpdate>(new Comparator<DbUpdate>() + { + + public int compare(DbUpdate o1, DbUpdate o2) + { + return o1.getVersion() - o2.getVersion(); + } + + }); + sortedMigrations.addAll(updateTasks); + + log.info("Found {} migrations, looking for updates to run...", updateTasks.size()); + for (DbUpdate update : sortedMigrations) + { + if (update.getVersion() > currentVersion) + { + currentVersion = update.getVersion(); + + log.info("Preparing migration to version {}. {}", update.getVersion(), update.getDescription()); + try + { + update.execute(dataSource); + } + catch (DataAccessException e) + { + log.error("\n***********\n\n\nDatabase upgrade from version " + + initialVersion + + " to version " + + currentVersion + + " FAILED!\n\n\n***********\n", e); + } + versionManager.setNewVersion(currentVersion); + } + } + if (currentVersion != initialVersion) + { + log.info("Database upgraded from version {} to version {}", initialVersion, currentVersion); + } + else + { + log.info("No Database upgrade is needed. Current version is {} ", initialVersion); + } + // org.springframework.jdbc.BadSqlGrammarException: + // java.sql.SQLException: ORA-00959: tablespace 'XDM_DATA' inesistente + + } +} Deleted: tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java =================================================================== --- trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java 2007-07-03 22:04:13 UTC (rev 353) +++ tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java 2007-07-12 09:30:27 UTC (rev 360) @@ -1,143 +0,0 @@ -/* - * Copyright (c) Openmind. All rights reserved. http://www.openmindonline.it - */ -package it.openutils.migration.task.setup; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -import javax.sql.DataSource; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; -import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; - - -/** - * @author fgiust - * @version $Id$ - */ -public class GenericScriptBasedConditionalTask implements DbTask -{ - - /** - * Logger. - */ - private static Logger log = LoggerFactory.getLogger(GenericScriptBasedConditionalTask.class); - - /** - * Script list to execute - */ - protected List<Resource> scripts; - - private String check; - - /** - * Sets the scripts. - * @param scripts the scripts to set - */ - public void setScripts(List<Resource> scripts) - { - this.scripts = scripts; - } - - /** - * Sets the check. - * @param check the check to set - */ - public void setCheck(String check) - { - this.check = check; - } - - /** - * @param script The script resource - * @return The script name - */ - protected String objectNameFromFileName(Resource script) - { - return StringUtils.substringBeforeLast(script.getFilename(), "."); - } - - /** - * {@inheritDoc} - */ - public String getDescription() - { - if (scripts == null) - { - return "Nothing to do, no scripts configured"; - } - - StringBuffer result = new StringBuffer(); - if (!scripts.isEmpty()) - { - result.append("Checking :\n"); - for (Resource script : scripts) - { - result.append(" - " + objectNameFromFileName(script) + "\n"); - } - - } - return result.toString(); - } - - /** - * {@inheritDoc} - */ - public void execute(DataSource dataSource) - { - - SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); - - for (Resource script : scripts) - { - int result = jdbcTemplate.queryForInt(check, this.objectNameFromFileName(script)); - if (result == 0) - { - if (script == null || !script.exists()) - { - log.error("Unable to execute db task \"{}\", script \"{}\" not found.", getDescription(), script); - return; - } - - String scriptContent; - InputStream is = null; - - try - { - is = script.getInputStream(); - scriptContent = IOUtils.toString(is, "UTF8"); - } - catch (IOException e) - { - log.error( - "Unable to execute db task \"{}\", script \"{}\" can't be read.", - getDescription(), - script); - return; - } - finally - { - IOUtils.closeQuietly(is); - } - - String[] ddls = StringUtils.split(scriptContent, ";"); - - for (String ddl : ddls) - { - if (StringUtils.isNotBlank(ddl)) - { - log.debug("Executing:\n{}", ddl); - jdbcTemplate.update(ddl); - } - } - } - } - - } -} Copied: tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java (from rev 358, trunk/openutils-dbmigration/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java) =================================================================== --- tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java (rev 0) +++ tags/openutils-dbmigration-0.7.1/src/main/java/it/openutils/migration/task/setup/GenericScriptBasedConditionalTask.java 2007-07-12 09:30:27 UTC (rev 360) @@ -0,0 +1,165 @@ +/* + * Copyright (c) Openmind. All rights reserved. http://www.openmindonline.it + */ +package it.openutils.migration.task.setup; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + + +/** + * @author fgiust + * @version $Id$ + */ +public class GenericScriptBasedConditionalTask implements DbTask +{ + + /** + * Logger. + */ + private static Logger log = LoggerFactory.getLogger(GenericScriptBasedConditionalTask.class); + + /** + * Script list to execute + */ + protected List<Resource> scripts; + + /** + * Check statement. + */ + protected String check; + + /** + * Custom description. + */ + protected String description; + + /** + * Sets the scripts. + * @param scripts the scripts to set + */ + public void setScripts(List<Resource> scripts) + { + this.scripts = scripts; + } + + /** + * Sets the check. + * @param check the check to set + */ + public void setCheck(String check) + { + this.check = check; + } + + /** + * Sets the description. + * @param description the description to set + */ + public void setDescription(String description) + { + this.description = description; + } + + /** + * @param script The script resource + * @return The script name + */ + protected String objectNameFromFileName(Resource script) + { + return StringUtils.substringBeforeLast(script.getFilename(), "."); + } + + /** + * {@inheritDoc} + */ + public String getDescription() + { + if (StringUtils.isNotEmpty(description)) + { + return description; + } + + if (scripts == null) + { + return "Nothing to do, no scripts configured"; + } + + StringBuffer result = new StringBuffer(); + if (!scripts.isEmpty()) + { + result.append("Checking :\n"); + for (Resource script : scripts) + { + result.append(" - " + objectNameFromFileName(script) + "\n"); + } + + } + return result.toString(); + } + + /** + * {@inheritDoc} + */ + public void execute(DataSource dataSource) + { + + SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); + + for (Resource script : scripts) + { + int result = jdbcTemplate.queryForInt(check, this.objectNameFromFileName(script)); + if (result == 0) + { + if (script == null || !script.exists()) + { + log.error("Unable to execute db task \"{}\", script \"{}\" not found.", getDescription(), script); + return; + } + + String scriptContent; + InputStream is = null; + + try + { + is = script.getInputStream(); + scriptContent = IOUtils.toString(is, "UTF8"); + } + catch (IOException e) + { + log.error( + "Unable to execute db task \"{}\", script \"{}\" can't be read.", + getDescription(), + script); + return; + } + finally + { + IOUtils.closeQuietly(is); + } + + String[] ddls = StringUtils.split(scriptContent, ";"); + + for (String ddl : ddls) + { + if (StringUtils.isNotBlank(ddl)) + { + log.debug("Executing:\n{}", ddl); + jdbcTemplate.update(ddl); + } + } + } + } + + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |