killbill-aplcache
Changes
beatrix/pom.xml 2(+1 -1)
Details
beatrix/pom.xml 2(+1 -1)
diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 64a7b38..654c129 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -120,7 +120,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
- <groups>fast,slow</groups>
+ <groups>fast,slow, stress</groups>
</configuration>
</plugin>
<plugin>
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
index cdd7464..45c58d8 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
@@ -266,7 +266,7 @@ public class TestBasic {
Thread.sleep(600000);
}
- @Test(groups = "stress", enabled = false)
+ @Test(groups = "stress", enabled = true)
public void stressTest() throws Exception {
final int maxIterations = 7;
for (int curIteration = 0; curIteration < maxIterations; curIteration++) {
diff --git a/util/src/main/java/com/ning/billing/util/validation/ColumnInfo.java b/util/src/main/java/com/ning/billing/util/validation/ColumnInfo.java
new file mode 100644
index 0000000..31d8bf0
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/validation/ColumnInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.validation;
+
+public class ColumnInfo {
+ private final String tableName;
+ private final String columnName;
+ private final int scale;
+ private final int precision;
+ private final boolean isNullable;
+
+ public ColumnInfo(String tableName, String columnName, int scale, int precision, boolean nullable) {
+ this.tableName = tableName;
+ this.columnName = columnName;
+ this.scale = scale;
+ this.precision = precision;
+ isNullable = nullable;
+ }
+
+ public String getTableName() {
+ return tableName;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+
+ public int getScale() {
+ return scale;
+ }
+
+ public int getPrecision() {
+ return precision;
+ }
+
+ public boolean getIsNullable() {
+ return isNullable;
+ }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaDao.java b/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaDao.java
new file mode 100644
index 0000000..c5f88e3
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaDao.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.validation.dao;
+
+import com.google.inject.Inject;
+import com.ning.billing.util.validation.ColumnInfo;
+import org.skife.jdbi.v2.IDBI;
+
+import java.util.List;
+
+public class DatabaseSchemaDao {
+ private final DatabaseSchemaSqlDao dao;
+
+ @Inject
+ public DatabaseSchemaDao(IDBI dbi) {
+ this.dao = dbi.onDemand(DatabaseSchemaSqlDao.class);
+ }
+
+ public List<ColumnInfo> getColumnInfoList(final String schemaName) {
+ return dao.getSchemaInfo(schemaName);
+ }
+}
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.java b/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.java
new file mode 100644
index 0000000..250ecce
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.validation.dao;
+
+import com.ning.billing.util.validation.ColumnInfo;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+@ExternalizedSqlViaStringTemplate3
+@RegisterMapper(DatabaseSchemaSqlDao.ColumnInfoMapper.class)
+public interface DatabaseSchemaSqlDao {
+ @SqlQuery
+ List<ColumnInfo> getSchemaInfo(@Bind("schemaName") final String schemaName);
+
+ class ColumnInfoMapper implements ResultSetMapper<ColumnInfo> {
+ @Override
+ public ColumnInfo map(int index, ResultSet r, StatementContext ctx) throws SQLException {
+ final String tableName = r.getString("table_name");
+ final String columnName = r.getString("column_name");
+ final Integer scale = r.getInt("numeric_scale");
+ final Integer precision = r.getInt("numeric_precision");
+ final boolean isNullable = r.getBoolean("is_nullable");
+
+ return new ColumnInfo(tableName, columnName, scale, precision, isNullable);
+ }
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/validation/ValidationConfiguration.java b/util/src/main/java/com/ning/billing/util/validation/ValidationConfiguration.java
new file mode 100644
index 0000000..7d0d926
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/validation/ValidationConfiguration.java
@@ -0,0 +1,14 @@
+package com.ning.billing.util.validation;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ValidationConfiguration extends HashMap<String, ColumnInfo> {
+ public void addMapping(String propertyName, ColumnInfo columnInfo) {
+ super.put(propertyName, columnInfo);
+ }
+
+ public boolean hasMapping(String propertyName) {
+ return super.get(propertyName) != null;
+ }
+}
diff --git a/util/src/main/java/com/ning/billing/util/validation/ValidationManager.java b/util/src/main/java/com/ning/billing/util/validation/ValidationManager.java
new file mode 100644
index 0000000..4bd8e8e
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/validation/ValidationManager.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.validation;
+
+import com.google.inject.Inject;
+import com.ning.billing.util.validation.dao.DatabaseSchemaDao;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ValidationManager {
+ private final DatabaseSchemaDao dao;
+
+ // table name, string name, column info
+ private final Map<String, Map<String, ColumnInfo>> columnInfoMap = new HashMap<String, Map<String, ColumnInfo>>();
+ private final Map<Class, ValidationConfiguration> configurations = new HashMap<Class, ValidationConfiguration>();
+
+ @Inject
+ public ValidationManager(DatabaseSchemaDao dao) {
+ this.dao = dao;
+ }
+
+ // replaces existing schema information with the information for the specified schema
+ public void loadSchemaInformation(final String schemaName) {
+ columnInfoMap.clear();
+
+ // get schema information and map it to columnInfo
+ List<ColumnInfo> columnInfoList = dao.getColumnInfoList(schemaName);
+ for (ColumnInfo columnInfo : columnInfoList) {
+ final String tableName = columnInfo.getTableName();
+
+ if (!columnInfoMap.containsKey(tableName)) {
+ columnInfoMap.put(tableName, new HashMap<String, ColumnInfo>());
+ }
+
+ columnInfoMap.get(tableName).put(columnInfo.getColumnName(), columnInfo);
+ }
+ }
+
+ public Collection<ColumnInfo> getTableInfo(final String tableName) {
+ return columnInfoMap.get(tableName).values();
+ }
+
+ public ColumnInfo getColumnInfo(final String tableName, final String columnName) {
+ return (columnInfoMap.get(tableName) == null) ? null : columnInfoMap.get(tableName).get(columnName);
+ }
+
+ public boolean validate(Object o) {
+ ValidationConfiguration configuration = getConfiguration(o.getClass());
+
+ // if no configuration exists for this class, the object is valid
+ if (configuration == null) {return true;}
+
+ Class clazz = o.getClass();
+ for (String propertyName : configuration.keySet()) {
+ try {
+ Field field = clazz.getDeclaredField(propertyName);
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+
+ Object value = field.get(o);
+
+ ColumnInfo columnInfo = configuration.get(propertyName);
+ if (columnInfo == null) {
+ // no column info means the property hasn't been properly mapped; suppress validation
+ return true;
+ }
+
+ if (!columnInfo.getIsNullable()) {
+ if (value == null) {return false;}
+ }
+ } catch (NoSuchFieldException e) {
+ // if the field doesn't exist, assume the configuration is faulty and skip this property
+ } catch (IllegalAccessException e) {
+ // TODO: something? deliberate no op?
+ }
+
+ }
+
+ return true;
+ }
+
+ public boolean hasConfiguration(Class clazz) {
+ return configurations.containsKey(clazz);
+ }
+
+ public ValidationConfiguration getConfiguration(Class clazz) {
+ return configurations.get(clazz);
+ }
+
+ public void setConfiguration(Class clazz, String propertyName, ColumnInfo columnInfo) {
+ if (!configurations.containsKey(clazz)) {
+ configurations.put(clazz, new ValidationConfiguration());
+ }
+
+ configurations.get(clazz).addMapping(propertyName, columnInfo);
+ }
+}
diff --git a/util/src/main/resources/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg
new file mode 100644
index 0000000..1008369
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/validation/dao/DatabaseSchemaSqlDao.sql.stg
@@ -0,0 +1,10 @@
+group DatabaseSchemaSqlDao;
+
+getSchemaInfo() ::= <<
+ SELECT TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE,
+ CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION, NUMERIC_SCALE
+ FROM information_schema.columns
+ WHERE TABLE_SCHEMA = :schemaName
+ ORDER BY TABLE_NAME, COLUMN_NAME;
+>>
+
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 93814f3..9237997 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -160,4 +160,8 @@ public class MysqlTestingHelper
}
});
}
+
+ public String getDbName() {
+ return DB_NAME;
+ }
}
diff --git a/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java b/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java
new file mode 100644
index 0000000..f664da3
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/validation/TestValidationManager.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.util.validation;
+
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.util.validation.dao.DatabaseSchemaDao;
+import org.joda.time.DateTime;
+import org.skife.jdbi.v2.IDBI;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+public class TestValidationManager {
+ private final MysqlTestingHelper helper = new MysqlTestingHelper();
+ private static final String TABLE_NAME = "validation_test";
+
+ private ValidationManager vm;
+
+ @BeforeClass(alwaysRun = true)
+ public void setup() throws IOException {
+ setupDatabase();
+ setupDao();
+ }
+
+ private void setupDao() {
+ IDBI dbi = helper.getDBI();
+ DatabaseSchemaDao dao = new DatabaseSchemaDao(dbi);
+ vm = new ValidationManager(dao);
+ vm.loadSchemaInformation(helper.getDbName());
+ }
+
+ private void setupDatabase() throws IOException {
+ helper.startMysql();
+ StringBuilder ddl = new StringBuilder();
+ ddl.append(String.format("DROP TABLE IF EXISTS %s;", TABLE_NAME));
+ ddl.append(String.format("CREATE TABLE %s (column1 varchar(1), column2 char(2) NOT NULL, column3 numeric(10,4), column4 datetime) ENGINE = innodb;", TABLE_NAME));
+ helper.initDb(ddl.toString());
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void tearDown() {
+ stopDatabase();
+ }
+
+ private void stopDatabase() {
+ helper.stopMysql();
+ }
+
+ @Test
+ public void testRetrievingColumnInfo() {
+ Collection<ColumnInfo> columnInfoList = vm.getTableInfo(TABLE_NAME);
+ assertEquals(columnInfoList.size(), 4);
+ assertNotNull(vm.getColumnInfo(TABLE_NAME, "column1"));
+ assertNull(vm.getColumnInfo(TABLE_NAME, "bogus"));
+
+ ColumnInfo numericColumnInfo = vm.getColumnInfo(TABLE_NAME, "column3");
+ assertNotNull(numericColumnInfo);
+ assertEquals(numericColumnInfo.getScale(), 4);
+ assertEquals(numericColumnInfo.getPrecision(), 10);
+ }
+
+ @Test
+ public void testSimpleConfiguration() {
+ String STRING_FIELD_2 = "column2";
+ String STRING_FIELD_2_PROPERTY = "stringField2";
+
+ SimpleTestClass testObject = new SimpleTestClass("a", null, 7.9, new DateTime());
+
+ vm.setConfiguration(testObject.getClass(), STRING_FIELD_2_PROPERTY, vm.getColumnInfo(TABLE_NAME, STRING_FIELD_2));
+
+ assertTrue(vm.hasConfiguration(testObject.getClass()));
+ assertFalse(vm.hasConfiguration(ValidationManager.class));
+
+ ValidationConfiguration configuration = vm.getConfiguration(SimpleTestClass.class);
+ assertNotNull(configuration);
+ assertTrue(configuration.hasMapping(STRING_FIELD_2_PROPERTY));
+
+ assertFalse(vm.validate(testObject));
+ testObject.setStringField2("ab");
+ assertTrue(vm.validate(testObject));
+
+ }
+
+ private class SimpleTestClass {
+ private String stringField1;
+ private String stringField2;
+ private double numericField1;
+ private DateTime dateTimeField1;
+
+ public SimpleTestClass(String stringField1, String stringField2, double numericField1, DateTime dateTimeField1) {
+ this.stringField1 = stringField1;
+ this.stringField2 = stringField2;
+ this.numericField1 = numericField1;
+ this.dateTimeField1 = dateTimeField1;
+ }
+
+ public String getStringField1() {
+ return stringField1;
+ }
+
+ public void setStringField1(String stringField1) {
+ this.stringField1 = stringField1;
+ }
+
+ public String getStringField2() {
+ return stringField2;
+ }
+
+ public void setStringField2(String stringField2) {
+ this.stringField2 = stringField2;
+ }
+
+ public double getNumericField1() {
+ return numericField1;
+ }
+
+ public void setNumericField1(double numericField1) {
+ this.numericField1 = numericField1;
+ }
+
+ public DateTime getDateTimeField1() {
+ return dateTimeField1;
+ }
+
+ public void setDateTimeField1(DateTime dateTimeField1) {
+ this.dateTimeField1 = dateTimeField1;
+ }
+ }
+}