diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/DefaultEnvironment.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/DefaultEnvironment.java index 543ddae9e8..48073b4fb1 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/DefaultEnvironment.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/DefaultEnvironment.java @@ -7,10 +7,10 @@ public class DefaultEnvironment implements IEnvironment { protected IResourceFactory resourceFactory; protected IDbPlatform dbPlatform; - - public DefaultEnvironment() { + + public DefaultEnvironment() { } - + public DefaultEnvironment(IResourceFactory resourceFactory, IDbPlatform dbPlatform) { this.resourceFactory = resourceFactory; this.dbPlatform = dbPlatform; @@ -23,13 +23,13 @@ public void setDbPlatform(IDbPlatform dbPlatform) { public IDbPlatform getDbPlatform() { return dbPlatform; } - + public void setResourceFactory(IResourceFactory resourceFactory) { this.resourceFactory = resourceFactory; } - + public IResourceFactory getResourceFactory() { return resourceFactory; - } + } } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/IEnvironment.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/IEnvironment.java index 74880604f0..c271b6fae0 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/IEnvironment.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/IEnvironment.java @@ -6,7 +6,7 @@ public interface IEnvironment { public IResourceFactory getResourceFactory(); - + public IDbPlatform getDbPlatform(); - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/Version.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/Version.java index 68bed26b5a..7e867c2d30 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/Version.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/Version.java @@ -22,7 +22,6 @@ import org.jumpmind.symmetric.core.common.AbstractVersion; - /** * Follow the Apache versioning scheme documented here. diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/ArrayUtils.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/ArrayUtils.java index c560ee8943..7a93a82913 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/ArrayUtils.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/ArrayUtils.java @@ -3,7 +3,7 @@ import java.lang.reflect.Array; public abstract class ArrayUtils { - + /** *

* Adds all the elements of the given arrays into a new array. @@ -45,17 +45,25 @@ public static Object[] addAll(Object[] array1, Object[] array2) { System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } - + /** - *

Shallow clones an array returning a typecast result and handling - * null.

- * - *

The objects in the array are not cloned, thus there is no special - * handling for multi-dimensional arrays.

+ *

+ * Shallow clones an array returning a typecast result and handling + * null. + *

* - *

This method returns null for a null input array.

+ *

+ * The objects in the array are not cloned, thus there is no special + * handling for multi-dimensional arrays. + *

+ * + *

+ * This method returns null for a null input + * array. + *

* - * @param array the array to shallow clone, may be null + * @param array + * the array to shallow clone, may be null * @return the cloned array, null if null input */ public static Object[] clone(Object[] array) { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/CollectionUtils.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/CollectionUtils.java index d4b108009d..133018b6ab 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/CollectionUtils.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/CollectionUtils.java @@ -7,33 +7,42 @@ public abstract class CollectionUtils { - /** + /** * Adds all elements in the array to the given collection. * - * @param collection the collection to add to, may not be null - * @param elements the array of elements to add, may not be null - * @throws NullPointerException if the collection or array is null + * @param collection + * the collection to add to, may not be null + * @param elements + * the array of elements to add, may not be null + * @throws NullPointerException + * if the collection or array is null */ public static void addAll(Collection collection, T[] elements) { for (int i = 0, size = elements.length; i < size; i++) { collection.add(elements[i]); } - } - + } + /** - *

Adds all the elements of the given arrays into a new array.

- *

The new array contains all of the element of array1 followed - * by all of the elements array2. When an array is returned, it is always - * a new array.

- * + *

+ * Adds all the elements of the given arrays into a new array. + *

+ *

+ * The new array contains all of the element of array1 followed + * by all of the elements array2. When an array is returned, it + * is always a new array. + *

+ * *
      * ArrayUtils.addAll(array1, null)   = cloned copy of array1
      * ArrayUtils.addAll(null, array2)   = cloned copy of array2
      * ArrayUtils.addAll([], [])         = []
      * 
- * - * @param array1 the first array whose elements are added to the new array. - * @param array2 the second array whose elements are added to the new array. + * + * @param array1 + * the first array whose elements are added to the new array. + * @param array2 + * the second array whose elements are added to the new array. * @return The new int[] array. * @since 2.1 */ @@ -48,14 +57,20 @@ public static int[] addAll(int[] array1, int[] array2) { System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } - + /** - *

Clones an array returning a typecast result and handling - * null.

- * - *

This method returns null for a null input array.

+ *

+ * Clones an array returning a typecast result and handling + * null. + *

* - * @param array the array to clone, may be null + *

+ * This method returns null for a null input + * array. + *

+ * + * @param array + * the array to clone, may be null * @return the cloned array, null if null input */ public static int[] clone(int[] array) { @@ -63,15 +78,18 @@ public static int[] clone(int[] array) { return null; } return (int[]) array.clone(); - } - - + } + /** - *

Adds all the elements of the given arrays into a new array.

- *

The new array contains all of the element of array1 followed - * by all of the elements array2. When an array is returned, it is always - * a new array.

- * + *

+ * Adds all the elements of the given arrays into a new array. + *

+ *

+ * The new array contains all of the element of array1 followed + * by all of the elements array2. When an array is returned, it + * is always a new array. + *

+ * *
      * ArrayUtils.addAll(null, null)     = null
      * ArrayUtils.addAll(array1, null)   = cloned copy of array1
@@ -80,11 +98,15 @@ public static int[] clone(int[] array) {
      * ArrayUtils.addAll([null], [null]) = [null, null]
      * ArrayUtils.addAll(["a", "b", "c"], ["1", "2", "3"]) = ["a", "b", "c", "1", "2", "3"]
      * 
- * - * @param array1 the first array whose elements are added to the new array, may be null - * @param array2 the second array whose elements are added to the new array, may be null - * @return The new array, null if null array inputs. - * The type of the new array is the type of the first array. + * + * @param array1 + * the first array whose elements are added to the new array, may + * be null + * @param array2 + * the second array whose elements are added to the new array, + * may be null + * @return The new array, null if null array + * inputs. The type of the new array is the type of the first array. * @since 2.1 */ public static T[] addAll(T[] array1, T[] array2) { @@ -95,22 +117,30 @@ public static T[] addAll(T[] array1, T[] array2) { } @SuppressWarnings("unchecked") T[] joinedArray = (T[]) Array.newInstance(array1.getClass().getComponentType(), - array1.length + array2.length); + array1.length + array2.length); System.arraycopy(array1, 0, joinedArray, 0, array1.length); System.arraycopy(array2, 0, joinedArray, array1.length, array2.length); return joinedArray; } - + /** - *

Shallow clones an array returning a typecast result and handling - * null.

- * - *

The objects in the array are not cloned, thus there is no special - * handling for multi-dimensional arrays.

+ *

+ * Shallow clones an array returning a typecast result and handling + * null. + *

* - *

This method returns null for a null input array.

+ *

+ * The objects in the array are not cloned, thus there is no special + * handling for multi-dimensional arrays. + *

* - * @param array the array to shallow clone, may be null + *

+ * This method returns null for a null input + * array. + *

+ * + * @param array + * the array to shallow clone, may be null * @return the cloned array, null if null input */ public static T[] clone(T[] array) { @@ -118,19 +148,19 @@ public static T[] clone(T[] array) { return null; } return (T[]) array.clone(); - } - - - public static List selectList(Class collectionType, Class[] candidateTypes, Collection collection) { + } + + public static List selectList(Class collectionType, Class[] candidateTypes, + Collection collection) { List list = new ArrayList(); for (Object object : collection) { for (Class type : candidateTypes) { if (type.isAssignableFrom(object.getClass())) { - list.add((T)object); + list.add((T) object); } } } return list; } - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/DateUtils.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/DateUtils.java index 4c5d95d586..cd2dc4f35c 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/DateUtils.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/DateUtils.java @@ -26,9 +26,11 @@ import java.util.TimeZone; /** - *

A suite of utilities surrounding the use of the - * {@link java.util.Calendar} and {@link java.util.Date} object.

- * + *

+ * A suite of utilities surrounding the use of the {@link java.util.Calendar} + * and {@link java.util.Date} object. + *

+ * * @author Serge Knystautas * @author Stephen Colebourne * @author Janek Bogucki @@ -37,50 +39,51 @@ * @since 2.0 * @version $Id: DateUtils.java 437554 2006-08-28 06:21:41Z bayard $ */ -public abstract class DateUtils { - +public abstract class DateUtils { + /** - * The UTC time zone (often referred to as GMT). + * The UTC time zone (often referred to as GMT). */ public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT"); /** * Number of milliseconds in a standard second. + * * @since 2.1 */ public static final long MILLIS_PER_SECOND = 1000; /** * Number of milliseconds in a standard minute. + * * @since 2.1 */ public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; /** * Number of milliseconds in a standard hour. + * * @since 2.1 */ public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; /** * Number of milliseconds in a standard day. + * * @since 2.1 */ public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; /** - * This is half a month, so this represents whether a date is in the top - * or bottom half of the month. + * This is half a month, so this represents whether a date is in the top or + * bottom half of the month. */ public final static int SEMI_MONTH = 1001; - private static final int[][] fields = { - {Calendar.MILLISECOND}, - {Calendar.SECOND}, - {Calendar.MINUTE}, - {Calendar.HOUR_OF_DAY, Calendar.HOUR}, - {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM - /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */ - }, - {Calendar.MONTH, DateUtils.SEMI_MONTH}, - {Calendar.YEAR}, - {Calendar.ERA}}; + private static final int[][] fields = { { Calendar.MILLISECOND }, { Calendar.SECOND }, + { Calendar.MINUTE }, { Calendar.HOUR_OF_DAY, Calendar.HOUR }, + { Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM + /* + * Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, + * Calendar.DAY_OF_WEEK_IN_MONTH + */ + }, { Calendar.MONTH, DateUtils.SEMI_MONTH }, { Calendar.YEAR }, { Calendar.ERA } }; /** * A week range, starting on Sunday. @@ -113,29 +116,39 @@ public abstract class DateUtils { public final static int RANGE_MONTH_MONDAY = 6; /** - *

DateUtils instances should NOT be constructed in - * standard programming. Instead, the class should be used as - * DateUtils.parse(str);.

- * - *

This constructor is public to permit tools that require a JavaBean - * instance to operate.

+ *

+ * DateUtils instances should NOT be constructed in standard + * programming. Instead, the class should be used as + * DateUtils.parse(str);. + *

+ * + *

+ * This constructor is public to permit tools that require a JavaBean + * instance to operate. + *

*/ public DateUtils() { super(); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Checks if two date objects are on the same day ignoring time.

- * - *

28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. - * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. + *

+ * Checks if two date objects are on the same day ignoring time. *

* - * @param date1 the first date, not altered, not null - * @param date2 the second date, not altered, not null + *

+ * 28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. 28 Mar 2002 + * 13:45 and 12 Mar 2002 13:45 would return false. + *

+ * + * @param date1 + * the first date, not altered, not null + * @param date2 + * the second date, not altered, not null * @return true if they represent the same day - * @throws IllegalArgumentException if either date is null + * @throws IllegalArgumentException + * if either date is null * @since 2.1 */ public static boolean isSameDay(Date date1, Date date2) { @@ -150,37 +163,50 @@ public static boolean isSameDay(Date date1, Date date2) { } /** - *

Checks if two calendar objects are on the same day ignoring time.

- * - *

28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. - * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. + *

+ * Checks if two calendar objects are on the same day ignoring time. + *

+ * + *

+ * 28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. 28 Mar 2002 + * 13:45 and 12 Mar 2002 13:45 would return false. *

* - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null + * @param cal1 + * the first calendar, not altered, not null + * @param cal2 + * the second calendar, not altered, not null * @return true if they represent the same day - * @throws IllegalArgumentException if either calendar is null + * @throws IllegalArgumentException + * if either calendar is null * @since 2.1 */ public static boolean isSameDay(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The date must not be null"); } - return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && - cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && - cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); + return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) + && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1 + .get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Checks if two date objects represent the same instant in time.

- * - *

This method compares the long millisecond time of the two objects.

+ *

+ * Checks if two date objects represent the same instant in time. + *

+ * + *

+ * This method compares the long millisecond time of the two objects. + *

* - * @param date1 the first date, not altered, not null - * @param date2 the second date, not altered, not null + * @param date1 + * the first date, not altered, not null + * @param date2 + * the second date, not altered, not null * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null + * @throws IllegalArgumentException + * if either date is null * @since 2.1 */ public static boolean isSameInstant(Date date1, Date date2) { @@ -191,14 +217,21 @@ public static boolean isSameInstant(Date date1, Date date2) { } /** - *

Checks if two calendar objects represent the same instant in time.

- * - *

This method compares the long millisecond time of the two objects.

+ *

+ * Checks if two calendar objects represent the same instant in time. + *

+ * + *

+ * This method compares the long millisecond time of the two objects. + *

* - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null + * @param cal1 + * the first calendar, not altered, not null + * @param cal2 + * the second calendar, not altered, not null * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null + * @throws IllegalArgumentException + * if either date is null * @since 2.1 */ public static boolean isSameInstant(Calendar cal1, Calendar cal2) { @@ -208,52 +241,69 @@ public static boolean isSameInstant(Calendar cal1, Calendar cal2) { return cal1.getTime().getTime() == cal2.getTime().getTime(); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Checks if two calendar objects represent the same local time.

- * - *

This method compares the values of the fields of the two objects. - * In addition, both calendars must be the same of the same type.

+ *

+ * Checks if two calendar objects represent the same local time. + *

+ * + *

+ * This method compares the values of the fields of the two objects. In + * addition, both calendars must be the same of the same type. + *

* - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null + * @param cal1 + * the first calendar, not altered, not null + * @param cal2 + * the second calendar, not altered, not null * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null + * @throws IllegalArgumentException + * if either date is null * @since 2.1 */ public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The date must not be null"); } - return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) && - cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) && - cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) && - cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR) && - cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && - cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && - cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && - cal1.getClass() == cal2.getClass()); + return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) + && cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) + && cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) + && cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR) + && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) + && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) + && cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.getClass() == cal2 + .getClass()); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Parses a string representing a date by trying a variety of different parsers.

+ *

+ * Parses a string representing a date by trying a variety of different + * parsers. + *

* - *

The parse will try each parse pattern in turn. - * A parse is only deemed sucessful if it parses the whole of the input string. - * If no parse patterns match, a ParseException is thrown.

+ *

+ * The parse will try each parse pattern in turn. A parse is only deemed + * sucessful if it parses the whole of the input string. If no parse + * patterns match, a ParseException is thrown. + *

* - * @param str the date to parse, not null - * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null + * @param str + * the date to parse, not null + * @param parsePatterns + * the date format patterns to use, see SimpleDateFormat, not + * null * @return the parsed date - * @throws IllegalArgumentException if the date string or pattern array is null - * @throws ParseException if none of the date patterns were suitable + * @throws IllegalArgumentException + * if the date string or pattern array is null + * @throws ParseException + * if none of the date patterns were suitable */ public static Date parseDate(String str, String[] parsePatterns) throws ParseException { if (str == null || parsePatterns == null) { throw new IllegalArgumentException("Date and Patterns must not be null"); } - + SimpleDateFormat parser = null; ParsePosition pos = new ParsePosition(0); for (int i = 0; i < parsePatterns.length; i++) { @@ -271,128 +321,156 @@ public static Date parseDate(String str, String[] parsePatterns) throws ParseExc throw new ParseException("Unable to parse the date: " + str, -1); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of years to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of years to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addYears(Date date, int amount) { return add(date, Calendar.YEAR, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of months to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of months to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addMonths(Date date, int amount) { return add(date, Calendar.MONTH, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of weeks to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of weeks to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addWeeks(Date date, int amount) { return add(date, Calendar.WEEK_OF_YEAR, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of days to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of days to a date returning a new object. The original date + * object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addDays(Date date, int amount) { return add(date, Calendar.DAY_OF_MONTH, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of hours to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of hours to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addHours(Date date, int amount) { return add(date, Calendar.HOUR_OF_DAY, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of minutes to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of minutes to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addMinutes(Date date, int amount) { return add(date, Calendar.MINUTE, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of seconds to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of seconds to a date returning a new object. The original + * date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addSeconds(Date date, int amount) { return add(date, Calendar.SECOND, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds a number of milliseconds to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative + * Adds a number of milliseconds to a date returning a new object. The + * original date object is unchanged. + * + * @param date + * the date, not null + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date addMilliseconds(Date date, int amount) { return add(date, Calendar.MILLISECOND, amount); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - * Adds to a date returning a new object. - * The original date object is unchanged. - * - * @param date the date, not null - * @param calendarField the calendar field to add to - * @param amount the amount to add, may be negative + * Adds to a date returning a new object. The original date object is + * unchanged. + * + * @param date + * the date, not null + * @param calendarField + * the calendar field to add to + * @param amount + * the amount to add, may be negative * @return the new date object with the amount added - * @throws IllegalArgumentException if the date is null + * @throws IllegalArgumentException + * if the date is null */ public static Date add(Date date, int calendarField, int amount) { if (date == null) { @@ -404,20 +482,24 @@ public static Date add(Date date, int calendarField, int amount) { return c.getTime(); } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

+ *

+ * Round this date, leaving the field specified as the most significant + * field. + *

* - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if this + * was passed with HOUR, it would return 28 Mar 2002 14:00:00.000. If this + * was passed with MONTH, it would return 1 April 2002 0:00:00.000. + *

+ * + *

+ * For a date in a timezone that handles the change to daylight saving time, + * rounding to Calendar.HOUR_OF_DAY will behave as follows. Suppose daylight + * saving time begins at 02:00 on March 30. Rounding a date that crosses + * this time would produce the following values: *

    *
  • March 30, 2003 01:10 rounds to March 30, 2003 01:00
  • *
  • March 30, 2003 01:40 rounds to March 30, 2003 03:00
  • @@ -426,12 +508,16 @@ public static Date add(Date date, int calendarField, int amount) { *
*

* - * @param date the date to work with - * @param field the field from Calendar - * or SEMI_MONTH + * @param date + * the date to work with + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ArithmeticException + * if the year is over 280 million */ public static Date round(Date date, int field) { if (date == null) { @@ -444,18 +530,22 @@ public static Date round(Date date, int field) { } /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

+ *

+ * Round this date, leaving the field specified as the most significant + * field. + *

+ * + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if this + * was passed with HOUR, it would return 28 Mar 2002 14:00:00.000. If this + * was passed with MONTH, it would return 1 April 2002 0:00:00.000. + *

* - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: + *

+ * For a date in a timezone that handles the change to daylight saving time, + * rounding to Calendar.HOUR_OF_DAY will behave as follows. Suppose daylight + * saving time begins at 02:00 on March 30. Rounding a date that crosses + * this time would produce the following values: *

    *
  • March 30, 2003 01:10 rounds to March 30, 2003 01:00
  • *
  • March 30, 2003 01:40 rounds to March 30, 2003 03:00
  • @@ -464,12 +554,16 @@ public static Date round(Date date, int field) { *
*

* - * @param date the date to work with - * @param field the field from Calendar - * or SEMI_MONTH + * @param date + * the date to work with + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date (a different object) - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ArithmeticException + * if the year is over 280 million */ public static Calendar round(Calendar date, int field) { if (date == null) { @@ -481,18 +575,22 @@ public static Calendar round(Calendar date, int field) { } /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

+ *

+ * Round this date, leaving the field specified as the most significant + * field. + *

* - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if this + * was passed with HOUR, it would return 28 Mar 2002 14:00:00.000. If this + * was passed with MONTH, it would return 1 April 2002 0:00:00.000. + *

+ * + *

+ * For a date in a timezone that handles the change to daylight saving time, + * rounding to Calendar.HOUR_OF_DAY will behave as follows. Suppose daylight + * saving time begins at 02:00 on March 30. Rounding a date that crosses + * this time would produce the following values: *

    *
  • March 30, 2003 01:10 rounds to March 30, 2003 01:00
  • *
  • March 30, 2003 01:40 rounds to March 30, 2003 03:00
  • @@ -501,14 +599,19 @@ public static Calendar round(Calendar date, int field) { *
*

* - * @param date the date to work with, either Date or Calendar - * @param field the field from Calendar - * or SEMI_MONTH + * @param date + * the date to work with, either Date or Calendar + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date - * @throws IllegalArgumentException if the date is null - * @throws ClassCastException if the object type is not a Date - * or Calendar - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ClassCastException + * if the object type is not a Date or + * Calendar + * @throws ArithmeticException + * if the year is over 280 million */ public static Date round(Object date, int field) { if (date == null) { @@ -523,22 +626,29 @@ public static Date round(Object date, int field) { } } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

+ *

+ * Truncate this date, leaving the field specified as the most significant + * field. + *

* - * @param date the date to work with - * @param field the field from Calendar - * or SEMI_MONTH + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if you + * passed with HOUR, it would return 28 Mar 2002 13:00:00.000. If this was + * passed with MONTH, it would return 1 Mar 2002 0:00:00.000. + *

+ * + * @param date + * the date to work with + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ArithmeticException + * if the year is over 280 million */ public static Date truncate(Date date, int field) { if (date == null) { @@ -551,20 +661,27 @@ public static Date truncate(Date date, int field) { } /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

+ *

+ * Truncate this date, leaving the field specified as the most significant + * field. + *

* - * @param date the date to work with - * @param field the field from Calendar - * or SEMI_MONTH + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if you + * passed with HOUR, it would return 28 Mar 2002 13:00:00.000. If this was + * passed with MONTH, it would return 1 Mar 2002 0:00:00.000. + *

+ * + * @param date + * the date to work with + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date (a different object) - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ArithmeticException + * if the year is over 280 million */ public static Calendar truncate(Calendar date, int field) { if (date == null) { @@ -576,24 +693,31 @@ public static Calendar truncate(Calendar date, int field) { } /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

+ *

+ * Truncate this date, leaving the field specified as the most significant + * field. + *

* - * @param date the date to work with, either Date - * or Calendar - * @param field the field from Calendar - * or SEMI_MONTH + *

+ * For example, if you had the datetime of 28 Mar 2002 13:45:01.231, if you + * passed with HOUR, it would return 28 Mar 2002 13:00:00.000. If this was + * passed with MONTH, it would return 1 Mar 2002 0:00:00.000. + *

+ * + * @param date + * the date to work with, either Date or + * Calendar + * @param field + * the field from Calendar or + * SEMI_MONTH * @return the rounded date - * @throws IllegalArgumentException if the date - * is null - * @throws ClassCastException if the object type is not a - * Date or Calendar - * @throws ArithmeticException if the year is over 280 million + * @throws IllegalArgumentException + * if the date is null + * @throws ClassCastException + * if the object type is not a Date or + * Calendar + * @throws ArithmeticException + * if the year is over 280 million */ public static Date truncate(Object date, int field) { if (date == null) { @@ -608,28 +732,36 @@ public static Date truncate(Object date, int field) { } } - //----------------------------------------------------------------------- + // ----------------------------------------------------------------------- /** - *

Internal calculation method.

+ *

+ * Internal calculation method. + *

* - * @param val the calendar - * @param field the field constant - * @param round true to round, false to truncate - * @throws ArithmeticException if the year is over 280 million + * @param val + * the calendar + * @param field + * the field constant + * @param round + * true to round, false to truncate + * @throws ArithmeticException + * if the year is over 280 million */ private static void modify(Calendar val, int field, boolean round) { if (val.get(Calendar.YEAR) > 280000000) { throw new ArithmeticException("Calendar value too large for accurate calculations"); } - + if (field == Calendar.MILLISECOND) { return; } - // ----------------- Fix for LANG-59 ---------------------- START --------------- + // ----------------- Fix for LANG-59 ---------------------- START + // --------------- // see http://issues.apache.org/jira/browse/LANG-59 // - // Manually truncate milliseconds, seconds and minutes, rather than using + // Manually truncate milliseconds, seconds and minutes, rather than + // using // Calendar methods. Date date = val.getTime(); @@ -665,18 +797,19 @@ private static void modify(Calendar val, int field, boolean round) { date.setTime(time); val.setTime(date); } - // ----------------- Fix for LANG-59 ----------------------- END ---------------- + // ----------------- Fix for LANG-59 ----------------------- END + // ---------------- boolean roundUp = false; for (int i = 0; i < fields.length; i++) { for (int j = 0; j < fields[i].length; j++) { if (fields[i][j] == field) { - //This is our field... we stop looping + // This is our field... we stop looping if (round && roundUp) { if (field == DateUtils.SEMI_MONTH) { - //This is a special case that's hard to generalize - //If the date is 1, we round up to 16, otherwise - // we subtract 15 days and add 1 month + // This is a special case that's hard to generalize + // If the date is 1, we round up to 16, otherwise + // we subtract 15 days and add 1 month if (val.get(Calendar.DATE) == 1) { val.add(Calendar.DATE, 15); } else { @@ -684,57 +817,61 @@ private static void modify(Calendar val, int field, boolean round) { val.add(Calendar.MONTH, 1); } } else { - //We need at add one to this field since the - // last number causes us to round up + // We need at add one to this field since the + // last number causes us to round up val.add(fields[i][0], 1); } } return; } } - //We have various fields that are not easy roundings + // We have various fields that are not easy roundings int offset = 0; boolean offsetSet = false; - //These are special types of fields that require different rounding rules + // These are special types of fields that require different rounding + // rules switch (field) { - case DateUtils.SEMI_MONTH: - if (fields[i][0] == Calendar.DATE) { - //If we're going to drop the DATE field's value, - // we want to do this our own way. - //We need to subtrace 1 since the date has a minimum of 1 - offset = val.get(Calendar.DATE) - 1; - //If we're above 15 days adjustment, that means we're in the - // bottom half of the month and should stay accordingly. - if (offset >= 15) { - offset -= 15; - } - //Record whether we're in the top or bottom half of that range - roundUp = offset > 7; - offsetSet = true; + case DateUtils.SEMI_MONTH: + if (fields[i][0] == Calendar.DATE) { + // If we're going to drop the DATE field's value, + // we want to do this our own way. + // We need to subtrace 1 since the date has a minimum of 1 + offset = val.get(Calendar.DATE) - 1; + // If we're above 15 days adjustment, that means we're in + // the + // bottom half of the month and should stay accordingly. + if (offset >= 15) { + offset -= 15; } - break; - case Calendar.AM_PM: - if (fields[i][0] == Calendar.HOUR_OF_DAY) { - //If we're going to drop the HOUR field's value, - // we want to do this our own way. - offset = val.get(Calendar.HOUR_OF_DAY); - if (offset >= 12) { - offset -= 12; - } - roundUp = offset > 6; - offsetSet = true; + // Record whether we're in the top or bottom half of that + // range + roundUp = offset > 7; + offsetSet = true; + } + break; + case Calendar.AM_PM: + if (fields[i][0] == Calendar.HOUR_OF_DAY) { + // If we're going to drop the HOUR field's value, + // we want to do this our own way. + offset = val.get(Calendar.HOUR_OF_DAY); + if (offset >= 12) { + offset -= 12; } - break; + roundUp = offset > 6; + offsetSet = true; + } + break; } if (!offsetSet) { int min = val.getActualMinimum(fields[i][0]); int max = val.getActualMaximum(fields[i][0]); - //Calculate the offset from the minimum allowed value + // Calculate the offset from the minimum allowed value offset = val.get(fields[i][0]) - min; - //Set roundUp if this is more than half way between the minimum and maximum + // Set roundUp if this is more than half way between the minimum + // and maximum roundUp = offset > ((max - min) / 2); } - //We need to remove this field + // We need to remove this field if (offset != 0) { val.set(fields[i][0], val.get(fields[i][0]) - offset); } @@ -743,30 +880,40 @@ private static void modify(Calendar val, int field, boolean round) { } - //----------------------------------------------------------------------- - /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - *

This method provides an iterator that returns Calendar objects. - * The days are progressed using {@link Calendar#add(int, int)}.

- * - * @param focus the date to work with, not null - * @param rangeStyle the style constant to use. Must be one of - * {@link DateUtils#RANGE_MONTH_SUNDAY}, - * {@link DateUtils#RANGE_MONTH_MONDAY}, - * {@link DateUtils#RANGE_WEEK_SUNDAY}, - * {@link DateUtils#RANGE_WEEK_MONDAY}, - * {@link DateUtils#RANGE_WEEK_RELATIVE}, - * {@link DateUtils#RANGE_WEEK_CENTER} + // ----------------------------------------------------------------------- + /** + *

+ * This constructs an Iterator over each day in a date range + * defined by a focus date and range style. + *

+ * + *

+ * For instance, passing Thursday, July 4, 2002 and a + * RANGE_MONTH_SUNDAY will return an Iterator that + * starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 2002, + * returning a Calendar instance for each intermediate day. + *

+ * + *

+ * This method provides an iterator that returns Calendar objects. The days + * are progressed using {@link Calendar#add(int, int)}. + *

+ * + * @param focus + * the date to work with, not null + * @param rangeStyle + * the style constant to use. Must be one of + * {@link DateUtils#RANGE_MONTH_SUNDAY}, + * {@link DateUtils#RANGE_MONTH_MONDAY}, + * {@link DateUtils#RANGE_WEEK_SUNDAY}, + * {@link DateUtils#RANGE_WEEK_MONDAY}, + * {@link DateUtils#RANGE_WEEK_RELATIVE}, + * {@link DateUtils#RANGE_WEEK_CENTER} * @return the date iterator, which always returns Calendar instances - * @throws IllegalArgumentException if the date is null - * @throws IllegalArgumentException if the rangeStyle is invalid + * @throws IllegalArgumentException + * if the date is null + * @throws IllegalArgumentException + * if the rangeStyle is invalid */ public static Iterator iterator(Date focus, int rangeStyle) { if (focus == null) { @@ -778,28 +925,38 @@ public static Iterator iterator(Date focus, int rangeStyle) { } /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - *

This method provides an iterator that returns Calendar objects. - * The days are progressed using {@link Calendar#add(int, int)}.

- * - * @param focus the date to work with - * @param rangeStyle the style constant to use. Must be one of - * {@link DateUtils#RANGE_MONTH_SUNDAY}, - * {@link DateUtils#RANGE_MONTH_MONDAY}, - * {@link DateUtils#RANGE_WEEK_SUNDAY}, - * {@link DateUtils#RANGE_WEEK_MONDAY}, - * {@link DateUtils#RANGE_WEEK_RELATIVE}, - * {@link DateUtils#RANGE_WEEK_CENTER} + *

+ * This constructs an Iterator over each day in a date range + * defined by a focus date and range style. + *

+ * + *

+ * For instance, passing Thursday, July 4, 2002 and a + * RANGE_MONTH_SUNDAY will return an Iterator that + * starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 2002, + * returning a Calendar instance for each intermediate day. + *

+ * + *

+ * This method provides an iterator that returns Calendar objects. The days + * are progressed using {@link Calendar#add(int, int)}. + *

+ * + * @param focus + * the date to work with + * @param rangeStyle + * the style constant to use. Must be one of + * {@link DateUtils#RANGE_MONTH_SUNDAY}, + * {@link DateUtils#RANGE_MONTH_MONDAY}, + * {@link DateUtils#RANGE_WEEK_SUNDAY}, + * {@link DateUtils#RANGE_WEEK_MONDAY}, + * {@link DateUtils#RANGE_WEEK_RELATIVE}, + * {@link DateUtils#RANGE_WEEK_CENTER} * @return the date iterator - * @throws IllegalArgumentException if the date is null - * @throws IllegalArgumentException if the rangeStyle is invalid + * @throws IllegalArgumentException + * if the date is null + * @throws IllegalArgumentException + * if the rangeStyle is invalid */ public static Iterator iterator(Calendar focus, int rangeStyle) { if (focus == null) { @@ -810,47 +967,47 @@ public static Iterator iterator(Calendar focus, int rangeStyle) { int startCutoff = Calendar.SUNDAY; int endCutoff = Calendar.SATURDAY; switch (rangeStyle) { - case RANGE_MONTH_SUNDAY: - case RANGE_MONTH_MONDAY: - //Set start to the first of the month - start = truncate(focus, Calendar.MONTH); - //Set end to the last of the month - end = (Calendar) start.clone(); - end.add(Calendar.MONTH, 1); - end.add(Calendar.DATE, -1); - //Loop start back to the previous sunday or monday - if (rangeStyle == RANGE_MONTH_MONDAY) { - startCutoff = Calendar.MONDAY; - endCutoff = Calendar.SUNDAY; - } - break; + case RANGE_MONTH_SUNDAY: + case RANGE_MONTH_MONDAY: + // Set start to the first of the month + start = truncate(focus, Calendar.MONTH); + // Set end to the last of the month + end = (Calendar) start.clone(); + end.add(Calendar.MONTH, 1); + end.add(Calendar.DATE, -1); + // Loop start back to the previous sunday or monday + if (rangeStyle == RANGE_MONTH_MONDAY) { + startCutoff = Calendar.MONDAY; + endCutoff = Calendar.SUNDAY; + } + break; + case RANGE_WEEK_SUNDAY: + case RANGE_WEEK_MONDAY: + case RANGE_WEEK_RELATIVE: + case RANGE_WEEK_CENTER: + // Set start and end to the current date + start = truncate(focus, Calendar.DATE); + end = truncate(focus, Calendar.DATE); + switch (rangeStyle) { case RANGE_WEEK_SUNDAY: + // already set by default + break; case RANGE_WEEK_MONDAY: + startCutoff = Calendar.MONDAY; + endCutoff = Calendar.SUNDAY; + break; case RANGE_WEEK_RELATIVE: + startCutoff = focus.get(Calendar.DAY_OF_WEEK); + endCutoff = startCutoff - 1; + break; case RANGE_WEEK_CENTER: - //Set start and end to the current date - start = truncate(focus, Calendar.DATE); - end = truncate(focus, Calendar.DATE); - switch (rangeStyle) { - case RANGE_WEEK_SUNDAY: - //already set by default - break; - case RANGE_WEEK_MONDAY: - startCutoff = Calendar.MONDAY; - endCutoff = Calendar.SUNDAY; - break; - case RANGE_WEEK_RELATIVE: - startCutoff = focus.get(Calendar.DAY_OF_WEEK); - endCutoff = startCutoff - 1; - break; - case RANGE_WEEK_CENTER: - startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3; - endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3; - break; - } + startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3; + endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3; break; - default: - throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid."); + } + break; + default: + throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid."); } if (startCutoff < Calendar.SUNDAY) { startCutoff += 7; @@ -874,23 +1031,30 @@ public static Iterator iterator(Calendar focus, int rangeStyle) { } /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - * @param focus the date to work with, either - * Date or Calendar - * @param rangeStyle the style constant to use. Must be one of the range - * styles listed for the {@link #iterator(Calendar, int)} method. + *

+ * This constructs an Iterator over each day in a date range + * defined by a focus date and range style. + *

+ * + *

+ * For instance, passing Thursday, July 4, 2002 and a + * RANGE_MONTH_SUNDAY will return an Iterator that + * starts with Sunday, June 30, 2002 and ends with Saturday, August 3, 2002, + * returning a Calendar instance for each intermediate day. + *

+ * + * @param focus + * the date to work with, either Date or + * Calendar + * @param rangeStyle + * the style constant to use. Must be one of the range styles + * listed for the {@link #iterator(Calendar, int)} method. * @return the date iterator - * @throws IllegalArgumentException if the date - * is null - * @throws ClassCastException if the object type is - * not a Date or Calendar + * @throws IllegalArgumentException + * if the date is null + * @throws ClassCastException + * if the object type is not a Date or + * Calendar */ public static Iterator iterator(Object focus, int rangeStyle) { if (focus == null) { @@ -906,17 +1070,21 @@ public static Iterator iterator(Object focus, int rangeStyle) { } /** - *

Date iterator.

+ *

+ * Date iterator. + *

*/ static class DateIterator implements Iterator { private final Calendar endFinal; private final Calendar spot; - + /** - * Constructs a DateIterator that ranges from one date to another. - * - * @param startFinal start date (inclusive) - * @param endFinal end date (not inclusive) + * Constructs a DateIterator that ranges from one date to another. + * + * @param startFinal + * start date (inclusive) + * @param endFinal + * end date (not inclusive) */ DateIterator(Calendar startFinal, Calendar endFinal) { super(); @@ -927,8 +1095,9 @@ static class DateIterator implements Iterator { /** * Has the iterator not reached the end date yet? - * - * @return true if the iterator has yet to reach the end date + * + * @return true if the iterator has yet to reach the end + * date */ public boolean hasNext() { return spot.before(endFinal); @@ -936,7 +1105,7 @@ public boolean hasNext() { /** * Return the next calendar in the iteration - * + * * @return Object calendar for the next date */ public Object next() { @@ -957,27 +1126,30 @@ public void remove() { throw new UnsupportedOperationException(); } } - - //------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- // Deprecated int constants // TODO: Remove in 3.0 - + /** * Number of milliseconds in a standard second. * - * @deprecated Use MILLIS_PER_SECOND. This will be removed in Commons Lang 3.0. + * @deprecated Use MILLIS_PER_SECOND. This will be removed in Commons Lang + * 3.0. */ public static final int MILLIS_IN_SECOND = 1000; /** * Number of milliseconds in a standard minute. * - * @deprecated Use MILLIS_PER_MINUTE. This will be removed in Commons Lang 3.0. + * @deprecated Use MILLIS_PER_MINUTE. This will be removed in Commons Lang + * 3.0. */ public static final int MILLIS_IN_MINUTE = 60 * 1000; /** * Number of milliseconds in a standard hour. * - * @deprecated Use MILLIS_PER_HOUR. This will be removed in Commons Lang 3.0. + * @deprecated Use MILLIS_PER_HOUR. This will be removed in Commons Lang + * 3.0. */ public static final int MILLIS_IN_HOUR = 60 * 60 * 1000; /** @@ -986,5 +1158,5 @@ public void remove() { * @deprecated Use MILLIS_PER_DAY. This will be removed in Commons Lang 3.0. */ public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000; - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/EqualsBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/EqualsBuilder.java index 33c1e14188..0f5d3ae58a 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/EqualsBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/EqualsBuilder.java @@ -24,57 +24,68 @@ import java.util.List; /** - *

Assists in implementing {@link Object#equals(Object)} methods.

- * - *

This class provides methods to build a good equals method for any - * class. It follows rules laid out in - * Effective Java + *

+ * Assists in implementing {@link Object#equals(Object)} methods. + *

+ * + *

+ * This class provides methods to build a good equals method for any class. It + * follows rules laid out in Effective Java * , by Joshua Bloch. In particular the rule for comparing doubles, * floats, and arrays can be tricky. Also, making sure that * equals() and hashCode() are consistent can be - * difficult.

- * - *

Two Objects that compare as equals must generate the same hash code, - * but two Objects with the same hash code do not have to be equal.

- * - *

All relevant fields should be included in the calculation of equals. - * Derived fields may be ignored. In particular, any field used in - * generating a hash code must be used in the equals method, and vice - * versa.

- * - *

Typical use for the code is as follows:

+ * difficult. + *

+ * + *

+ * Two Objects that compare as equals must generate the same hash code, but two + * Objects with the same hash code do not have to be equal. + *

+ * + *

+ * All relevant fields should be included in the calculation of equals. Derived + * fields may be ignored. In particular, any field used in generating a hash + * code must be used in the equals method, and vice versa. + *

+ * + *

+ * Typical use for the code is as follows: + *

+ * *
  * public boolean equals(Object obj) {
- *   if (obj instanceof MyClass == false) {
- *     return false;
- *   }
- *   if (this == obj) {
- *     return true;
- *   }
- *   MyClass rhs = (MyClass) obj;
- *   return new EqualsBuilder()
- *                 .appendSuper(super.equals(obj))
- *                 .append(field1, rhs.field1)
- *                 .append(field2, rhs.field2)
- *                 .append(field3, rhs.field3)
- *                 .isEquals();
- *  }
+ *     if (obj instanceof MyClass == false) {
+ *         return false;
+ *     }
+ *     if (this == obj) {
+ *         return true;
+ *     }
+ *     MyClass rhs = (MyClass) obj;
+ *     return new EqualsBuilder().appendSuper(super.equals(obj)).append(field1, rhs.field1)
+ *             .append(field2, rhs.field2).append(field3, rhs.field3).isEquals();
+ * }
  * 
- * - *

Alternatively, there is a method that uses reflection to determine - * the fields to test. Because these fields are usually private, the method, - * reflectionEquals, uses AccessibleObject.setAccessible to - * change the visibility of the fields. This will fail under a security - * manager, unless the appropriate permissions are set up correctly. It is - * also slower than testing explicitly.

- * - *

A typical invocation for this method would look like:

+ * + *

+ * Alternatively, there is a method that uses reflection to determine the fields + * to test. Because these fields are usually private, the method, + * reflectionEquals, uses + * AccessibleObject.setAccessible to change the visibility of the + * fields. This will fail under a security manager, unless the appropriate + * permissions are set up correctly. It is also slower than testing explicitly. + *

+ * + *

+ * A typical invocation for this method would look like: + *

+ * *
  * public boolean equals(Object obj) {
- *   return EqualsBuilder.reflectionEquals(this, obj);
+ *     return EqualsBuilder.reflectionEquals(this, obj);
  * }
  * 
- * + * * @author Steve Downey * @author Stephen Colebourne * @author Gary Gregory @@ -84,41 +95,55 @@ * @version $Id: EqualsBuilder.java 437554 2006-08-28 06:21:41Z bayard $ */ public class EqualsBuilder { - + /** - * If the fields tested are equals. - * The default value is true. + * If the fields tested are equals. The default value is true. */ private boolean isEquals = true; /** - *

Constructor for EqualsBuilder.

- * - *

Starts off assuming that equals is true.

+ *

+ * Constructor for EqualsBuilder. + *

+ * + *

+ * Starts off assuming that equals is true. + *

+ * * @see Object#equals(Object) */ public EqualsBuilder() { // do nothing for now. } - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** - *

This method uses reflection to determine if the two Objects - * are equal.

- * - *

It uses AccessibleObject.setAccessible to gain access to private - * fields. This means that it will throw a security exception if run under - * a security manager, if the permissions are not set up correctly. It is also - * not as efficient as testing explicitly.

- * - *

Transient members will be not be tested, as they are likely derived - * fields, and not part of the value of the Object.

- * - *

Static fields will not be tested. Superclass fields will be included.

- * - * @param lhs this object - * @param rhs the other object + *

+ * This method uses reflection to determine if the two Objects + * are equal. + *

+ * + *

+ * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. + *

+ * + *

+ * Transient members will be not be tested, as they are likely derived + * fields, and not part of the value of the Object. + *

+ * + *

+ * Static fields will not be tested. Superclass fields will be included. + *

+ * + * @param lhs + * this object + * @param rhs + * the other object * @return true if the two Objects have tested equals. */ public static boolean reflectionEquals(Object lhs, Object rhs) { @@ -126,22 +151,33 @@ public static boolean reflectionEquals(Object lhs, Object rhs) { } /** - *

This method uses reflection to determine if the two Objects - * are equal.

- * - *

It uses AccessibleObject.setAccessible to gain access to private - * fields. This means that it will throw a security exception if run under - * a security manager, if the permissions are not set up correctly. It is also - * not as efficient as testing explicitly.

- * - *

Transient members will be not be tested, as they are likely derived - * fields, and not part of the value of the Object.

- * - *

Static fields will not be tested. Superclass fields will be included.

- * - * @param lhs this object - * @param rhs the other object - * @param excludeFields array of field names to exclude from testing + *

+ * This method uses reflection to determine if the two Objects + * are equal. + *

+ * + *

+ * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. + *

+ * + *

+ * Transient members will be not be tested, as they are likely derived + * fields, and not part of the value of the Object. + *

+ * + *

+ * Static fields will not be tested. Superclass fields will be included. + *

+ * + * @param lhs + * this object + * @param rhs + * the other object + * @param excludeFields + * array of field names to exclude from testing * @return true if the two Objects have tested equals. */ public static boolean reflectionEquals(Object lhs, Object rhs, String[] excludeFields) { @@ -149,23 +185,34 @@ public static boolean reflectionEquals(Object lhs, Object rhs, String[] excludeF } /** - *

This method uses reflection to determine if the two Objects - * are equal.

- * - *

It uses AccessibleObject.setAccessible to gain access to private - * fields. This means that it will throw a security exception if run under - * a security manager, if the permissions are not set up correctly. It is also - * not as efficient as testing explicitly.

- * - *

If the TestTransients parameter is set to true, transient + *

+ * This method uses reflection to determine if the two Objects + * are equal. + *

+ * + *

+ * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. + *

+ * + *

+ * If the TestTransients parameter is set to true, transient * members will be tested, otherwise they are ignored, as they are likely - * derived fields, and not part of the value of the Object.

- * - *

Static fields will not be tested. Superclass fields will be included.

- * - * @param lhs this object - * @param rhs the other object - * @param testTransients whether to include transient fields + * derived fields, and not part of the value of the Object. + *

+ * + *

+ * Static fields will not be tested. Superclass fields will be included. + *

+ * + * @param lhs + * this object + * @param rhs + * the other object + * @param testTransients + * whether to include transient fields * @return true if the two Objects have tested equals. */ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) { @@ -173,71 +220,97 @@ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTrans } /** - *

This method uses reflection to determine if the two Objects - * are equal.

- * - *

It uses AccessibleObject.setAccessible to gain access to private - * fields. This means that it will throw a security exception if run under - * a security manager, if the permissions are not set up correctly. It is also - * not as efficient as testing explicitly.

- * - *

If the testTransients parameter is set to true, transient + *

+ * This method uses reflection to determine if the two Objects + * are equal. + *

+ * + *

+ * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. + *

+ * + *

+ * If the testTransients parameter is set to true, transient * members will be tested, otherwise they are ignored, as they are likely - * derived fields, and not part of the value of the Object.

- * - *

Static fields will not be included. Superclass fields will be appended - * up to and including the specified superclass. A null superclass is treated - * as java.lang.Object.

- * - * @param lhs this object - * @param rhs the other object - * @param testTransients whether to include transient fields - * @param reflectUpToClass the superclass to reflect up to (inclusive), - * may be null + * derived fields, and not part of the value of the Object. + *

+ * + *

+ * Static fields will not be included. Superclass fields will be appended up + * to and including the specified superclass. A null superclass is treated + * as java.lang.Object. + *

+ * + * @param lhs + * this object + * @param rhs + * the other object + * @param testTransients + * whether to include transient fields + * @param reflectUpToClass + * the superclass to reflect up to (inclusive), may be + * null * @return true if the two Objects have tested equals. * @since 2.0 */ - public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass) { + public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, + Class reflectUpToClass) { return reflectionEquals(lhs, rhs, testTransients, reflectUpToClass, null); } /** - *

This method uses reflection to determine if the two Objects - * are equal.

- * - *

It uses AccessibleObject.setAccessible to gain access to private - * fields. This means that it will throw a security exception if run under - * a security manager, if the permissions are not set up correctly. It is also - * not as efficient as testing explicitly.

- * - *

If the testTransients parameter is set to true, transient + *

+ * This method uses reflection to determine if the two Objects + * are equal. + *

+ * + *

+ * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. + *

+ * + *

+ * If the testTransients parameter is set to true, transient * members will be tested, otherwise they are ignored, as they are likely - * derived fields, and not part of the value of the Object.

- * - *

Static fields will not be included. Superclass fields will be appended - * up to and including the specified superclass. A null superclass is treated - * as java.lang.Object.

- * - * @param lhs this object - * @param rhs the other object - * @param testTransients whether to include transient fields - * @param reflectUpToClass the superclass to reflect up to (inclusive), - * may be null - * @param excludeFields array of field names to exclude from testing + * derived fields, and not part of the value of the Object. + *

+ * + *

+ * Static fields will not be included. Superclass fields will be appended up + * to and including the specified superclass. A null superclass is treated + * as java.lang.Object. + *

+ * + * @param lhs + * this object + * @param rhs + * the other object + * @param testTransients + * whether to include transient fields + * @param reflectUpToClass + * the superclass to reflect up to (inclusive), may be + * null + * @param excludeFields + * array of field names to exclude from testing * @return true if the two Objects have tested equals. * @since 2.0 */ - public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class reflectUpToClass, - String[] excludeFields) { + public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, + Class reflectUpToClass, String[] excludeFields) { if (lhs == rhs) { return true; } if (lhs == null || rhs == null) { return false; } - // Find the leaf class since there may be transients in the leaf + // Find the leaf class since there may be transients in the leaf // class or in classes between the leaf and root. - // If we are not testing transients or a subclass has no ivars, + // If we are not testing transients or a subclass has no ivars, // then a subclass can test equals to a superclass. Class lhsClass = lhs.getClass(); Class rhsClass = rhs.getClass(); @@ -267,9 +340,10 @@ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTrans } } catch (IllegalArgumentException e) { // In this case, we tried to test a subclass vs. a superclass and - // the subclass has ivars or the ivars are transient and + // the subclass has ivars or the ivars are transient and // we are testing transients. - // If a subclass has ivars that we are trying to test them, we get an + // If a subclass has ivars that we are trying to test them, we get + // an // exception and we know that the objects are not equal. return false; } @@ -277,49 +351,55 @@ public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTrans } /** - *

Appends the fields and values defined by the given object of the - * given Class.

- * - * @param lhs the left hand object - * @param rhs the right hand object - * @param clazz the class to append details of - * @param builder the builder to append to - * @param useTransients whether to test transient fields - * @param excludeFields array of field names to exclude from testing + *

+ * Appends the fields and values defined by the given object of the given + * Class. + *

+ * + * @param lhs + * the left hand object + * @param rhs + * the right hand object + * @param clazz + * the class to append details of + * @param builder + * the builder to append to + * @param useTransients + * whether to test transient fields + * @param excludeFields + * array of field names to exclude from testing */ - private static void reflectionAppend( - Object lhs, - Object rhs, - Class clazz, - EqualsBuilder builder, - boolean useTransients, - String[] excludeFields) { + private static void reflectionAppend(Object lhs, Object rhs, Class clazz, + EqualsBuilder builder, boolean useTransients, String[] excludeFields) { Field[] fields = clazz.getDeclaredFields(); - List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST; + List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) + : Collections.EMPTY_LIST; AccessibleObject.setAccessible(fields, true); for (int i = 0; i < fields.length && builder.isEquals; i++) { Field f = fields[i]; - if (!excludedFieldList.contains(f.getName()) - && (f.getName().indexOf('$') == -1) - && (useTransients || !Modifier.isTransient(f.getModifiers())) - && (!Modifier.isStatic(f.getModifiers()))) { + if (!excludedFieldList.contains(f.getName()) && (f.getName().indexOf('$') == -1) + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && (!Modifier.isStatic(f.getModifiers()))) { try { builder.append(f.get(lhs), f.get(rhs)); } catch (IllegalAccessException e) { - //this can't happen. Would get a Security exception instead - //throw a runtime exception in case the impossible happens. + // this can't happen. Would get a Security exception instead + // throw a runtime exception in case the impossible happens. throw new InternalError("Unexpected IllegalAccessException"); } } } } - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** - *

Adds the result of super.equals() to this builder.

- * - * @param superEquals the result of calling super.equals() + *

+ * Adds the result of super.equals() to this builder. + *

+ * + * @param superEquals + * the result of calling super.equals() * @return EqualsBuilder - used to chain calls. * @since 2.0 */ @@ -331,14 +411,18 @@ public EqualsBuilder appendSuper(boolean superEquals) { return this; } - //------------------------------------------------------------------------- + // ------------------------------------------------------------------------- /** - *

Test if two Objects are equal using their - * equals method.

- * - * @param lhs the left hand object - * @param rhs the right hand object + *

+ * Test if two Objects are equal using their + * equals method. + *

+ * + * @param lhs + * the left hand object + * @param rhs + * the right hand object * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(Object lhs, Object rhs) { @@ -357,7 +441,8 @@ public EqualsBuilder append(Object lhs, Object rhs) { // The simple case, not an array, just test the element isEquals = lhs.equals(rhs); } else if (lhs.getClass() != rhs.getClass()) { - // Here when we compare different dimensions, for example: a boolean[][] to a boolean[] + // Here when we compare different dimensions, for example: a + // boolean[][] to a boolean[] this.setEquals(false); } // 'Switch' on type of array, to dispatch to the correct handler @@ -391,9 +476,9 @@ else if (lhs instanceof long[]) { *

* * @param lhs - * the left hand long + * the left hand long * @param rhs - * the right hand long + * the right hand long * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(long lhs, long rhs) { @@ -405,10 +490,14 @@ public EqualsBuilder append(long lhs, long rhs) { } /** - *

Test if two ints are equal.

- * - * @param lhs the left hand int - * @param rhs the right hand int + *

+ * Test if two ints are equal. + *

+ * + * @param lhs + * the left hand int + * @param rhs + * the right hand int * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(int lhs, int rhs) { @@ -420,10 +509,14 @@ public EqualsBuilder append(int lhs, int rhs) { } /** - *

Test if two shorts are equal.

- * - * @param lhs the left hand short - * @param rhs the right hand short + *

+ * Test if two shorts are equal. + *

+ * + * @param lhs + * the left hand short + * @param rhs + * the right hand short * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(short lhs, short rhs) { @@ -435,10 +528,14 @@ public EqualsBuilder append(short lhs, short rhs) { } /** - *

Test if two chars are equal.

- * - * @param lhs the left hand char - * @param rhs the right hand char + *

+ * Test if two chars are equal. + *

+ * + * @param lhs + * the left hand char + * @param rhs + * the right hand char * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(char lhs, char rhs) { @@ -450,10 +547,14 @@ public EqualsBuilder append(char lhs, char rhs) { } /** - *

Test if two bytes are equal.

- * - * @param lhs the left hand byte - * @param rhs the right hand byte + *

+ * Test if two bytes are equal. + *

+ * + * @param lhs + * the left hand byte + * @param rhs + * the right hand byte * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(byte lhs, byte rhs) { @@ -465,16 +566,24 @@ public EqualsBuilder append(byte lhs, byte rhs) { } /** - *

Test if two doubles are equal by testing that the - * pattern of bits returned by doubleToLong are equal.

- * - *

This handles NaNs, Infinities, and -0.0.

- * - *

It is compatible with the hash code generated by - * HashCodeBuilder.

- * - * @param lhs the left hand double - * @param rhs the right hand double + *

+ * Test if two doubles are equal by testing that the pattern of + * bits returned by doubleToLong are equal. + *

+ * + *

+ * This handles NaNs, Infinities, and -0.0. + *

+ * + *

+ * It is compatible with the hash code generated by + * HashCodeBuilder. + *

+ * + * @param lhs + * the left hand double + * @param rhs + * the right hand double * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(double lhs, double rhs) { @@ -485,16 +594,24 @@ public EqualsBuilder append(double lhs, double rhs) { } /** - *

Test if two floats are equal byt testing that the - * pattern of bits returned by doubleToLong are equal.

- * - *

This handles NaNs, Infinities, and -0.0.

- * - *

It is compatible with the hash code generated by - * HashCodeBuilder.

- * - * @param lhs the left hand float - * @param rhs the right hand float + *

+ * Test if two floats are equal byt testing that the pattern of + * bits returned by doubleToLong are equal. + *

+ * + *

+ * This handles NaNs, Infinities, and -0.0. + *

+ * + *

+ * It is compatible with the hash code generated by + * HashCodeBuilder. + *

+ * + * @param lhs + * the left hand float + * @param rhs + * the right hand float * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(float lhs, float rhs) { @@ -505,12 +622,16 @@ public EqualsBuilder append(float lhs, float rhs) { } /** - *

Test if two booleanss are equal.

- * - * @param lhs the left hand boolean - * @param rhs the right hand boolean + *

+ * Test if two booleanss are equal. + *

+ * + * @param lhs + * the left hand boolean + * @param rhs + * the right hand boolean * @return EqualsBuilder - used to chain calls. - */ + */ public EqualsBuilder append(boolean lhs, boolean rhs) { if (isEquals == false) { return this; @@ -520,13 +641,19 @@ public EqualsBuilder append(boolean lhs, boolean rhs) { } /** - *

Performs a deep comparison of two Object arrays.

- * - *

This also will be called for the top level of - * multi-dimensional, ragged, and multi-typed arrays.

- * - * @param lhs the left hand Object[] - * @param rhs the right hand Object[] + *

+ * Performs a deep comparison of two Object arrays. + *

+ * + *

+ * This also will be called for the top level of multi-dimensional, ragged, + * and multi-typed arrays. + *

+ * + * @param lhs + * the left hand Object[] + * @param rhs + * the right hand Object[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(Object[] lhs, Object[] rhs) { @@ -551,13 +678,19 @@ public EqualsBuilder append(Object[] lhs, Object[] rhs) { } /** - *

Deep comparison of array of long. Length and all - * values are compared.

- * - *

The method {@link #append(long, long)} is used.

- * - * @param lhs the left hand long[] - * @param rhs the right hand long[] + *

+ * Deep comparison of array of long. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(long, long)} is used. + *

+ * + * @param lhs + * the left hand long[] + * @param rhs + * the right hand long[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(long[] lhs, long[] rhs) { @@ -582,13 +715,19 @@ public EqualsBuilder append(long[] lhs, long[] rhs) { } /** - *

Deep comparison of array of int. Length and all - * values are compared.

- * - *

The method {@link #append(int, int)} is used.

- * - * @param lhs the left hand int[] - * @param rhs the right hand int[] + *

+ * Deep comparison of array of int. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(int, int)} is used. + *

+ * + * @param lhs + * the left hand int[] + * @param rhs + * the right hand int[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(int[] lhs, int[] rhs) { @@ -613,13 +752,19 @@ public EqualsBuilder append(int[] lhs, int[] rhs) { } /** - *

Deep comparison of array of short. Length and all - * values are compared.

- * - *

The method {@link #append(short, short)} is used.

- * - * @param lhs the left hand short[] - * @param rhs the right hand short[] + *

+ * Deep comparison of array of short. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(short, short)} is used. + *

+ * + * @param lhs + * the left hand short[] + * @param rhs + * the right hand short[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(short[] lhs, short[] rhs) { @@ -644,13 +789,19 @@ public EqualsBuilder append(short[] lhs, short[] rhs) { } /** - *

Deep comparison of array of char. Length and all - * values are compared.

- * - *

The method {@link #append(char, char)} is used.

- * - * @param lhs the left hand char[] - * @param rhs the right hand char[] + *

+ * Deep comparison of array of char. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(char, char)} is used. + *

+ * + * @param lhs + * the left hand char[] + * @param rhs + * the right hand char[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(char[] lhs, char[] rhs) { @@ -675,13 +826,19 @@ public EqualsBuilder append(char[] lhs, char[] rhs) { } /** - *

Deep comparison of array of byte. Length and all - * values are compared.

- * - *

The method {@link #append(byte, byte)} is used.

- * - * @param lhs the left hand byte[] - * @param rhs the right hand byte[] + *

+ * Deep comparison of array of byte. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(byte, byte)} is used. + *

+ * + * @param lhs + * the left hand byte[] + * @param rhs + * the right hand byte[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(byte[] lhs, byte[] rhs) { @@ -706,13 +863,19 @@ public EqualsBuilder append(byte[] lhs, byte[] rhs) { } /** - *

Deep comparison of array of double. Length and all - * values are compared.

- * - *

The method {@link #append(double, double)} is used.

- * - * @param lhs the left hand double[] - * @param rhs the right hand double[] + *

+ * Deep comparison of array of double. Length and all values + * are compared. + *

+ * + *

+ * The method {@link #append(double, double)} is used. + *

+ * + * @param lhs + * the left hand double[] + * @param rhs + * the right hand double[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(double[] lhs, double[] rhs) { @@ -737,13 +900,19 @@ public EqualsBuilder append(double[] lhs, double[] rhs) { } /** - *

Deep comparison of array of float. Length and all - * values are compared.

- * - *

The method {@link #append(float, float)} is used.

- * - * @param lhs the left hand float[] - * @param rhs the right hand float[] + *

+ * Deep comparison of array of float. Length and all values are + * compared. + *

+ * + *

+ * The method {@link #append(float, float)} is used. + *

+ * + * @param lhs + * the left hand float[] + * @param rhs + * the right hand float[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(float[] lhs, float[] rhs) { @@ -768,13 +937,19 @@ public EqualsBuilder append(float[] lhs, float[] rhs) { } /** - *

Deep comparison of array of boolean. Length and all - * values are compared.

- * - *

The method {@link #append(boolean, boolean)} is used.

- * - * @param lhs the left hand boolean[] - * @param rhs the right hand boolean[] + *

+ * Deep comparison of array of boolean. Length and all values + * are compared. + *

+ * + *

+ * The method {@link #append(boolean, boolean)} is used. + *

+ * + * @param lhs + * the left hand boolean[] + * @param rhs + * the right hand boolean[] * @return EqualsBuilder - used to chain calls. */ public EqualsBuilder append(boolean[] lhs, boolean[] rhs) { @@ -799,9 +974,11 @@ public EqualsBuilder append(boolean[] lhs, boolean[] rhs) { } /** - *

Returns true if the fields that have been checked - * are all equal.

- * + *

+ * Returns true if the fields that have been checked are all + * equal. + *

+ * * @return boolean */ public boolean isEquals() { @@ -811,7 +988,8 @@ public boolean isEquals() { /** * Sets the isEquals value. * - * @param isEquals The value to set. + * @param isEquals + * The value to set. * @since 2.1 */ protected void setEquals(boolean isEquals) { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/HashCodeBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/HashCodeBuilder.java index 57c8aef5d4..668545d271 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/HashCodeBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/HashCodeBuilder.java @@ -32,15 +32,18 @@ *

* *

- * This class enables a good hashCode method to be built for any class. It follows the rules laid out in - * the book Effective Java by Joshua Bloch. Writing a - * good hashCode method is actually quite difficult. This class aims to simplify the process. + * This class enables a good hashCode method to be built for any + * class. It follows the rules laid out in the book Effective Java + * by Joshua Bloch. Writing a good hashCode method is actually + * quite difficult. This class aims to simplify the process. *

* *

- * All relevant fields from the object should be included in the hashCode method. Derived fields may be - * excluded. In general, any field used in the equals method must be used in the hashCode - * method. + * All relevant fields from the object should be included in the + * hashCode method. Derived fields may be excluded. In general, any + * field used in the equals method must be used in the + * hashCode method. *

* *

@@ -53,7 +56,7 @@ * int age; * boolean smoker; * ... - * + * * public int hashCode() { * // you pick a hard-coded, randomly chosen, non-zero, odd number * // ideally different for each class @@ -67,14 +70,17 @@ * * *

- * If required, the superclass hashCode() can be added using {@link #appendSuper}. + * If required, the superclass hashCode() can be added using + * {@link #appendSuper}. *

* *

- * Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are - * usually private, the method, reflectionHashCode, uses AccessibleObject.setAccessible - * to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions - * are set up correctly. It is also slower than testing explicitly. + * Alternatively, there is a method that uses reflection to determine the fields + * to test. Because these fields are usually private, the method, + * reflectionHashCode, uses + * AccessibleObject.setAccessible to change the visibility of the + * fields. This will fail under a security manager, unless the appropriate + * permissions are set up correctly. It is also slower than testing explicitly. *

* *

@@ -83,7 +89,7 @@ * *

  * public int hashCode() {
- *   return HashCodeBuilder.reflectionHashCode(this);
+ *     return HashCodeBuilder.reflectionHashCode(this);
  * }
  * 
* @@ -96,7 +102,8 @@ public class HashCodeBuilder { /** *

- * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops. + * A registry of objects used by reflection methods to detect cyclical + * object references and avoid infinite loops. *

* * @since 2.3 @@ -111,7 +118,8 @@ protected synchronized Object initialValue() { /** *

- * Returns the registry of objects being traversed by the reflection methods in the current thread. + * Returns the registry of objects being traversed by the reflection methods + * in the current thread. *

* * @return Set the registry of objects being traversed @@ -123,13 +131,14 @@ static Set getRegistry() { /** *

- * Returns true if the registry contains the given object. Used by the reflection methods to avoid - * infinite loops. + * Returns true if the registry contains the given object. Used + * by the reflection methods to avoid infinite loops. *

* * @param value * The object to lookup in the registry. - * @return boolean true if the registry contains the given object. + * @return boolean true if the registry contains the given + * object. * @since 2.3 */ static boolean isRegistered(Object value) { @@ -138,7 +147,8 @@ static boolean isRegistered(Object value) { /** *

- * Appends the fields and values defined by the given object of the given Class. + * Appends the fields and values defined by the given object of the given + * Class. *

* * @param object @@ -150,30 +160,34 @@ static boolean isRegistered(Object value) { * @param useTransients * whether to use transient fields * @param excludeFields - * Collection of String field names to exclude from use in calculation of hash code + * Collection of String field names to exclude from use in + * calculation of hash code */ - private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients, - String[] excludeFields) { + private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, + boolean useTransients, String[] excludeFields) { if (isRegistered(object)) { return; } try { register(object); Field[] fields = clazz.getDeclaredFields(); - List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) : Collections.EMPTY_LIST; + List excludedFieldList = excludeFields != null ? Arrays.asList(excludeFields) + : Collections.EMPTY_LIST; AccessibleObject.setAccessible(fields, true); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if (!excludedFieldList.contains(field.getName()) - && (field.getName().indexOf('$') == -1) - && (useTransients || !Modifier.isTransient(field.getModifiers())) - && (!Modifier.isStatic(field.getModifiers()))) { + && (field.getName().indexOf('$') == -1) + && (useTransients || !Modifier.isTransient(field.getModifiers())) + && (!Modifier.isStatic(field.getModifiers()))) { try { Object fieldValue = field.get(object); builder.append(fieldValue); } catch (IllegalAccessException e) { - // this can't happen. Would get a Security exception instead - // throw a runtime exception in case the impossible happens. + // this can't happen. Would get a Security exception + // instead + // throw a runtime exception in case the impossible + // happens. throw new InternalError("Unexpected IllegalAccessException"); } } @@ -189,14 +203,15 @@ private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the - * Object. + * Transient members will be not be used, as they are likely derived fields, + * and not part of the value of the Object. *

* *

@@ -204,8 +219,9 @@ private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder *

* *

- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, - * however this is not vital. Prime numbers are preferred, especially for the multiplier. + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally + * these should be different for each class, however this is not vital. + * Prime numbers are preferred, especially for the multiplier. *

* * @param initialNonZeroOddNumber @@ -220,8 +236,10 @@ private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder * @throws IllegalArgumentException * if the number is zero or even */ - public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) { - return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null, null); + public static int reflectionHashCode(int initialNonZeroOddNumber, + int multiplierNonZeroOddNumber, Object object) { + return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, + false, null, null); } /** @@ -230,14 +248,16 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * If the TestTransients parameter is set to true, transient members will be tested, otherwise they - * are ignored, as they are likely derived fields, and not part of the value of the Object. + * If the TestTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. *

* *

@@ -245,8 +265,9 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier *

* *

- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, - * however this is not vital. Prime numbers are preferred, especially for the multiplier. + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally + * these should be different for each class, however this is not vital. + * Prime numbers are preferred, especially for the multiplier. *

* * @param initialNonZeroOddNumber @@ -263,15 +284,16 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier * @throws IllegalArgumentException * if the number is zero or even */ - public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, - boolean testTransients) { - return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null, - null); + public static int reflectionHashCode(int initialNonZeroOddNumber, + int multiplierNonZeroOddNumber, Object object, boolean testTransients) { + return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, + testTransients, null, null); } /** - * Calls {@link #reflectionHashCode(int, int, Object, boolean, Class, String[])} with excludeFields set to - * null. + * Calls + * {@link #reflectionHashCode(int, int, Object, boolean, Class, String[])} + * with excludeFields set to null. * * @param initialNonZeroOddNumber * a non-zero, odd number used as the initial value @@ -282,13 +304,15 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier * @param testTransients * whether to include transient fields * @param reflectUpToClass - * the superclass to reflect up to (inclusive), may be null + * the superclass to reflect up to (inclusive), may be + * null * @return int hash code */ - public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, - boolean testTransients, Class reflectUpToClass) { - return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, - reflectUpToClass, null); + public static int reflectionHashCode(int initialNonZeroOddNumber, + int multiplierNonZeroOddNumber, Object object, boolean testTransients, + Class reflectUpToClass) { + return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, + testTransients, reflectUpToClass, null); } /** @@ -297,24 +321,28 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * If the TestTransients parameter is set to true, transient members will be tested, otherwise they - * are ignored, as they are likely derived fields, and not part of the value of the Object. + * If the TestTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. *

* *

- * Static fields will not be included. Superclass fields will be included up to and including the specified - * superclass. A null superclass is treated as java.lang.Object. + * Static fields will not be included. Superclass fields will be included up + * to and including the specified superclass. A null superclass is treated + * as java.lang.Object. *

* *

- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, - * however this is not vital. Prime numbers are preferred, especially for the multiplier. + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally + * these should be different for each class, however this is not vital. + * Prime numbers are preferred, especially for the multiplier. *

* * @param initialNonZeroOddNumber @@ -326,9 +354,11 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier * @param testTransients * whether to include transient fields * @param reflectUpToClass - * the superclass to reflect up to (inclusive), may be null + * the superclass to reflect up to (inclusive), may be + * null * @param excludeFields - * array of field names to exclude from use in calculation of hash code + * array of field names to exclude from use in calculation of + * hash code * @return int hash code * @throws IllegalArgumentException * if the Object is null @@ -336,13 +366,16 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier * if the number is zero or even * @since 2.0 */ - public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object, - boolean testTransients, Class reflectUpToClass, String[] excludeFields) { + public static int reflectionHashCode(int initialNonZeroOddNumber, + int multiplierNonZeroOddNumber, Object object, boolean testTransients, + Class reflectUpToClass, String[] excludeFields) { if (object == null) { - throw new IllegalArgumentException("The object to build a hash code for must not be null"); + throw new IllegalArgumentException( + "The object to build a hash code for must not be null"); } - HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber); + HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, + multiplierNonZeroOddNumber); Class clazz = object.getClass(); reflectionAppend(object, clazz, builder, testTransients, excludeFields); while (clazz.getSuperclass() != null && clazz != reflectUpToClass) { @@ -358,18 +391,20 @@ public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplier *

* *

- * This constructor uses two hard coded choices for the constants needed to build a hash code. + * This constructor uses two hard coded choices for the constants needed to + * build a hash code. *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the - * Object. + * Transient members will be not be used, as they are likely derived fields, + * and not part of the value of the Object. *

* *

@@ -392,18 +427,21 @@ public static int reflectionHashCode(Object object) { *

* *

- * This constructor uses two hard coded choices for the constants needed to build a hash code. + * This constructor uses two hard coded choices for the constants needed to + * build a hash code. *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * If the TestTransients parameter is set to true, transient members will be tested, otherwise they - * are ignored, as they are likely derived fields, and not part of the value of the Object. + * If the TestTransients parameter is set to true, transient + * members will be tested, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. *

* *

@@ -430,18 +468,20 @@ public static int reflectionHashCode(Object object, boolean testTransients) { *

* *

- * This constructor uses two hard coded choices for the constants needed to build a hash code. + * This constructor uses two hard coded choices for the constants needed to + * build a hash code. *

* *

- * It uses AccessibleObject.setAccessible to gain access to private fields. This means that it will - * throw a security exception if run under a security manager, if the permissions are not set up correctly. It is - * also not as efficient as testing explicitly. + * It uses AccessibleObject.setAccessible to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. *

* *

- * Transient members will be not be used, as they are likely derived fields, and not part of the value of the - * Object. + * Transient members will be not be used, as they are likely derived fields, + * and not part of the value of the Object. *

* *

@@ -451,7 +491,8 @@ public static int reflectionHashCode(Object object, boolean testTransients) { * @param object * the Object to create a hashCode for * @param excludeFields - * array of field names to exclude from use in calculation of hash code + * array of field names to exclude from use in calculation of + * hash code * @return int hash code * @throws IllegalArgumentException * if the object is null @@ -462,7 +503,8 @@ public static int reflectionHashCode(Object object, String[] excludeFields) { /** *

- * Registers the given object. Used by the reflection methods to avoid infinite loops. + * Registers the given object. Used by the reflection methods to avoid + * infinite loops. *

* * @param value @@ -512,7 +554,8 @@ static void unregister(Object value) { /** *

- * Uses two hard coded choices for the constants needed to build a hashCode. + * Uses two hard coded choices for the constants needed to build a + * hashCode. *

*/ public HashCodeBuilder() { @@ -522,8 +565,8 @@ public HashCodeBuilder() { /** *

- * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class, - * however this is not vital. + * Two randomly chosen, non-zero, odd numbers must be passed in. Ideally + * these should be different for each class, however this is not vital. *

* *

@@ -559,9 +602,9 @@ public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumb * Append a hashCode for a boolean. *

*

- * This adds iConstant * 1 to the hashCode and not a 1231 or - * 1237 as done in java.lang.Boolean. This is in accordance with the Effective Java - * design. + * This adds iConstant * 1 to the hashCode and not + * a 1231 or 1237 as done in java.lang.Boolean. + * This is in accordance with the Effective Java design. *

* * @param value diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/Log.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/Log.java index 6df6547000..a41270aa19 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/Log.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/Log.java @@ -1,22 +1,21 @@ package org.jumpmind.symmetric.core.common; - abstract public class Log { Class clazz; - - public abstract void log (LogLevel level, String msg, Object ... params); - - public abstract void log (LogLevel level, Throwable error, String msg, Object ... params); - + + public abstract void log(LogLevel level, String msg, Object... params); + + public abstract void log(LogLevel level, Throwable error, String msg, Object... params); + public abstract void log(LogLevel level, Throwable error); - + public abstract void debug(String msg); - + public abstract boolean isDebugEnabled(); - + public abstract void error(Throwable ex); - + protected void initialize(Class clazz) { this.clazz = clazz; } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/LogFactory.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/LogFactory.java index 2616d2aed9..a89b4f7749 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/LogFactory.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/LogFactory.java @@ -10,8 +10,7 @@ public class LogFactory { private static Map, Log> logs = new HashMap, Log>(); static { - String clazzName = System.getProperty(Log.class.getName(), - DefaultLog.class.getName()); + String clazzName = System.getProperty(Log.class.getName(), DefaultLog.class.getName()); try { logClass = Class.forName(clazzName); Object log = logClass.newInstance(); diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/NotImplementedException.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/NotImplementedException.java index c34435deec..90720960b1 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/NotImplementedException.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/NotImplementedException.java @@ -7,9 +7,9 @@ public class NotImplementedException extends RuntimeException { public NotImplementedException() { super(); } - + public NotImplementedException(String message) { super(message); } - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/StringUtils.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/StringUtils.java index ffda30b3f3..730dcd54ea 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/StringUtils.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/common/StringUtils.java @@ -5,16 +5,17 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; - public abstract class StringUtils { private static Pattern TOKEN_REPLACEMENT_PATTERN = Pattern.compile("\\$\\((.+?)\\)"); - + /** - *

The maximum size to which the padding constant(s) can expand.

+ *

+ * The maximum size to which the padding constant(s) can expand. + *

*/ private static final int PAD_LIMIT = 8192; - + /** *

* Replaces all occurrences of a String within another String. @@ -137,10 +138,12 @@ public static String replace(String text, String repl, String with, int max) { public static boolean isEmpty(String str) { return str == null || str.length() == 0; } - + /** - *

Checks if a String is whitespace, empty ("") or null.

- * + *

+ * Checks if a String is whitespace, empty ("") or null. + *

+ * *
      * StringUtils.isBlank(null)      = true
      * StringUtils.isBlank("")        = true
@@ -148,8 +151,9 @@ public static boolean isEmpty(String str) {
      * StringUtils.isBlank("bob")     = false
      * StringUtils.isBlank("  bob  ") = false
      * 
- * - * @param str the String to check, may be null + * + * @param str + * the String to check, may be null * @return true if the String is null, empty or whitespace * @since 2.0 */ @@ -165,10 +169,12 @@ public static boolean isBlank(String str) { } return true; } - + /** - *

Checks if a String is not empty (""), not null and not whitespace only.

- * + *

+ * Checks if a String is not empty (""), not null and not whitespace only. + *

+ * *
      * StringUtils.isNotBlank(null)      = false
      * StringUtils.isNotBlank("")        = false
@@ -176,28 +182,34 @@ public static boolean isBlank(String str) {
      * StringUtils.isNotBlank("bob")     = true
      * StringUtils.isNotBlank("  bob  ") = true
      * 
- * - * @param str the String to check, may be null - * @return true if the String is - * not empty and not null and not whitespace + * + * @param str + * the String to check, may be null + * @return true if the String is not empty and not null and not + * whitespace * @since 2.0 */ public static boolean isNotBlank(String str) { return !StringUtils.isBlank(str); - } - + } + /** - *

Converts a String to upper case as per {@link String#toUpperCase()}.

- * - *

A null input String returns null.

- * + *

+ * Converts a String to upper case as per {@link String#toUpperCase()}. + *

+ * + *

+ * A null input String returns null. + *

+ * *
      * StringUtils.upperCase(null)  = null
      * StringUtils.upperCase("")    = ""
      * StringUtils.upperCase("aBc") = "ABC"
      * 
- * - * @param str the String to upper case, may be null + * + * @param str + * the String to upper case, may be null * @return the upper cased String, null if null String input */ public static String upperCase(String str) { @@ -208,17 +220,22 @@ public static String upperCase(String str) { } /** - *

Converts a String to lower case as per {@link String#toLowerCase()}.

- * - *

A null input String returns null.

- * + *

+ * Converts a String to lower case as per {@link String#toLowerCase()}. + *

+ * + *

+ * A null input String returns null. + *

+ * *
      * StringUtils.lowerCase(null)  = null
      * StringUtils.lowerCase("")    = ""
      * StringUtils.lowerCase("aBc") = "abc"
      * 
- * - * @param str the String to lower case, may be null + * + * @param str + * the String to lower case, may be null * @return the lower cased String, null if null String input */ public static String lowerCase(String str) { @@ -229,10 +246,14 @@ public static String lowerCase(String str) { } /** - *

Right pad a String with a specified character.

- * - *

The String is padded to the size of size.

- * + *

+ * Right pad a String with a specified character. + *

+ * + *

+ * The String is padded to the size of size. + *

+ * *
      * StringUtils.rightPad(null, *, *)     = null
      * StringUtils.rightPad("", 3, 'z')     = "zzz"
@@ -241,12 +262,15 @@ public static String lowerCase(String str) {
      * StringUtils.rightPad("bat", 1, 'z')  = "bat"
      * StringUtils.rightPad("bat", -1, 'z') = "bat"
      * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padChar the character to pad with - * @return right padded String or original String if no padding is necessary, - * null if null String input + * + * @param str + * the String to pad out, may be null + * @param size + * the size to pad to + * @param padChar + * the character to pad with + * @return right padded String or original String if no padding is + * necessary, null if null String input * @since 2.0 */ public static String rightPad(String str, int size, char padChar) { @@ -264,10 +288,14 @@ public static String rightPad(String str, int size, char padChar) { } /** - *

Right pad a String with a specified String.

- * - *

The String is padded to the size of size.

- * + *

+ * Right pad a String with a specified String. + *

+ * + *

+ * The String is padded to the size of size. + *

+ * *
      * StringUtils.rightPad(null, *, *)      = null
      * StringUtils.rightPad("", 3, "z")      = "zzz"
@@ -279,12 +307,15 @@ public static String rightPad(String str, int size, char padChar) {
      * StringUtils.rightPad("bat", 5, null)  = "bat  "
      * StringUtils.rightPad("bat", 5, "")    = "bat  "
      * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padStr the String to pad with, null or empty treated as single space - * @return right padded String or original String if no padding is necessary, - * null if null String input + * + * @param str + * the String to pad out, may be null + * @param size + * the size to pad to + * @param padStr + * the String to pad with, null or empty treated as single space + * @return right padded String or original String if no padding is + * necessary, null if null String input */ public static String rightPad(String str, int size, String padStr) { if (str == null) { @@ -316,28 +347,33 @@ public static String rightPad(String str, int size, String padStr) { return str.concat(new String(padding)); } } - + /** - *

Returns padding using the specified delimiter repeated - * to a given length.

- * + *

+ * Returns padding using the specified delimiter repeated to a given length. + *

+ * *
      * StringUtils.padding(0, 'e')  = ""
      * StringUtils.padding(3, 'e')  = "eee"
      * StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
      * 
- * - *

Note: this method doesn't not support padding with - * Unicode Supplementary Characters - * as they require a pair of chars to be represented. - * If you are needing to support full I18N of your applications - * consider using {@link #repeat(String, int)} instead. + * + *

+ * Note: this method doesn't not support padding with Unicode + * Supplementary Characters as they require a pair of chars + * to be represented. If you are needing to support full I18N of your + * applications consider using {@link #repeat(String, int)} instead. *

- * - * @param repeat number of times to repeat delim - * @param padChar character to repeat + * + * @param repeat + * number of times to repeat delim + * @param padChar + * character to repeat * @return String with repeated character - * @throws IndexOutOfBoundsException if repeat < 0 + * @throws IndexOutOfBoundsException + * if repeat < 0 * @see #repeat(String, int) */ private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException { @@ -350,13 +386,17 @@ private static String padding(int repeat, char padChar) throws IndexOutOfBoundsE } return new String(buf); } - + /** - *

Compares two Strings, returning true if they are equal.

- * - *

nulls are handled without exceptions. Two null - * references are considered to be equal. The comparison is case sensitive.

- * + *

+ * Compares two Strings, returning true if they are equal. + *

+ * + *

+ * nulls are handled without exceptions. Two null + * references are considered to be equal. The comparison is case sensitive. + *

+ * *
      * StringUtils.equals(null, null)   = true
      * StringUtils.equals(null, "abc")  = false
@@ -364,24 +404,30 @@ private static String padding(int repeat, char padChar) throws IndexOutOfBoundsE
      * StringUtils.equals("abc", "abc") = true
      * StringUtils.equals("abc", "ABC") = false
      * 
- * + * * @see java.lang.String#equals(Object) - * @param str1 the first String, may be null - * @param str2 the second String, may be null + * @param str1 + * the first String, may be null + * @param str2 + * the second String, may be null * @return true if the Strings are equal, case sensitive, or - * both null + * both null */ public static boolean equals(String str1, String str2) { return str1 == null ? str2 == null : str1.equals(str2); } /** - *

Compares two Strings, returning true if they are equal ignoring - * the case.

- * - *

nulls are handled without exceptions. Two null - * references are considered equal. Comparison is case insensitive.

- * + *

+ * Compares two Strings, returning true if they are equal + * ignoring the case. + *

+ * + *

+ * nulls are handled without exceptions. Two null + * references are considered equal. Comparison is case insensitive. + *

+ * *
      * StringUtils.equalsIgnoreCase(null, null)   = true
      * StringUtils.equalsIgnoreCase(null, "abc")  = false
@@ -389,18 +435,21 @@ public static boolean equals(String str1, String str2) {
      * StringUtils.equalsIgnoreCase("abc", "abc") = true
      * StringUtils.equalsIgnoreCase("abc", "ABC") = true
      * 
- * + * * @see java.lang.String#equalsIgnoreCase(String) - * @param str1 the first String, may be null - * @param str2 the second String, may be null + * @param str1 + * the first String, may be null + * @param str2 + * the second String, may be null * @return true if the Strings are equal, case insensitive, or - * both null + * both null */ public static boolean equalsIgnoreCase(String str1, String str2) { return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2); } - - public static String replaceTokens(String tokenName, String replacementValue, String originalText) { + + public static String replaceTokens(String tokenName, String replacementValue, + String originalText) { Map replacements = new HashMap(1); replacements.put(tokenName, replacementValue); return replaceTokens(originalText, replacements, true); @@ -444,14 +493,18 @@ public static String formatString(String format, String arg) { return String.format(format, arg); } } - + /** - *

Checks if the String contains only unicode digits. - * A decimal point is not a unicode digit and returns false.

- * - *

null will return false. - * An empty String ("") will return true.

- * + *

+ * Checks if the String contains only unicode digits. A decimal point is not + * a unicode digit and returns false. + *

+ * + *

+ * null will return false. An empty String ("") + * will return true. + *

+ * *
      * StringUtils.isNumeric(null)   = false
      * StringUtils.isNumeric("")     = true
@@ -462,8 +515,9 @@ public static String formatString(String format, String arg) {
      * StringUtils.isNumeric("12-3") = false
      * StringUtils.isNumeric("12.3") = false
      * 
- * - * @param str the String to check, may be null + * + * @param str + * the String to check, may be null * @return true if only contains digits, and is non-null */ public static boolean isNumeric(String str) { @@ -477,6 +531,6 @@ public static boolean isNumeric(String str) { } } return true; - } - + } + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/AbstractDbPlatform.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/AbstractDbPlatform.java index 3e53cf706d..1111af0c6e 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/AbstractDbPlatform.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/AbstractDbPlatform.java @@ -44,20 +44,20 @@ abstract public class AbstractDbPlatform implements IDbPlatform { protected String defaultCatalog; protected SqlBuilder sqlBuilder; - + protected TriggerBuilder triggerBuilder; - + protected Parameters parameters; - + public AbstractDbPlatform(Parameters parameters) { this.parameters = parameters == null ? new Parameters() : parameters; } - + public Parameters getParameters() { return parameters; } - + public TriggerBuilder getTriggerBuilder() { return triggerBuilder; } @@ -65,7 +65,7 @@ public TriggerBuilder getTriggerBuilder() { public SqlBuilder getSqlBuilder() { return sqlBuilder; } - + public boolean isLob(int type) { return type == Types.CLOB || type == Types.BLOB || type == Types.BINARY || type == Types.VARBINARY || type == Types.LONGVARBINARY || diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/DbPlatformInfo.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/DbPlatformInfo.java index cbc095e9be..e001097485 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/DbPlatformInfo.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/DbPlatformInfo.java @@ -33,27 +33,27 @@ * and native type mappings. */ public class DbPlatformInfo { - + /** The Log to which logging calls will be made. */ private final Log log = LogFactory.getLog(DbPlatformInfo.class); - + private boolean scriptModeOn = false; - - private boolean sqlCommentsOn = false; - + + private boolean sqlCommentsOn = false; + private boolean dateOverridesToTimestamp = false; - + private String identifierQuoteString = "\""; /** Whether delimited identifiers are used or not. */ private boolean delimitedIdentifierModeOn = false; - + private boolean emptyStringNulled = false; - + private boolean blankCharColumnSpacePadded = false; - + private boolean nonBlankCharColumnSpacePadded = false; - + /** * Whether the database requires the explicit stating of NULL as the default * value. @@ -79,10 +79,10 @@ public class DbPlatformInfo { * statement. */ private boolean foreignKeysEmbedded = false; - + /** - * Determines whether foreign keys of a table read from a live database - * are alphabetically sorted. + * Determines whether foreign keys of a table read from a live database are + * alphabetically sorted. */ private boolean foreignKeysSorted = false; @@ -204,9 +204,9 @@ public class DbPlatformInfo { /** The text separating individual sql commands. */ private String sqlCommandDelimiter = ";"; - + private boolean requiresAutoCommitFalseToSetFetchSize = false; - + private boolean needsToSelectLobData; /** Contains non-default mappings from jdbc to native types. */ @@ -332,11 +332,11 @@ public boolean isPrimaryKeyEmbedded() { public void setPrimaryKeyEmbedded(boolean primaryKeyEmbedded) { this.primaryKeyEmbedded = primaryKeyEmbedded; } - + public boolean isForeignKeysSorted() { return foreignKeysSorted; } - + public void setForeignKeysSorted(boolean foreignKeySorted) { this.foreignKeysSorted = foreignKeySorted; } @@ -965,8 +965,8 @@ public void addNativeTypeMapping(String jdbcTypeName, String nativeType) { } } catch (Exception ex) { // ignore -> won't be defined - log.log(LogLevel.WARN, ex, - "Cannot add native type mapping for undefined jdbc type %s", jdbcTypeName); + log.log(LogLevel.WARN, ex, "Cannot add native type mapping for undefined jdbc type %s", + jdbcTypeName); } } @@ -997,8 +997,7 @@ public void addNativeTypeMapping(String jdbcTypeName, String nativeType, } } catch (Exception ex) { // ignore -> won't be defined - log.log( - LogLevel.WARN, + log.log(LogLevel.WARN, ex, "Cannot add native type mapping for undefined jdbc type %s , target jdbc type %s", jdbcTypeName, targetJdbcTypeName); @@ -1144,31 +1143,31 @@ public void setHasPrecisionAndScale(int sqlTypeCode, boolean hasPrecisionAndScal typesWithPrecisionAndScale.remove(new Integer(sqlTypeCode)); } } - + public void setDelimitedIdentifierModeOn(boolean delimitedIdentifierModeOn) { this.delimitedIdentifierModeOn = delimitedIdentifierModeOn; } - + public boolean isDelimitedIdentifierModeOn() { return delimitedIdentifierModeOn; - } - + } + public boolean isDateOverridesToTimestamp() { return dateOverridesToTimestamp; } - + public void setDateOverridesToTimestamp(boolean dateOverridesToTimestamp) { this.dateOverridesToTimestamp = dateOverridesToTimestamp; } - + public String getIdentifierQuoteString() { return identifierQuoteString; } - + public void setIdentifierQuoteString(String identifierQuoteString) { this.identifierQuoteString = identifierQuoteString; } - + public void setBlankCharColumnSpacePadded(boolean blankCharColumnSpacePadded) { this.blankCharColumnSpacePadded = blankCharColumnSpacePadded; } @@ -1184,7 +1183,7 @@ public void setEmptyStringNulled(boolean emptyStringNulled) { public boolean isEmptyStringNulled() { return emptyStringNulled; } - + public void setNonBlankCharColumnSpacePadded(boolean nonBlankCharColumnSpacePadded) { this.nonBlankCharColumnSpacePadded = nonBlankCharColumnSpacePadded; } @@ -1193,11 +1192,10 @@ public boolean isNonBlankCharColumnSpacePadded() { return nonBlankCharColumnSpacePadded; } - public boolean isSqlCommentsOn() { return sqlCommentsOn; } - + public void setSqlCommentsOn(boolean sqlCommentsOn) { this.sqlCommentsOn = sqlCommentsOn; } @@ -1205,24 +1203,24 @@ public void setSqlCommentsOn(boolean sqlCommentsOn) { public void setScriptModeOn(boolean scriptModeOn) { this.scriptModeOn = scriptModeOn; } - + public boolean isScriptModeOn() { return scriptModeOn; } - + public void setRequiresAutoCommitFalseToSetFetchSize( boolean requiresAutoCommitFalseToSetFetchSize) { this.requiresAutoCommitFalseToSetFetchSize = requiresAutoCommitFalseToSetFetchSize; } - + public boolean isRequiresAutoCommitFalseToSetFetchSize() { return requiresAutoCommitFalseToSetFetchSize; } - + public void setNeedsToSelectLobData(boolean needsToSelectLobData) { this.needsToSelectLobData = needsToSelectLobData; } - + public boolean isNeedsToSelectLobData() { return needsToSelectLobData; } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/IDbPlatform.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/IDbPlatform.java index 77ce17d792..ec21b52d59 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/IDbPlatform.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/IDbPlatform.java @@ -9,38 +9,39 @@ import org.jumpmind.symmetric.core.model.Table; import org.jumpmind.symmetric.core.sql.ISqlConnection; -public interface IDbPlatform { - +public interface IDbPlatform { + public DbPlatformInfo getPlatformInfo(); - + public Parameters getParameters(); - + public String getAlterScriptFor(Table... tables); - + public void alter(boolean failOnError, Table... tables); - + public Database findDatabase(String catalogName, String schemaName); - + public Table findTable(String tableName); - public Table findTable(String catalogName, String schemaName, String tableName, boolean useCached); + public Table findTable(String catalogName, String schemaName, String tableName, + boolean useCached); public List findTables(String catalogName, String schemaName); - + public Object[] getObjectValues(BinaryEncoding encoding, String[] values, Column[] orderedMetaData); - + public String getDefaultCatalog(); - + public String getDefaultSchema(); - + public SqlBuilder getSqlBuilder(); - + public ISqlConnection getSqlConnection(); - + public TriggerBuilder getTriggerBuilder(); - - public boolean isLob(int type); + + public boolean isLob(int type); /** * Returns the constraint name. This method takes care of length limitations @@ -69,6 +70,6 @@ public Object[] getObjectValues(BinaryEncoding encoding, String[] values, * @return The shortened version */ public String shortenName(String name, int desiredLength); - + public boolean isDataIntegrityException(Exception ex); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/SqlBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/SqlBuilder.java index 6f76211793..828c7d6a10 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/SqlBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/SqlBuilder.java @@ -2566,5 +2566,5 @@ protected void printIndent() { protected String createUniqueIdentifier() { return new UID().toString().replace(':', '_').replace('-', '_'); } - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/TriggerBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/TriggerBuilder.java index bc711e99fb..ecc41f5087 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/TriggerBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/TriggerBuilder.java @@ -77,7 +77,7 @@ public TriggerBuilder(IDbPlatform dbPlatform) { abstract protected boolean isTransactionIdOverrideSupported(); abstract protected String preProcessTriggerSqlClause(String sqlClause); - + abstract protected String getDataHasChangedCondition(); abstract protected String getSourceNodeExpression(); @@ -286,7 +286,7 @@ protected String replaceDefaultSchemaAndCatalog(Table table, String sql) { && defaultCatalog != null && defaultCatalog.length() > 0 ? defaultCatalog + "." : "", sql); } - + public String createTableExtractSql(TableToExtract tableToExtract, boolean supportsBigLobs) { return createTableExtractSql(tableToExtract, null, supportsBigLobs); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/alter/ModelComparator.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/alter/ModelComparator.java index de849bbc71..b2b250eb37 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/alter/ModelComparator.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/alter/ModelComparator.java @@ -136,8 +136,8 @@ public List compare(Database sourceModel, Database targetModel) { * The target table * @return The changes */ - public List compareTables(Database sourceModel, Table sourceTable, Database targetModel, - Table targetTable) { + public List compareTables(Database sourceModel, Table sourceTable, + Database targetModel, Table targetTable) { ArrayList changes = new ArrayList(); for (int fkIdx = 0; fkIdx < sourceTable.getForeignKeyCount(); fkIdx++) { @@ -175,8 +175,8 @@ public List compareTables(Database sourceModel, Table sourceTable, if (targetIndex == null) { if (log.isDebugEnabled()) { - log.debug("Index " + sourceIndex.getName() - + " needs to be removed from table " + sourceTable.getTableName()); + log.debug("Index " + sourceIndex.getName() + " needs to be removed from table " + + sourceTable.getTableName()); } changes.add(new RemoveIndexChange(sourceTable, sourceIndex)); } @@ -239,7 +239,8 @@ public List compareTables(Database sourceModel, Table sourceTable, if ((sourcePK.length == 0) && (targetPK.length > 0)) { if (log.isDebugEnabled()) { - log.debug("A primary key needs to be added to the table " + sourceTable.getTableName()); + log.debug("A primary key needs to be added to the table " + + sourceTable.getTableName()); } // we have to use the target table here because the primary key // might @@ -316,8 +317,8 @@ public List compareTables(Database sourceModel, Table sourceTable, * The target column * @return The changes */ - public List compareColumns(Table sourceTable, Column sourceColumn, Table targetTable, - Column targetColumn) { + public List compareColumns(Table sourceTable, Column sourceColumn, + Table targetTable, Column targetColumn) { ArrayList changes = new ArrayList(); if (targetColumn.getTypeCode() != sourceColumn.getTypeCode() diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/h2/H2SqlBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/h2/H2SqlBuilder.java index 3e8fd01084..c19c2ec4bd 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/h2/H2SqlBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/h2/H2SqlBuilder.java @@ -48,7 +48,6 @@ import org.jumpmind.symmetric.core.model.TypeMap; import org.jumpmind.symmetric.core.sql.SqlException; - /** * The SQL Builder for the H2 database. From patch changes) { + protected void processTableStructureChanges(Database currentModel, Database desiredModel, + Collection changes) { // Only drop columns that are not part of a primary key for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { TableChange change = changeIt.next(); - if ((change instanceof RemoveColumnChange) && ((RemoveColumnChange) change).getColumn().isPrimaryKey()) { + if ((change instanceof RemoveColumnChange) + && ((RemoveColumnChange) change).getColumn().isPrimaryKey()) { changeIt.remove(); } } @@ -102,12 +103,13 @@ protected void processTableStructureChanges(Database currentModel, Database desi for (Iterator changeIt = changes.iterator(); changeIt.hasNext();) { TableChange change = changeIt.next(); if (change instanceof AddColumnChange) { - addColumnChanges.add((AddColumnChange)change); + addColumnChanges.add((AddColumnChange) change); changeIt.remove(); } } - for (ListIterator changeIt = addColumnChanges.listIterator(addColumnChanges.size()); changeIt.hasPrevious();) { + for (ListIterator changeIt = addColumnChanges + .listIterator(addColumnChanges.size()); changeIt.hasPrevious();) { AddColumnChange addColumnChange = (AddColumnChange) changeIt.previous(); processChange(currentModel, desiredModel, addColumnChange); changeIt.remove(); @@ -119,9 +121,8 @@ protected void processTableStructureChanges(Database currentModel, Database desi RemoveColumnChange removeColumnChange = (RemoveColumnChange) change; processChange(currentModel, desiredModel, removeColumnChange); changeIt.remove(); - } - else if (change instanceof ColumnAutoIncrementChange) { - processAlterColumn(currentModel, change); + } else if (change instanceof ColumnAutoIncrementChange) { + processAlterColumn(currentModel, change); changeIt.remove(); } else if (change instanceof ColumnChange) { boolean needsAlter = true; @@ -144,7 +145,8 @@ else if (change instanceof ColumnAutoIncrementChange) { ColumnSizeChange sizeChange = (ColumnSizeChange) change; if (sizeChange.getNewScale() == 0 && sizeChange.getNewSize() == 0) { needsAlter = false; - } else if (sizeChange.getNewSize() == sizeChange.getChangedColumn().getSizeAsInt() + } else if (sizeChange.getNewSize() == sizeChange.getChangedColumn() + .getSizeAsInt() && sizeChange.getNewScale() == sizeChange.getChangedColumn().getScale()) { needsAlter = false; } @@ -157,13 +159,13 @@ else if (change instanceof ColumnAutoIncrementChange) { } } - + @Override - protected void writeColumnAutoIncrementStmt(Table table, Column column) { + protected void writeColumnAutoIncrementStmt(Table table, Column column) { print("AUTO_INCREMENT"); } - protected void processAlterColumn(Database currentModel, TableChange change) { + protected void processAlterColumn(Database currentModel, TableChange change) { Column column = null; if (change instanceof ColumnChange) { column = ((ColumnChange) change).getChangedColumn(); @@ -203,8 +205,8 @@ protected void processAlterColumn(Database currentModel, TableChange change) { * @param change * The change object */ - protected void processChange(Database currentModel, Database desiredModel, AddColumnChange change) - { + protected void processChange(Database currentModel, Database desiredModel, + AddColumnChange change) { print("ALTER TABLE "); printlnIdentifier(getTableName(change.getChangedTable())); printIndent(); @@ -228,8 +230,8 @@ protected void processChange(Database currentModel, Database desiredModel, AddCo * @param change * The change object */ - protected void processChange(Database currentModel, Database desiredModel, RemoveColumnChange change) - { + protected void processChange(Database currentModel, Database desiredModel, + RemoveColumnChange change) { print("ALTER TABLE "); printlnIdentifier(getTableName(change.getChangedTable())); printIndent(); @@ -240,7 +242,7 @@ protected void processChange(Database currentModel, Database desiredModel, Remov } @Override - protected void writeColumnDefaultValueStmt(Table table, Column column) { + protected void writeColumnDefaultValueStmt(Table table, Column column) { Object parsedDefault = column.getParsedDefaultValue(); if (parsedDefault != null) { @@ -255,22 +257,24 @@ protected void writeColumnDefaultValueStmt(Table table, Column column) { print(" DEFAULT "); writeColumnDefaultValue(table, column); } - } else if (getPlatformInfo().isDefaultValueUsedForIdentitySpec() && column.isAutoIncrement()) { + } else if (getPlatformInfo().isDefaultValueUsedForIdentitySpec() + && column.isAutoIncrement()) { print(" DEFAULT "); writeColumnDefaultValue(table, column); } else if (!StringUtils.isBlank(column.getDefaultValue())) { print(" DEFAULT "); writeColumnDefaultValue(table, column); } - } + } @Override - protected void printDefaultValue(Object defaultValue, int typeCode) { + protected void printDefaultValue(Object defaultValue, int typeCode) { if (defaultValue != null) { String defaultValueStr = defaultValue.toString(); - boolean shouldUseQuotes = !TypeMap.isNumericType(typeCode) && !defaultValueStr.startsWith("TO_DATE(") - && !defaultValue.equals("CURRENT_TIMESTAMP") && !defaultValue.equals("CURRENT_TIME") - && !defaultValue.equals("CURRENT_DATE"); + boolean shouldUseQuotes = !TypeMap.isNumericType(typeCode) + && !defaultValueStr.startsWith("TO_DATE(") + && !defaultValue.equals("CURRENT_TIMESTAMP") + && !defaultValue.equals("CURRENT_TIME") && !defaultValue.equals("CURRENT_DATE"); ; if (shouldUseQuotes) { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/oracle/OracleSqlBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/oracle/OracleSqlBuilder.java index 52a0ca1fb5..6002b09d40 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/oracle/OracleSqlBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/db/oracle/OracleSqlBuilder.java @@ -42,13 +42,13 @@ * The SQL Builder for Oracle. */ public class OracleSqlBuilder extends SqlBuilder { - + /** The regular expression pattern for ISO dates, i.e. 'YYYY-MM-DD'. */ private Pattern _isoDatePattern; - + /** The regular expression pattern for ISO times, i.e. 'HH:MI:SS'. */ private Pattern _isoTimePattern; - + /** * The regular expression pattern for ISO timestamps, i.e. 'YYYY-MM-DD * HH:MI:SS.fffffffff'. @@ -93,9 +93,9 @@ public void createTable(Database database, Table table) { /** * {@inheritDoc} */ - public void dropTable(Table table) - { - // The only difference to the Oracle 8/9 variant is the purge which prevents the + public void dropTable(Table table) { + // The only difference to the Oracle 8/9 variant is the purge which + // prevents the // table from being moved to the recycle bin (which is new in Oracle 10) List columns = table.getAutoIncrementColumns(); @@ -119,7 +119,7 @@ public void dropTable(Table table) * @param column * The column */ - protected void createAutoIncrementSequence(Table table, Column column) { + protected void createAutoIncrementSequence(Table table, Column column) { print("CREATE SEQUENCE "); printIdentifier(getConstraintName("seq", table, column.getName(), null)); printEndOfStatement(); @@ -133,7 +133,7 @@ protected void createAutoIncrementSequence(Table table, Column column) { * @param column * The column */ - protected void createAutoIncrementTrigger(Table table, Column column) { + protected void createAutoIncrementTrigger(Table table, Column column) { String columnName = getColumnName(column); String triggerName = getConstraintName("trg", table, column.getName(), null); @@ -195,7 +195,7 @@ protected void createAutoIncrementTrigger(Table table, Column column) { * @param column * The column */ - protected void dropAutoIncrementSequence(Table table, Column column) { + protected void dropAutoIncrementSequence(Table table, Column column) { print("DROP SEQUENCE "); printIdentifier(getConstraintName("seq", table, column.getName(), null)); printEndOfStatement(); @@ -209,7 +209,7 @@ protected void dropAutoIncrementSequence(Table table, Column column) { * @param column * The column */ - protected void dropAutoIncrementTrigger(Table table, Column column) { + protected void dropAutoIncrementTrigger(Table table, Column column) { print("DROP TRIGGER "); printIdentifier(getConstraintName("trg", table, column.getName(), null)); printEndOfStatement(); @@ -218,29 +218,28 @@ protected void dropAutoIncrementTrigger(Table table, Column column) { /** * {@inheritDoc} */ - protected void createTemporaryTable(Database database, Table table) - { + protected void createTemporaryTable(Database database, Table table) { createTable(database, table); } /** * {@inheritDoc} */ - protected void dropTemporaryTable(Database database, Table table) { + protected void dropTemporaryTable(Database database, Table table) { dropTable(table); } /** * {@inheritDoc} */ - public void dropExternalForeignKeys(Table table) { + public void dropExternalForeignKeys(Table table) { // no need to as we drop the table with CASCASE CONSTRAINTS } /** * {@inheritDoc} */ - public void writeExternalIndexDropStmt(Table table, Index index) { + public void writeExternalIndexDropStmt(Table table, Index index) { // Index names in Oracle are unique to a schema and hence Oracle does // not // use the ON clause @@ -252,7 +251,7 @@ public void writeExternalIndexDropStmt(Table table, Index index) { /** * {@inheritDoc} */ - protected void printDefaultValue(Object defaultValue, int typeCode) { + protected void printDefaultValue(Object defaultValue, int typeCode) { if (defaultValue != null) { String defaultValueStr = defaultValue.toString(); boolean shouldUseQuotes = !TypeMap.isNumericType(typeCode) @@ -274,7 +273,7 @@ protected void printDefaultValue(Object defaultValue, int typeCode) { */ protected String getNativeDefaultValue(Column column) { if (column.getTypeCode() == Types.BIT) { - return TypeMap.convertToBoolean(column.getDefaultValue()).toString(); + return TypeMap.convertToBoolean(column.getDefaultValue()).toString(); } // Oracle does not accept ISO formats, so we have to convert an ISO spec // if we find one @@ -300,7 +299,7 @@ else if (column.getTypeCode() == Types.DATE) { /** * {@inheritDoc} */ - protected void writeColumnAutoIncrementStmt(Table table, Column column) { + protected void writeColumnAutoIncrementStmt(Table table, Column column) { // we're using sequences instead } @@ -333,7 +332,7 @@ public String getSelectLastIdentityValues(Table table) { * {@inheritDoc} */ protected void processTableStructureChanges(Database currentModel, Database desiredModel, - Table sourceTable, Table targetTable, List changes) { + Table sourceTable, Table targetTable, List changes) { // While Oracle has an ALTER TABLE MODIFY statement, it is somewhat // limited // esp. if there is data in the table, so we don't use it @@ -414,7 +413,7 @@ protected void processTableStructureChanges(Database currentModel, Database desi * The change object */ protected void processChange(Database currentModel, Database desiredModel, - AddColumnChange change) { + AddColumnChange change) { print("ALTER TABLE "); printlnIdentifier(getTableName(change.getChangedTable())); printIndent(); @@ -439,7 +438,7 @@ protected void processChange(Database currentModel, Database desiredModel, * The change object */ protected void processChange(Database currentModel, Database desiredModel, - RemoveColumnChange change) { + RemoveColumnChange change) { if (change.getColumn().isAutoIncrement()) { dropAutoIncrementTrigger(change.getChangedTable(), change.getColumn()); dropAutoIncrementSequence(change.getChangedTable(), change.getColumn()); @@ -464,7 +463,7 @@ protected void processChange(Database currentModel, Database desiredModel, * The change object */ protected void processChange(Database currentModel, Database desiredModel, - RemovePrimaryKeyChange change) { + RemovePrimaryKeyChange change) { print("ALTER TABLE "); printlnIdentifier(getTableName(change.getChangedTable())); printIndent(); @@ -472,6 +471,5 @@ protected void processChange(Database currentModel, Database desiredModel, printEndOfStatement(); change.apply(currentModel, getPlatformInfo().isDelimitedIdentifierModeOn()); } - - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/ext/IExtensionPoint.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/ext/IExtensionPoint.java index 0ef48d52a0..88b70a5981 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/ext/IExtensionPoint.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/ext/IExtensionPoint.java @@ -16,18 +16,20 @@ * "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 org.jumpmind.symmetric.core.ext; - + * under the License. + */ +package org.jumpmind.symmetric.core.ext; + /** - * This is a marker interface that identifies ways that SymmetricDS can be extended. + * This is a marker interface that identifies ways that SymmetricDS can be + * extended. */ -public interface IExtensionPoint { - - /** - * Allow the plug-in implementation to specific whether the SymmetricDS - * runtime should auto register it or if it will register itself. - */ - public boolean isAutoRegister(); - +public interface IExtensionPoint { + + /** + * Allow the plug-in implementation to specific whether the SymmetricDS + * runtime should auto register it or if it will register itself. + */ + public boolean isAutoRegister(); + } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/io/IoException.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/io/IoException.java index 9a193b9594..d738328389 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/io/IoException.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/io/IoException.java @@ -11,12 +11,11 @@ public class IoException extends RuntimeException { public IoException(IOException ex) { super(ex); } - + public IoException(XmlPullParserException ex) { super(ex); } - - + public IoException(String msg) { super(msg); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Batch.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Batch.java index 6ded5f012c..66059fe181 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Batch.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Batch.java @@ -35,7 +35,7 @@ public long incrementLineCount() { public long incrementFallbackInsertCount() { return ++fallbackInsertCount; } - + public long incrementFallbackUpdateWithNewKeysCount() { return ++fallbackUpdateWithNewKeysCount; } @@ -51,26 +51,27 @@ public long incrementMissingDeleteCount() { public long incrementInsertCount() { return ++insertCount; } - + public long decrementInsertCount(int number) { - return insertCount-=number; + return insertCount -= number; } public long incrementUpdateCount() { return ++updateCount; } - + public long incrementDeleteCount() { return ++deleteCount; } - + public long incrementSqlCount() { return ++sqlCount; } - + public long incrementOtherCount() { return ++otherCount; } + public void incrementFilterMillis(long millis) { filterMillis += millis; } @@ -122,23 +123,23 @@ public Date getStartTime() { public void setStartTime(Date startTime) { this.startTime = startTime; } - + public long getDeleteCount() { return deleteCount; } - + public long getInsertCount() { return insertCount; } - + public long getOtherCount() { return otherCount; } - + public long getSqlCount() { return sqlCount; } - + public long getUpdateCount() { return updateCount; } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Column.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Column.java index 00de55495e..907dcb4567 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Column.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Column.java @@ -35,7 +35,7 @@ * @version $Revision: 463305 $ */ public class Column implements Cloneable, Serializable { - + /** Unique ID for serialization purposes. */ private static final long serialVersionUID = -6226348998874210093L; @@ -81,11 +81,12 @@ public class Column implements Cloneable, Serializable { private String defaultValue; private String jdbcTypeName; - - public Column() { + + public Column() { } - - public Column(String name, String type, String size, boolean autoincrement, boolean required, boolean primaryKey) { + + public Column(String name, String type, String size, boolean autoincrement, boolean required, + boolean primaryKey) { setName(name); setType(type); setSize(size); @@ -93,7 +94,7 @@ public Column(String name, String type, String size, boolean autoincrement, bool setRequired(required); setPrimaryKey(primaryKey); } - + /** * Returns the name of the column. * diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Data.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Data.java index 879a344787..86af1a4343 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Data.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Data.java @@ -118,7 +118,7 @@ public String[] toParsedOldData() { public String[] toParsedPkData() { return getData("pkData", pkData); } - + public void clearPkData() { this.pkData = null; this.removeData("pkData"); @@ -161,7 +161,7 @@ public String getPkData() { } public void setPkData(String pkData) { - this.pkData = pkData; + this.pkData = pkData; } public String getOldData() { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/DataEventType.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/DataEventType.java index e915b759b6..79c4c8843b 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/DataEventType.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/DataEventType.java @@ -16,86 +16,88 @@ * "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 org.jumpmind.symmetric.core.model; + * under the License. + */ -public enum DataEventType { - - /** - * Insert DML type. - */ - INSERT("I"), - - /** - * Update DML type. - */ - UPDATE("U"), - - /** - * Delete DML type. - */ - DELETE("D"), - - /** - * An event that indicates that a table needs to be reloaded. - */ - RELOAD("R"), - - /** - * An event that indicates that the data payload has a sql statement that needs to be executed. This is more of a - * remote control feature (that would have been very handy in past lives). - */ - SQL("S"), - - /** - * An event that indicates that the data payload is a table creation. - */ - CREATE("C"), - - /** - * An event that indicates that all SymmetricDS configuration table data should be streamed to the client. - */ - CONFIG("X"), - - /** - * An event the indicates that the data payload is going to be a Java bean shell script that is to be run at the - * client. - */ - BSH("B"); - - private String code; - - DataEventType(String code) { - this.code = code; - } - - public String getCode() { - return this.code; - } - - public static DataEventType getEventType(String s) { - if (s.equals(INSERT.getCode())) { - return INSERT; - } else if (s.equals(UPDATE.getCode())) { - return UPDATE; - } else if (s.equals(DELETE.getCode())) { - return DELETE; - } else if (s.equals(RELOAD.getCode())) { - return RELOAD; - } else if (s.equals(SQL.getCode())) { - return SQL; - } else if (s.equals(CREATE.getCode())) { - return CREATE; - } else if (s.equals(CONFIG.getCode())) { - return CONFIG; - } else if (s.equals(RELOAD.getCode())) { - return RELOAD; - } else if (s.equals(BSH.getCode())) { - return BSH; - } else { - throw new IllegalStateException(String.format("Invalid data event type of %s", s)); - } - } +package org.jumpmind.symmetric.core.model; + +public enum DataEventType { + + /** + * Insert DML type. + */ + INSERT("I"), + + /** + * Update DML type. + */ + UPDATE("U"), + + /** + * Delete DML type. + */ + DELETE("D"), + + /** + * An event that indicates that a table needs to be reloaded. + */ + RELOAD("R"), + + /** + * An event that indicates that the data payload has a sql statement that + * needs to be executed. This is more of a remote control feature (that + * would have been very handy in past lives). + */ + SQL("S"), + + /** + * An event that indicates that the data payload is a table creation. + */ + CREATE("C"), + + /** + * An event that indicates that all SymmetricDS configuration table data + * should be streamed to the client. + */ + CONFIG("X"), + + /** + * An event the indicates that the data payload is going to be a Java bean + * shell script that is to be run at the client. + */ + BSH("B"); + + private String code; + + DataEventType(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + public static DataEventType getEventType(String s) { + if (s.equals(INSERT.getCode())) { + return INSERT; + } else if (s.equals(UPDATE.getCode())) { + return UPDATE; + } else if (s.equals(DELETE.getCode())) { + return DELETE; + } else if (s.equals(RELOAD.getCode())) { + return RELOAD; + } else if (s.equals(SQL.getCode())) { + return SQL; + } else if (s.equals(CREATE.getCode())) { + return CREATE; + } else if (s.equals(CONFIG.getCode())) { + return CONFIG; + } else if (s.equals(RELOAD.getCode())) { + return RELOAD; + } else if (s.equals(BSH.getCode())) { + return BSH; + } else { + throw new IllegalStateException(String.format("Invalid data event type of %s", s)); + } + } } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Database.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Database.java index f217cfd8f2..48ea0e23e6 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Database.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Database.java @@ -38,7 +38,7 @@ * objects stored in the tables. */ public class Database implements Serializable, Cloneable { - + private static final long serialVersionUID = -1L; /** The name of the database model. */ @@ -49,8 +49,8 @@ public class Database implements Serializable, Cloneable { private String _version; /** The tables. */ private ArrayList
_tables = new ArrayList
(); - - private Map tableIndexCache = new HashMap(); + + private Map tableIndexCache = new HashMap(); /** * Adds all tables from the other database to this database. Note that the @@ -66,8 +66,8 @@ public void mergeWith(Database otherDb) throws SqlException { if (findTable(table.getTableName()) != null) { // TODO: It might make more sense to log a warning and overwrite // the table (or merge them) ? - throw new SqlException("Cannot merge the models because table " + table.getTableName() - + " already defined in this model"); + throw new SqlException("Cannot merge the models because table " + + table.getTableName() + " already defined in this model"); } addTable(table.copy()); } @@ -185,7 +185,7 @@ public void addTable(int idx, Table table) { _tables.add(idx, table); } } - + /** * Adds the given tables. * @@ -416,7 +416,7 @@ public Table findTable(String name, boolean caseSensitive) { } return null; } - + /** * Catalog & Schema aware finder */ @@ -466,7 +466,7 @@ public Table findTable(String catalogName, String schemaName, String tableName) public void resetTableIndexCache() { tableIndexCache.clear(); - } + } /** * {@inheritDoc} @@ -486,19 +486,14 @@ public Object clone() throws CloneNotSupportedException { /** * {@inheritDoc} */ - public boolean equals(Object obj) - { - if (obj instanceof Database) - { - Database other = (Database)obj; + public boolean equals(Object obj) { + if (obj instanceof Database) { + Database other = (Database) obj; // Note that this compares case sensitive - return new EqualsBuilder().append(_name, other._name) - .append(_tables, other._tables) - .isEquals(); - } - else - { + return new EqualsBuilder().append(_name, other._name).append(_tables, other._tables) + .isEquals(); + } else { return false; } } @@ -506,13 +501,10 @@ public boolean equals(Object obj) /** * {@inheritDoc} */ - public int hashCode() - { - return new HashCodeBuilder(17, 37).append(_name) - .append(_tables) - .toHashCode(); + public int hashCode() { + return new HashCodeBuilder(17, 37).append(_name).append(_tables).toHashCode(); } - + /** * {@inheritDoc} */ diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Index.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Index.java index 0fda8e6051..0125e04705 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Index.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Index.java @@ -119,12 +119,15 @@ public void removeColumn(int idx) { * {@inheritDoc} */ public abstract Object clone() throws CloneNotSupportedException; - + /** - * Compares this index to the given one while ignoring the case of identifiers. + * Compares this index to the given one while ignoring the case of + * identifiers. * - * @param otherIndex The other index - * @return true if this index is equal (ignoring case) to the given one + * @param otherIndex + * The other index + * @return true if this index is equal (ignoring case) to the + * given one */ public abstract boolean equalsIgnoreCase(Index otherIndex); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/IndexColumn.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/IndexColumn.java index 2d63b69b81..acfb2c5759 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/IndexColumn.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/IndexColumn.java @@ -162,47 +162,37 @@ public Object clone() throws CloneNotSupportedException { /** * {@inheritDoc} */ - public boolean equals(Object obj) - { - if (obj instanceof IndexColumn) - { - IndexColumn other = (IndexColumn)obj; - - return new EqualsBuilder().append(name, other.name) - .append(size, other.size) - .isEquals(); - } - else - { + public boolean equals(Object obj) { + if (obj instanceof IndexColumn) { + IndexColumn other = (IndexColumn) obj; + + return new EqualsBuilder().append(name, other.name).append(size, other.size).isEquals(); + } else { return false; } } /** - * Compares this index column to the given one while ignoring the case of identifiers. + * Compares this index column to the given one while ignoring the case of + * identifiers. * - * @param other The other index column - * @return true if this index column is equal (ignoring case) to the given one + * @param other + * The other index column + * @return true if this index column is equal (ignoring case) + * to the given one */ - public boolean equalsIgnoreCase(IndexColumn other) - { + public boolean equalsIgnoreCase(IndexColumn other) { return new EqualsBuilder().append(name.toUpperCase(), other.name.toUpperCase()) - .append(size, other.size) - .isEquals(); + .append(size, other.size).isEquals(); } /** * {@inheritDoc} */ - public int hashCode() - { - return new HashCodeBuilder(17, 37).append(name) - .append(size) - .toHashCode(); + public int hashCode() { + return new HashCodeBuilder(17, 37).append(name).append(size).toHashCode(); } - - /** * {@inheritDoc} */ diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Parameters.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Parameters.java index 2d96d6663b..202576a537 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Parameters.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Parameters.java @@ -8,19 +8,19 @@ public class Parameters extends HashMap { private static final long serialVersionUID = 1L; - + public final static String LOADER_MAX_ROWS_BEFORE_COMMIT = "dataloader.max.rows.before.commit"; - + public final static String LOADER_MAX_ROWS_BEFORE_BATCH_FLUSH = "dataloader.max.rows.before.batch.flush"; - + public final static String LOADER_USE_BATCHING = "dataloader.use.batching"; - + public final static String LOADER_ENABLE_FALLBACK_UPDATE = "dataloader.enable.fallback.update"; - + public final static String LOADER_ENABLE_FALLBACK_INSERT = "dataloader.enable.fallback.insert"; - + public final static String LOADER_ALLOW_MISSING_DELETES = "dataloader.allow.missing.delete"; - + public final static String LOADER_DONT_INCLUDE_PKS_IN_UPDATE = "dataloader.dont.include.keys.in.update.statement"; public final static String DB_METADATA_IGNORE_CASE = "db.metadata.ignore.case"; diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Table.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Table.java index 4687d39b75..0a491e6590 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Table.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Table.java @@ -54,7 +54,7 @@ public Table(String catalogName, String schemaName, String tableName) { this.setSchemaName(schemaName); this.setTableName(tableName); } - + public Table(String tableName) { this.setTableName(tableName); } @@ -686,7 +686,7 @@ public void reOrderColumns(Column[] targetOrder, boolean copyPrimaryKeys) { public String getFullyQualifiedTableName() { return getQualifiedTablePrefix() + this.tableName; } - + public String getQualifiedTablePrefix() { String fullyQualified = ""; if (!StringUtils.isBlank(schemaName)) { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Trigger.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Trigger.java index df627a458d..78d4067020 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Trigger.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/Trigger.java @@ -16,11 +16,11 @@ * "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 org.jumpmind.symmetric.core.model; - + * under the License. + */ + +package org.jumpmind.symmetric.core.model; + import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; @@ -31,404 +31,401 @@ import org.jumpmind.symmetric.core.common.Log; import org.jumpmind.symmetric.core.common.LogFactory; import org.jumpmind.symmetric.core.common.StringUtils; - -/** + +/** * Defines the trigger via which a table will be synchronized. - */ + */ public class Trigger implements Serializable { - private static final long serialVersionUID = 1L; - - static final Log logger = LogFactory.getLog(Trigger.class); - - private static int maxTriggerId; - - private static final String DEFAULT_CONDITION = "1=1"; - - private String triggerId; - - private String sourceTableName; - - private String sourceSchemaName; - - private String sourceCatalogName; - - private String channelId; - - private boolean syncOnUpdate = true; - - private boolean syncOnInsert = true; - - private boolean syncOnDelete = true; - - private boolean syncOnIncomingBatch = false; - - private String nameForInsertTrigger; - - private String nameForUpdateTrigger; - - private String nameForDeleteTrigger; - - private String syncOnUpdateCondition = DEFAULT_CONDITION; - - private String syncOnInsertCondition = DEFAULT_CONDITION; - - private String syncOnDeleteCondition = DEFAULT_CONDITION; - - private String excludedColumnNames = null; - - /** - * This is a SQL expression that creates a unique id which the sync process - * can use to 'group' events together and commit together. - */ - private String txIdExpression = null; - - private String externalSelect = null; - - private Date createTime; - - private Date lastUpdateTime; - - private String lastUpdateBy; - - public Trigger() { - triggerId = Integer.toString(maxTriggerId++); - } - - public Trigger(String tableName) { - this.sourceTableName = tableName; - } - - final public String qualifiedSourceTableName() { - return qualifiedSourceTablePrefix() + sourceTableName; - } - - final public String qualifiedSourceTablePrefix() { - String schemaPlus = (getSourceSchemaName() != null ? getSourceSchemaName() - + "." : ""); - String catalogPlus = (getSourceCatalogName() != null ? getSourceCatalogName() - + "." : "") + schemaPlus; - return catalogPlus; - } - - /** - * When dealing with columns, always use this method to order the columns so - * that the primary keys are first. - */ - public Column[] orderColumnsForTable(Table table) { - List excludedColumnNames = getExcludedColumnNamesAsList(); - Column[] pks = table.getPrimaryKeyColumnsArray(); - Column[] cols = table.getColumns(); - List orderedColumns = new ArrayList(cols.length); - for (int i = 0; i < pks.length; i++) { - orderedColumns.add(pks[i]); - } - for (int i = 0; i < cols.length; i++) { - Column col = cols[i]; - if (!col.isPrimaryKey() && !excludedColumnNames.contains(col.getName().toLowerCase())) { - orderedColumns.add(col); - } - } - return orderedColumns.toArray(new Column[orderedColumns.size()]); - } - - /** - * Get a list of the natural indexes of the excluded columns - */ - public int[] getExcludedColumnIndexes(Table table) { - if (excludedColumnNames != null && excludedColumnNames.length() > 0) { - StringTokenizer tokenizer = new StringTokenizer(excludedColumnNames, ","); - int[] indexes = new int[tokenizer.countTokens()]; - Column[] columns = table.getColumns(); - List columnNames = new ArrayList(columns.length); - for (Column column : columns) { - columnNames.add(column.getName().toLowerCase()); - } - int i = 0; - while (tokenizer.hasMoreTokens()) { - indexes[i++] = columnNames.indexOf(tokenizer.nextToken().toLowerCase()); - } - return indexes; - } else { - return new int[0]; - } - } - - @SuppressWarnings("unchecked") - private List getExcludedColumnNamesAsList() { - if (excludedColumnNames != null && excludedColumnNames.length() > 0) { - StringTokenizer tokenizer = new StringTokenizer(excludedColumnNames, ","); - List columnNames = new ArrayList(tokenizer.countTokens()); - while (tokenizer.hasMoreTokens()) { - columnNames.add(tokenizer.nextToken().toLowerCase()); - } - return columnNames; - } else { - return Collections.EMPTY_LIST; - } - } - - public boolean hasChangedSinceLastTriggerBuild(Date lastTriggerBuildTime) { - return lastTriggerBuildTime == null || getLastUpdateTime() == null - || lastTriggerBuildTime.before(getLastUpdateTime()); - } - - - public String getTriggerId() { - return triggerId; - } - - public void setTriggerId(String triggerId) { - this.triggerId = triggerId; - if (StringUtils.isNotBlank(triggerId) && StringUtils.isNumeric(triggerId)) { - int id = Integer.parseInt(triggerId); - if (id >= maxTriggerId) { - maxTriggerId = id + 1; - } - } - } - - - public String getSourceTableName() { - return sourceTableName; - } - - public void setSourceTableName(String sourceTableName) { - this.sourceTableName = sourceTableName; - } - - public String getSourceSchemaName() { - return sourceSchemaName; - } - - public void setSourceSchemaName(String sourceSchemaName) { - this.sourceSchemaName = sourceSchemaName; - } - - public String getSourceCatalogName() { - return sourceCatalogName; - } - - public void setSourceCatalogName(String sourceCatalogName) { - this.sourceCatalogName = sourceCatalogName; - } - - public String getChannelId() { - return channelId; - } - - public void setChannelId(String channelId) { - this.channelId = channelId; - } - - public boolean isSyncOnUpdate() { - return syncOnUpdate; - } - - public void setSyncOnUpdate(boolean syncOnUpdate) { - this.syncOnUpdate = syncOnUpdate; - } - - public boolean isSyncOnInsert() { - return syncOnInsert; - } - - public void setSyncOnInsert(boolean syncOnInsert) { - this.syncOnInsert = syncOnInsert; - } - - public boolean isSyncOnDelete() { - return syncOnDelete; - } - - public void setSyncOnDelete(boolean syncOnDelete) { - this.syncOnDelete = syncOnDelete; - } - - public boolean isSyncOnIncomingBatch() { - return syncOnIncomingBatch; - } - - public void setSyncOnIncomingBatch(boolean syncOnIncomingBatch) { - this.syncOnIncomingBatch = syncOnIncomingBatch; - } - - public String getNameForInsertTrigger() { - return nameForInsertTrigger; - } - - public void setNameForInsertTrigger(String nameForInsertTrigger) { - this.nameForInsertTrigger = nameForInsertTrigger; - } - - public String getNameForUpdateTrigger() { - return nameForUpdateTrigger; - } - - public void setNameForUpdateTrigger(String nameForUpdateTrigger) { - this.nameForUpdateTrigger = nameForUpdateTrigger; - } - - public String getNameForDeleteTrigger() { - return nameForDeleteTrigger; - } - - public void setNameForDeleteTrigger(String nameForDeleteTrigger) { - this.nameForDeleteTrigger = nameForDeleteTrigger; - } - - public String getSyncOnUpdateCondition() { - return syncOnUpdateCondition; - } - - public void setSyncOnUpdateCondition(String syncOnUpdateCondition) { - this.syncOnUpdateCondition = syncOnUpdateCondition; - } - - public String getSyncOnInsertCondition() { - return syncOnInsertCondition; - } - - public void setSyncOnInsertCondition(String syncOnInsertCondition) { - this.syncOnInsertCondition = syncOnInsertCondition; - } - - public String getSyncOnDeleteCondition() { - return syncOnDeleteCondition; - } - - public void setSyncOnDeleteCondition(String syncOnDeleteCondition) { - this.syncOnDeleteCondition = syncOnDeleteCondition; - } - - public String getExcludedColumnNames() { - return excludedColumnNames; - } - - public void setExcludedColumnNames(String excludedColumnNames) { - this.excludedColumnNames = excludedColumnNames; - } - - public String getTxIdExpression() { - return txIdExpression; - } - - public void setTxIdExpression(String txIdExpression) { - this.txIdExpression = txIdExpression; - } - - public String getExternalSelect() { - return externalSelect; - } - - public void setExternalSelect(String externalSelect) { - this.externalSelect = externalSelect; - } - - public void setLastUpdateBy(String updatedBy) { - this.lastUpdateBy = updatedBy; - } - - public String getLastUpdateBy() { - return lastUpdateBy; - } - - public Date getLastUpdateTime() { - return lastUpdateTime; - } - - public void setLastUpdateTime(Date lastModifiedOn) { - this.lastUpdateTime = lastModifiedOn; - } - - public Date getCreateTime() { - return createTime; - } - - public void setCreateTime(Date createdOn) { - this.createTime = createdOn; - } - - public long toHashedValue() { - long hashedValue = triggerId != null ? triggerId.hashCode() : 0; - if (null != sourceTableName) { - hashedValue += sourceTableName.hashCode(); - } - - if (null != channelId) { - hashedValue += channelId.hashCode(); - } - - if (null != sourceSchemaName) { - hashedValue += sourceSchemaName.hashCode(); - } - - if (null != sourceCatalogName) { - hashedValue += sourceCatalogName.hashCode(); - } - - hashedValue += syncOnUpdate ? 1 : 0; - hashedValue += syncOnInsert ? 1 : 0; - hashedValue += syncOnDelete ? 1 : 0; - hashedValue += syncOnIncomingBatch ? 1 : 0; - - if (null != nameForInsertTrigger) { - hashedValue += nameForInsertTrigger.hashCode(); - } - - if (null != nameForUpdateTrigger) { - hashedValue += nameForUpdateTrigger.hashCode(); - } - - if (null != nameForDeleteTrigger) { - hashedValue += nameForDeleteTrigger.hashCode(); - } - - if (null != syncOnUpdateCondition) { - hashedValue += syncOnUpdateCondition.hashCode(); - } - - if (null != syncOnInsertCondition) { - hashedValue += syncOnInsertCondition.hashCode(); - } - - if (null != syncOnDeleteCondition) { - hashedValue += syncOnDeleteCondition.hashCode(); - } - - if (null != excludedColumnNames) { - hashedValue += excludedColumnNames.hashCode(); - } - - if (null != txIdExpression) { - hashedValue += txIdExpression.hashCode(); - } - - return hashedValue; - } - - public boolean isSame(Trigger trigger) { - return isSame(sourceCatalogName, trigger.sourceCatalogName) - && isSame(sourceSchemaName, trigger.sourceSchemaName) - && trigger.sourceTableName.equalsIgnoreCase(sourceTableName); - } - - protected boolean isSame(String one, String two) { - return (one == null && two == null) || (one != null && two != null && one.equals(two)); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Trigger && triggerId != null) { - return triggerId.equals(((Trigger) obj).triggerId); - } else { - return super.equals(obj); - } - } - - @Override - public int hashCode() { - return triggerId != null ? triggerId.hashCode() : super.hashCode(); - } - + private static final long serialVersionUID = 1L; + + static final Log logger = LogFactory.getLog(Trigger.class); + + private static int maxTriggerId; + + private static final String DEFAULT_CONDITION = "1=1"; + + private String triggerId; + + private String sourceTableName; + + private String sourceSchemaName; + + private String sourceCatalogName; + + private String channelId; + + private boolean syncOnUpdate = true; + + private boolean syncOnInsert = true; + + private boolean syncOnDelete = true; + + private boolean syncOnIncomingBatch = false; + + private String nameForInsertTrigger; + + private String nameForUpdateTrigger; + + private String nameForDeleteTrigger; + + private String syncOnUpdateCondition = DEFAULT_CONDITION; + + private String syncOnInsertCondition = DEFAULT_CONDITION; + + private String syncOnDeleteCondition = DEFAULT_CONDITION; + + private String excludedColumnNames = null; + + /** + * This is a SQL expression that creates a unique id which the sync process + * can use to 'group' events together and commit together. + */ + private String txIdExpression = null; + + private String externalSelect = null; + + private Date createTime; + + private Date lastUpdateTime; + + private String lastUpdateBy; + + public Trigger() { + triggerId = Integer.toString(maxTriggerId++); + } + + public Trigger(String tableName) { + this.sourceTableName = tableName; + } + + final public String qualifiedSourceTableName() { + return qualifiedSourceTablePrefix() + sourceTableName; + } + + final public String qualifiedSourceTablePrefix() { + String schemaPlus = (getSourceSchemaName() != null ? getSourceSchemaName() + "." : ""); + String catalogPlus = (getSourceCatalogName() != null ? getSourceCatalogName() + "." : "") + + schemaPlus; + return catalogPlus; + } + + /** + * When dealing with columns, always use this method to order the columns so + * that the primary keys are first. + */ + public Column[] orderColumnsForTable(Table table) { + List excludedColumnNames = getExcludedColumnNamesAsList(); + Column[] pks = table.getPrimaryKeyColumnsArray(); + Column[] cols = table.getColumns(); + List orderedColumns = new ArrayList(cols.length); + for (int i = 0; i < pks.length; i++) { + orderedColumns.add(pks[i]); + } + for (int i = 0; i < cols.length; i++) { + Column col = cols[i]; + if (!col.isPrimaryKey() && !excludedColumnNames.contains(col.getName().toLowerCase())) { + orderedColumns.add(col); + } + } + return orderedColumns.toArray(new Column[orderedColumns.size()]); + } + + /** + * Get a list of the natural indexes of the excluded columns + */ + public int[] getExcludedColumnIndexes(Table table) { + if (excludedColumnNames != null && excludedColumnNames.length() > 0) { + StringTokenizer tokenizer = new StringTokenizer(excludedColumnNames, ","); + int[] indexes = new int[tokenizer.countTokens()]; + Column[] columns = table.getColumns(); + List columnNames = new ArrayList(columns.length); + for (Column column : columns) { + columnNames.add(column.getName().toLowerCase()); + } + int i = 0; + while (tokenizer.hasMoreTokens()) { + indexes[i++] = columnNames.indexOf(tokenizer.nextToken().toLowerCase()); + } + return indexes; + } else { + return new int[0]; + } + } + + @SuppressWarnings("unchecked") + private List getExcludedColumnNamesAsList() { + if (excludedColumnNames != null && excludedColumnNames.length() > 0) { + StringTokenizer tokenizer = new StringTokenizer(excludedColumnNames, ","); + List columnNames = new ArrayList(tokenizer.countTokens()); + while (tokenizer.hasMoreTokens()) { + columnNames.add(tokenizer.nextToken().toLowerCase()); + } + return columnNames; + } else { + return Collections.EMPTY_LIST; + } + } + + public boolean hasChangedSinceLastTriggerBuild(Date lastTriggerBuildTime) { + return lastTriggerBuildTime == null || getLastUpdateTime() == null + || lastTriggerBuildTime.before(getLastUpdateTime()); + } + + public String getTriggerId() { + return triggerId; + } + + public void setTriggerId(String triggerId) { + this.triggerId = triggerId; + if (StringUtils.isNotBlank(triggerId) && StringUtils.isNumeric(triggerId)) { + int id = Integer.parseInt(triggerId); + if (id >= maxTriggerId) { + maxTriggerId = id + 1; + } + } + } + + public String getSourceTableName() { + return sourceTableName; + } + + public void setSourceTableName(String sourceTableName) { + this.sourceTableName = sourceTableName; + } + + public String getSourceSchemaName() { + return sourceSchemaName; + } + + public void setSourceSchemaName(String sourceSchemaName) { + this.sourceSchemaName = sourceSchemaName; + } + + public String getSourceCatalogName() { + return sourceCatalogName; + } + + public void setSourceCatalogName(String sourceCatalogName) { + this.sourceCatalogName = sourceCatalogName; + } + + public String getChannelId() { + return channelId; + } + + public void setChannelId(String channelId) { + this.channelId = channelId; + } + + public boolean isSyncOnUpdate() { + return syncOnUpdate; + } + + public void setSyncOnUpdate(boolean syncOnUpdate) { + this.syncOnUpdate = syncOnUpdate; + } + + public boolean isSyncOnInsert() { + return syncOnInsert; + } + + public void setSyncOnInsert(boolean syncOnInsert) { + this.syncOnInsert = syncOnInsert; + } + + public boolean isSyncOnDelete() { + return syncOnDelete; + } + + public void setSyncOnDelete(boolean syncOnDelete) { + this.syncOnDelete = syncOnDelete; + } + + public boolean isSyncOnIncomingBatch() { + return syncOnIncomingBatch; + } + + public void setSyncOnIncomingBatch(boolean syncOnIncomingBatch) { + this.syncOnIncomingBatch = syncOnIncomingBatch; + } + + public String getNameForInsertTrigger() { + return nameForInsertTrigger; + } + + public void setNameForInsertTrigger(String nameForInsertTrigger) { + this.nameForInsertTrigger = nameForInsertTrigger; + } + + public String getNameForUpdateTrigger() { + return nameForUpdateTrigger; + } + + public void setNameForUpdateTrigger(String nameForUpdateTrigger) { + this.nameForUpdateTrigger = nameForUpdateTrigger; + } + + public String getNameForDeleteTrigger() { + return nameForDeleteTrigger; + } + + public void setNameForDeleteTrigger(String nameForDeleteTrigger) { + this.nameForDeleteTrigger = nameForDeleteTrigger; + } + + public String getSyncOnUpdateCondition() { + return syncOnUpdateCondition; + } + + public void setSyncOnUpdateCondition(String syncOnUpdateCondition) { + this.syncOnUpdateCondition = syncOnUpdateCondition; + } + + public String getSyncOnInsertCondition() { + return syncOnInsertCondition; + } + + public void setSyncOnInsertCondition(String syncOnInsertCondition) { + this.syncOnInsertCondition = syncOnInsertCondition; + } + + public String getSyncOnDeleteCondition() { + return syncOnDeleteCondition; + } + + public void setSyncOnDeleteCondition(String syncOnDeleteCondition) { + this.syncOnDeleteCondition = syncOnDeleteCondition; + } + + public String getExcludedColumnNames() { + return excludedColumnNames; + } + + public void setExcludedColumnNames(String excludedColumnNames) { + this.excludedColumnNames = excludedColumnNames; + } + + public String getTxIdExpression() { + return txIdExpression; + } + + public void setTxIdExpression(String txIdExpression) { + this.txIdExpression = txIdExpression; + } + + public String getExternalSelect() { + return externalSelect; + } + + public void setExternalSelect(String externalSelect) { + this.externalSelect = externalSelect; + } + + public void setLastUpdateBy(String updatedBy) { + this.lastUpdateBy = updatedBy; + } + + public String getLastUpdateBy() { + return lastUpdateBy; + } + + public Date getLastUpdateTime() { + return lastUpdateTime; + } + + public void setLastUpdateTime(Date lastModifiedOn) { + this.lastUpdateTime = lastModifiedOn; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createdOn) { + this.createTime = createdOn; + } + + public long toHashedValue() { + long hashedValue = triggerId != null ? triggerId.hashCode() : 0; + if (null != sourceTableName) { + hashedValue += sourceTableName.hashCode(); + } + + if (null != channelId) { + hashedValue += channelId.hashCode(); + } + + if (null != sourceSchemaName) { + hashedValue += sourceSchemaName.hashCode(); + } + + if (null != sourceCatalogName) { + hashedValue += sourceCatalogName.hashCode(); + } + + hashedValue += syncOnUpdate ? 1 : 0; + hashedValue += syncOnInsert ? 1 : 0; + hashedValue += syncOnDelete ? 1 : 0; + hashedValue += syncOnIncomingBatch ? 1 : 0; + + if (null != nameForInsertTrigger) { + hashedValue += nameForInsertTrigger.hashCode(); + } + + if (null != nameForUpdateTrigger) { + hashedValue += nameForUpdateTrigger.hashCode(); + } + + if (null != nameForDeleteTrigger) { + hashedValue += nameForDeleteTrigger.hashCode(); + } + + if (null != syncOnUpdateCondition) { + hashedValue += syncOnUpdateCondition.hashCode(); + } + + if (null != syncOnInsertCondition) { + hashedValue += syncOnInsertCondition.hashCode(); + } + + if (null != syncOnDeleteCondition) { + hashedValue += syncOnDeleteCondition.hashCode(); + } + + if (null != excludedColumnNames) { + hashedValue += excludedColumnNames.hashCode(); + } + + if (null != txIdExpression) { + hashedValue += txIdExpression.hashCode(); + } + + return hashedValue; + } + + public boolean isSame(Trigger trigger) { + return isSame(sourceCatalogName, trigger.sourceCatalogName) + && isSame(sourceSchemaName, trigger.sourceSchemaName) + && trigger.sourceTableName.equalsIgnoreCase(sourceTableName); + } + + protected boolean isSame(String one, String two) { + return (one == null && two == null) || (one != null && two != null && one.equals(two)); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Trigger && triggerId != null) { + return triggerId.equals(((Trigger) obj).triggerId); + } else { + return super.equals(obj); + } + } + + @Override + public int hashCode() { + return triggerId != null ? triggerId.hashCode() : super.hashCode(); + } + } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerHistory.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerHistory.java index 27b844e2d2..629e162e3a 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerHistory.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerHistory.java @@ -16,275 +16,273 @@ * "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 org.jumpmind.symmetric.core.model; - + * under the License. + */ + +package org.jumpmind.symmetric.core.model; + import java.io.Serializable; import java.util.Date; - - -/** - * Maps to the table sync audit table which tracks the history of sync trigger - * creation.

This table also tracks the columns and the primary keys as of - * the create date so that if the table definition changes while we still have - * events to process (as may be the case when distributing events to remote - * locations), then we still have the history of what the columns and primary - * keys were at the time. - * + +/** + * Maps to the table sync audit table which tracks the history of sync trigger + * creation. + *

+ * This table also tracks the columns and the primary keys as of the create date + * so that if the table definition changes while we still have events to process + * (as may be the case when distributing events to remote locations), then we + * still have the history of what the columns and primary keys were at the time. + * * - */ + */ public class TriggerHistory extends AbstractCsvData implements Serializable { - private static final long serialVersionUID = 1L; - - private int triggerHistoryId; - - private Trigger trigger; - - private String sourceTableName; - - private String sourceSchemaName; - - private String sourceCatalogName; - - private Date createTime; - - private String columnNames; - - private String pkColumnNames; - - private String nameForInsertTrigger; - - private String nameForUpdateTrigger; - - private String nameForDeleteTrigger; - - private Date inactiveTime; - - - /** - * This is a hash based on the tablename, column names, and column data - * types. It is used to effectively version a table so we know when it - * changes. - */ - private int tableHash; - - /** - * This is a hash based on the values in the trigger configuration table. - */ - private long triggerRowHash; - - private TriggerReBuildReason lastTriggerBuildReason; - - public TriggerHistory() { - createTime = new Date(); - } - - public TriggerHistory(String tableName, String pkColumnNames, String columnNames) { - this.sourceTableName = tableName; - this.pkColumnNames = pkColumnNames; - this.columnNames = columnNames; - } - - public TriggerHistory(Table table, Trigger trigger) { - this(table,trigger,null); - } - - public TriggerHistory(Table table, Trigger trigger, TriggerReBuildReason reason) { - this(); - this.sourceTableName = table.getTableName(); - this.lastTriggerBuildReason = reason; - this.columnNames = getCommaDeliminatedColumns(trigger.orderColumnsForTable(table)); - this.sourceSchemaName = trigger.getSourceSchemaName(); - this.sourceCatalogName = trigger.getSourceCatalogName(); - this.trigger = trigger; - this.pkColumnNames = getCommaDeliminatedColumns(table.getPrimaryKeyColumnsArray()); - this.triggerRowHash = trigger.toHashedValue(); - // set primary key equal to all the columns to make data sync work for - // tables with no primary keys - if (pkColumnNames == null) { - pkColumnNames = columnNames; - } - - tableHash = calculateTableHashFor(table); - } - - public static int calculateTableHashFor(Table table) { - final int PRIME = 31; - int result = 1; - result = PRIME * result + table.getTableName().hashCode(); - result = PRIME * result + calculateHashForColumns(PRIME, table.getColumns()); - result = PRIME * result + calculateHashForColumns(PRIME, table.getPrimaryKeyColumnsArray()); - return result; - } - - private static int calculateHashForColumns(final int PRIME, Column[] cols) { - int result = 1; - if (cols != null && cols.length > 0) { - for (Column column : cols) { - result = PRIME * result + column.getName().hashCode(); - result = PRIME * result + column.getType().hashCode(); - result = PRIME * result + column.getSizeAsInt(); - } - } - return result; - } - - private String getCommaDeliminatedColumns(Column[] cols) { - StringBuilder columns = new StringBuilder(); - if (cols != null && cols.length > 0) { - for (Column column : cols) { - columns.append(column.getName()); - columns.append(","); - } - columns.replace(columns.length() - 1, columns.length(), ""); - return columns.toString(); - } else { - return null; - } - } - - public String getTriggerNameForDmlType(DataEventType type) { - switch (type) { - case INSERT: - return getNameForInsertTrigger(); - case UPDATE: - return getNameForUpdateTrigger(); - case DELETE: - return getNameForDeleteTrigger(); - } - throw new IllegalStateException(); - } - - public String[] getParsedColumnNames() { - return getData("columnNames", columnNames); - } - - public String[] getParsedPkColumnNames() { - return getData("pkColumnNames", pkColumnNames); - } - - public int getTableHash() { - return tableHash; - } - - public void setTableHash(int tableHash) { - this.tableHash = tableHash; - } - - public String getSourceTableName() { - return sourceTableName; - } - - public void setSourceTableName(String tableName) { - this.sourceTableName = tableName; - } - - public String getColumnNames() { - return columnNames; - } - - public void setColumnNames(String allColumnData) { - this.columnNames = allColumnData; - } - - public Date getCreateTime() { - return createTime; - } - - public void setCreateTime(Date createTime) { - this.createTime = createTime; - } - - public TriggerReBuildReason getLastTriggerBuildReason() { - return lastTriggerBuildReason; - } - - public void setLastTriggerBuildReason(TriggerReBuildReason lastTriggerBuildReason) { - this.lastTriggerBuildReason = lastTriggerBuildReason; - } - - public String getPkColumnNames() { - return pkColumnNames; - } - - public void setPkColumnNames(String pkColumnData) { - this.pkColumnNames = pkColumnData; - } - - public int getTriggerHistoryId() { - return triggerHistoryId; - } - - public void setTriggerHistoryId(int tableSyncAuditId) { - this.triggerHistoryId = tableSyncAuditId; - } - - public String getNameForDeleteTrigger() { - return nameForDeleteTrigger; - } - - public void setNameForDeleteTrigger(String nameForDeleteTrigger) { - this.nameForDeleteTrigger = nameForDeleteTrigger; - } - - public String getNameForInsertTrigger() { - return nameForInsertTrigger; - } - - public void setNameForInsertTrigger(String nameForInsertTrigger) { - this.nameForInsertTrigger = nameForInsertTrigger; - } - - public String getNameForUpdateTrigger() { - return nameForUpdateTrigger; - } - - public void setNameForUpdateTrigger(String nameForUpdateTrigger) { - this.nameForUpdateTrigger = nameForUpdateTrigger; - } - - public String getSourceSchemaName() { - return sourceSchemaName; - } - - public void setSourceSchemaName(String schemaName) { - this.sourceSchemaName = schemaName; - } + private static final long serialVersionUID = 1L; + + private int triggerHistoryId; + + private Trigger trigger; + + private String sourceTableName; + + private String sourceSchemaName; + + private String sourceCatalogName; + + private Date createTime; + + private String columnNames; + + private String pkColumnNames; + + private String nameForInsertTrigger; + + private String nameForUpdateTrigger; + + private String nameForDeleteTrigger; + + private Date inactiveTime; + + /** + * This is a hash based on the tablename, column names, and column data + * types. It is used to effectively version a table so we know when it + * changes. + */ + private int tableHash; + + /** + * This is a hash based on the values in the trigger configuration table. + */ + private long triggerRowHash; + + private TriggerReBuildReason lastTriggerBuildReason; + + public TriggerHistory() { + createTime = new Date(); + } + + public TriggerHistory(String tableName, String pkColumnNames, String columnNames) { + this.sourceTableName = tableName; + this.pkColumnNames = pkColumnNames; + this.columnNames = columnNames; + } + + public TriggerHistory(Table table, Trigger trigger) { + this(table, trigger, null); + } + + public TriggerHistory(Table table, Trigger trigger, TriggerReBuildReason reason) { + this(); + this.sourceTableName = table.getTableName(); + this.lastTriggerBuildReason = reason; + this.columnNames = getCommaDeliminatedColumns(trigger.orderColumnsForTable(table)); + this.sourceSchemaName = trigger.getSourceSchemaName(); + this.sourceCatalogName = trigger.getSourceCatalogName(); + this.trigger = trigger; + this.pkColumnNames = getCommaDeliminatedColumns(table.getPrimaryKeyColumnsArray()); + this.triggerRowHash = trigger.toHashedValue(); + // set primary key equal to all the columns to make data sync work for + // tables with no primary keys + if (pkColumnNames == null) { + pkColumnNames = columnNames; + } + + tableHash = calculateTableHashFor(table); + } + + public static int calculateTableHashFor(Table table) { + final int PRIME = 31; + int result = 1; + result = PRIME * result + table.getTableName().hashCode(); + result = PRIME * result + calculateHashForColumns(PRIME, table.getColumns()); + result = PRIME * result + calculateHashForColumns(PRIME, table.getPrimaryKeyColumnsArray()); + return result; + } + + private static int calculateHashForColumns(final int PRIME, Column[] cols) { + int result = 1; + if (cols != null && cols.length > 0) { + for (Column column : cols) { + result = PRIME * result + column.getName().hashCode(); + result = PRIME * result + column.getType().hashCode(); + result = PRIME * result + column.getSizeAsInt(); + } + } + return result; + } + + private String getCommaDeliminatedColumns(Column[] cols) { + StringBuilder columns = new StringBuilder(); + if (cols != null && cols.length > 0) { + for (Column column : cols) { + columns.append(column.getName()); + columns.append(","); + } + columns.replace(columns.length() - 1, columns.length(), ""); + return columns.toString(); + } else { + return null; + } + } + + public String getTriggerNameForDmlType(DataEventType type) { + switch (type) { + case INSERT: + return getNameForInsertTrigger(); + case UPDATE: + return getNameForUpdateTrigger(); + case DELETE: + return getNameForDeleteTrigger(); + } + throw new IllegalStateException(); + } + + public String[] getParsedColumnNames() { + return getData("columnNames", columnNames); + } + + public String[] getParsedPkColumnNames() { + return getData("pkColumnNames", pkColumnNames); + } + + public int getTableHash() { + return tableHash; + } + + public void setTableHash(int tableHash) { + this.tableHash = tableHash; + } + + public String getSourceTableName() { + return sourceTableName; + } + + public void setSourceTableName(String tableName) { + this.sourceTableName = tableName; + } + + public String getColumnNames() { + return columnNames; + } + + public void setColumnNames(String allColumnData) { + this.columnNames = allColumnData; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public TriggerReBuildReason getLastTriggerBuildReason() { + return lastTriggerBuildReason; + } + + public void setLastTriggerBuildReason(TriggerReBuildReason lastTriggerBuildReason) { + this.lastTriggerBuildReason = lastTriggerBuildReason; + } + + public String getPkColumnNames() { + return pkColumnNames; + } + + public void setPkColumnNames(String pkColumnData) { + this.pkColumnNames = pkColumnData; + } + + public int getTriggerHistoryId() { + return triggerHistoryId; + } + + public void setTriggerHistoryId(int tableSyncAuditId) { + this.triggerHistoryId = tableSyncAuditId; + } + + public String getNameForDeleteTrigger() { + return nameForDeleteTrigger; + } + + public void setNameForDeleteTrigger(String nameForDeleteTrigger) { + this.nameForDeleteTrigger = nameForDeleteTrigger; + } + + public String getNameForInsertTrigger() { + return nameForInsertTrigger; + } + + public void setNameForInsertTrigger(String nameForInsertTrigger) { + this.nameForInsertTrigger = nameForInsertTrigger; + } + + public String getNameForUpdateTrigger() { + return nameForUpdateTrigger; + } + + public void setNameForUpdateTrigger(String nameForUpdateTrigger) { + this.nameForUpdateTrigger = nameForUpdateTrigger; + } + + public String getSourceSchemaName() { + return sourceSchemaName; + } + + public void setSourceSchemaName(String schemaName) { + this.sourceSchemaName = schemaName; + } public Trigger getTrigger() { return trigger; } - + public void setTrigger(Trigger trigger) { this.trigger = trigger; - } - - public Date getInactiveTime() { - return inactiveTime; - } - - public void setInactiveTime(Date inactiveTime) { - this.inactiveTime = inactiveTime; - } - - public String getSourceCatalogName() { - return sourceCatalogName; - } - - public void setSourceCatalogName(String sourceCatalogName) { - this.sourceCatalogName = sourceCatalogName; - } - - public long getTriggerRowHash() { - return triggerRowHash; - } - - public void setTriggerRowHash(long triggerRowHash) { - this.triggerRowHash = triggerRowHash; - } - - + } + + public Date getInactiveTime() { + return inactiveTime; + } + + public void setInactiveTime(Date inactiveTime) { + this.inactiveTime = inactiveTime; + } + + public String getSourceCatalogName() { + return sourceCatalogName; + } + + public void setSourceCatalogName(String sourceCatalogName) { + this.sourceCatalogName = sourceCatalogName; + } + + public long getTriggerRowHash() { + return triggerRowHash; + } + + public void setTriggerRowHash(long triggerRowHash) { + this.triggerRowHash = triggerRowHash; + } + } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerReBuildReason.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerReBuildReason.java index 7da2dc7290..4dab5495f8 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerReBuildReason.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TriggerReBuildReason.java @@ -20,7 +20,6 @@ package org.jumpmind.symmetric.core.model; - /** * {@link TriggerHistory} */ diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TypeMap.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TypeMap.java index 8e6814ff7a..580229024e 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TypeMap.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/TypeMap.java @@ -244,8 +244,7 @@ public static String getJdbcTypeName(int typeCode) { * @param category * The type category */ - protected static void registerJdbcType(int typeCode, String typeName, - TypeCategory category) { + protected static void registerJdbcType(int typeCode, String typeName, TypeCategory category) { Integer typeId = new Integer(typeCode); typeNameToTypeCode.put(typeName.toUpperCase(), typeId); diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/UniqueIndex.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/UniqueIndex.java index cfbbd66483..9cbe79819e 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/UniqueIndex.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/model/UniqueIndex.java @@ -25,21 +25,19 @@ /** * Provides compatibility with Torque-style xml with separate <index> and - * <unique> tags, but adds no functionality. All indexes are treated the + * <unique> tags, but adds no functionality. All indexes are treated the * same by the Table. * * @version $Revision: 463305 $ */ -public class UniqueIndex extends Index -{ +public class UniqueIndex extends Index { /** Unique ID for serialization purposes. */ private static final long serialVersionUID = -4097003126550294993L; /** * {@inheritDoc} */ - public boolean isUnique() - { + public boolean isUnique() { return true; } @@ -47,29 +45,23 @@ public boolean isUnique() * {@inheritDoc} */ @SuppressWarnings("unchecked") - public Object clone() throws CloneNotSupportedException - { + public Object clone() throws CloneNotSupportedException { UniqueIndex result = new UniqueIndex(); - result._name = _name; - result._columns = (ArrayList)_columns.clone(); + result._name = _name; + result._columns = (ArrayList) _columns.clone(); return result; } - + /** * {@inheritDoc} */ - public boolean equals(Object obj) - { - if (obj instanceof UniqueIndex) - { - UniqueIndex other = (UniqueIndex)obj; - - return new EqualsBuilder().append(_name, other._name) - .append(_columns, other._columns) - .isEquals(); - } - else - { + public boolean equals(Object obj) { + if (obj instanceof UniqueIndex) { + UniqueIndex other = (UniqueIndex) obj; + + return new EqualsBuilder().append(_name, other._name).append(_columns, other._columns) + .isEquals(); + } else { return false; } } @@ -77,22 +69,17 @@ public boolean equals(Object obj) /** * {@inheritDoc} */ - public boolean equalsIgnoreCase(Index other) - { - if (other instanceof UniqueIndex) - { - UniqueIndex otherIndex = (UniqueIndex)other; - - boolean checkName = (_name != null) && (_name.length() > 0) && - (otherIndex._name != null) && (otherIndex._name.length() > 0); - - if ((!checkName || _name.equalsIgnoreCase(otherIndex._name)) && - (getColumnCount() == otherIndex.getColumnCount())) - { - for (int idx = 0; idx < getColumnCount(); idx++) - { - if (!getColumn(idx).equalsIgnoreCase(otherIndex.getColumn(idx))) - { + public boolean equalsIgnoreCase(Index other) { + if (other instanceof UniqueIndex) { + UniqueIndex otherIndex = (UniqueIndex) other; + + boolean checkName = (_name != null) && (_name.length() > 0) + && (otherIndex._name != null) && (otherIndex._name.length() > 0); + + if ((!checkName || _name.equalsIgnoreCase(otherIndex._name)) + && (getColumnCount() == otherIndex.getColumnCount())) { + for (int idx = 0; idx < getColumnCount(); idx++) { + if (!getColumn(idx).equalsIgnoreCase(otherIndex.getColumn(idx))) { return false; } } @@ -105,17 +92,14 @@ public boolean equalsIgnoreCase(Index other) /** * {@inheritDoc} */ - public int hashCode() - { + public int hashCode() { return _columns.hashCode(); } - /** * {@inheritDoc} */ - public String toString() - { + public String toString() { StringBuffer result = new StringBuffer(); result.append("Unique index [name="); @@ -130,15 +114,13 @@ public String toString() /** * {@inheritDoc} */ - public String toVerboseString() - { + public String toVerboseString() { StringBuffer result = new StringBuffer(); result.append("Unique index ["); result.append(getName()); result.append("] columns:"); - for (int idx = 0; idx < getColumnCount(); idx++) - { + for (int idx = 0; idx < getColumnCount(); idx++) { result.append(" "); result.append(getColumn(idx).toString()); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IColumnFilter.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IColumnFilter.java index fd0f1c689c..cff5846b25 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IColumnFilter.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IColumnFilter.java @@ -16,42 +16,45 @@ * "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 org.jumpmind.symmetric.core.process; - + * under the License. + */ + +package org.jumpmind.symmetric.core.process; + import org.jumpmind.symmetric.core.ext.IExtensionPoint; import org.jumpmind.symmetric.core.model.Column; import org.jumpmind.symmetric.core.model.Table; - -/** - * This is an extension point that can be implemented to filter out columns from - * use by the dataloader. One column filter may be added per target table. - *

- * Please implement {@link ITableColumnFilter} instead of this class directly if - * you want the extension to be auto discovered. - * + +/** + * This is an extension point that can be implemented to filter out columns from + * use by the dataloader. One column filter may be added per target table.

+ * Please implement {@link ITableColumnFilter} instead of this class directly if + * you want the extension to be auto discovered. * - */ -public interface IColumnFilter extends IExtensionPoint { - - /** - * This method is always called first. Typically, you must cache the column - * index you are interested in order to be able to filter the column value - * as well. - *

- * @param columnNames If column names are going to change, then you should change the name in this reference and return it as the return value. - * @return The columnName that the data loader will use to build its dml. - */ - public Column[] filterColumnsNames(T ctx, Table table, Column[] columns); - - /** - * This method is always called after - * {@link IColumnFilter#filterColumnsNames(DmlType, String[])}. It should - * perform the same filtering under the same conditions for the values as - * was done for the column names. - * - * @return the column values - */ - public Object[] filterColumnsValues(T ctx, Table table, Object[] values); + * + */ +public interface IColumnFilter extends IExtensionPoint { + + /** + * This method is always called first. Typically, you must cache the column + * index you are interested in order to be able to filter the column value + * as well. + *

+ * + * @param columnNames + * If column names are going to change, then you should change + * the name in this reference and return it as the return value. + * @return The columnName that the data loader will use to build its dml. + */ + public Column[] filterColumnsNames(T ctx, Table table, Column[] columns); + + /** + * This method is always called after + * {@link IColumnFilter#filterColumnsNames(DmlType, String[])}. It should + * perform the same filtering under the same conditions for the values as + * was done for the column names. + * + * @return the column values + */ + public Object[] filterColumnsValues(T ctx, Table table, Object[] values); } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IDataFilter.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IDataFilter.java index b9a68748e2..053fe9f4bb 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IDataFilter.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/IDataFilter.java @@ -16,25 +16,23 @@ * "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 org.jumpmind.symmetric.core.process; + * under the License. + */ +package org.jumpmind.symmetric.core.process; import org.jumpmind.symmetric.core.ext.IExtensionPoint; import org.jumpmind.symmetric.core.model.Data; - - /** - * Extension point that can be use to change or prevent a {@link Data} object from - * being processes + * Extension point that can be use to change or prevent a {@link Data} object + * from being processes */ -public interface IDataFilter extends IExtensionPoint { - - /** - * @return true if the row should be loaded. false if the filter has handled - * the row and it should be ignored. - */ - public boolean filter(T context, Data data); - - +public interface IDataFilter extends IExtensionPoint { + + /** + * @return true if the row should be loaded. false if the filter has handled + * the row and it should be ignored. + */ + public boolean filter(T context, Data data); + } \ No newline at end of file diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/csv/CsvDataReader.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/csv/CsvDataReader.java index d53f2bc1db..094b8ef918 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/csv/CsvDataReader.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/csv/CsvDataReader.java @@ -8,7 +8,6 @@ public class CsvDataReader implements IDataReader { - public void open(DataContext context) { // TODO Auto-generated method stub diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataReader.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataReader.java index a41e0e0484..8f0972dbc3 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataReader.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataReader.java @@ -8,36 +8,30 @@ public class SqlDataReader implements IDataReader { - public void close(DataContext context) { } - - + public DataContext createDataContext() { return null; } - - + public Batch nextBatch(DataContext context) { return null; } - - + public Data nextData(DataContext context) { return null; } - - + public Table nextTable(DataContext context) { return null; } - - + public void open(DataContext context) { - + } } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriter.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriter.java index a79d2f7352..95ffe87940 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriter.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriter.java @@ -16,6 +16,7 @@ import org.jumpmind.symmetric.core.model.Parameters; import org.jumpmind.symmetric.core.model.Table; import org.jumpmind.symmetric.core.process.DataContext; +import org.jumpmind.symmetric.core.process.DataProcessor; import org.jumpmind.symmetric.core.process.IColumnFilter; import org.jumpmind.symmetric.core.process.IDataFilter; import org.jumpmind.symmetric.core.process.IDataWriter; @@ -25,7 +26,10 @@ import org.jumpmind.symmetric.core.sql.StatementBuilder; import org.jumpmind.symmetric.core.sql.StatementBuilder.DmlType; -// Notes: Inserts and deletes try to use jdbc batching by default +/** + * An {@link IDataWriter} used by {@link DataProcessor}s to write {@link Data} + * to a relational database. + */ public class SqlDataWriter implements IDataWriter { final Log log = LogFactory.getLog(getClass()); @@ -60,28 +64,15 @@ public SqlDataWriter(IDbPlatform platform, Parameters parameters) { this(platform, parameters, null, null); } + public SqlDataWriter(IDbPlatform platform, Settings settings) { + this(platform, settings, null, null); + } + public SqlDataWriter(IDbPlatform platform, Parameters parameters, List> columnFilters, List> dataFilters) { this(platform, new Settings(), columnFilters, dataFilters); - - settings.maxRowsBeforeBatchFlush = parameters.getInt( - Parameters.LOADER_MAX_ROWS_BEFORE_BATCH_FLUSH, 10); - settings.enableFallbackForInsert = parameters.is(Parameters.LOADER_ENABLE_FALLBACK_INSERT, - true); - settings.enableFallbackForUpdate = parameters.is(Parameters.LOADER_ENABLE_FALLBACK_UPDATE, - true); - settings.allowMissingDeletes = parameters.is(Parameters.LOADER_ALLOW_MISSING_DELETES, true); - settings.useBatching = parameters.is(Parameters.LOADER_USE_BATCHING, true); - settings.maxRowsBeforeCommit = parameters.getInt(Parameters.LOADER_MAX_ROWS_BEFORE_COMMIT, - 1000); - settings.usePrimaryKeysFromSource = parameters.is(Parameters.DB_USE_PKS_FROM_SOURCE, true); - settings.dontIncludeKeysInUpdateStatement = parameters.is( - Parameters.LOADER_DONT_INCLUDE_PKS_IN_UPDATE, false); - } - - public SqlDataWriter(IDbPlatform platform, Settings settings) { - this(platform, settings, null, null); + populateSettings(parameters); } public SqlDataWriter(IDbPlatform platform, Settings settings, @@ -90,7 +81,7 @@ public SqlDataWriter(IDbPlatform platform, Settings settings, this.platform = platform; this.columnFilters = columnFilters; this.dataFilters = dataFilters; - this.settings = settings; + this.settings = settings == null ? new Settings() : settings; } public DataContext createDataContext() { @@ -134,11 +125,11 @@ public void writeData(Data data) { protected void writeData(Data data, boolean batchMode) { - if (lastData != null && lastData.getEventType() != data.getEventType()) { - transaction.flush(); - } - try { + if (requireNewStatement(data)) { + flush(); + } + switch (data.getEventType()) { case INSERT: processInsert(data, batchMode); @@ -165,17 +156,7 @@ protected void writeData(Data data, boolean batchMode) { } } catch (DataIntegrityViolationException ex) { - if (transaction.isInBatchMode() && isCorrectForIntegrityViolation(data)) { - // if we were in batch mode, then resubmit in non-batch mode so - // we can fallback. - List failed = transaction.getUnflushedMarkers(); - batch.decrementInsertCount(failed.size()); - for (Data data2 : failed) { - writeData(data2, false); - } - } else { - throw ex; - } + handleDataIntegrityViolationException(ex); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { @@ -183,6 +164,51 @@ protected void writeData(Data data, boolean batchMode) { } } + protected void handleDataIntegrityViolationException(DataIntegrityViolationException ex) { + if (transaction.isInBatchMode()) { + resendFailedDataInNonBatchMode(); + } else { + throw ex; + } + } + + protected void flush() { + try { + transaction.flush(); + } catch (DataIntegrityViolationException ex) { + handleDataIntegrityViolationException(ex); + } + } + + protected boolean requireNewStatement(Data data) { + return statementBuilder == null || lastData == null + || lastData.getEventType() != data.getEventType(); + } + + protected void resendFailedDataInNonBatchMode() { + List failed = transaction.getUnflushedMarkers(true); + batch.decrementInsertCount(failed.size()); + for (Data data2 : failed) { + writeData(data2, false); + } + } + + protected void populateSettings(Parameters parameters) { + settings.maxRowsBeforeBatchFlush = parameters.getInt( + Parameters.LOADER_MAX_ROWS_BEFORE_BATCH_FLUSH, 10); + settings.enableFallbackForInsert = parameters.is(Parameters.LOADER_ENABLE_FALLBACK_INSERT, + true); + settings.enableFallbackForUpdate = parameters.is(Parameters.LOADER_ENABLE_FALLBACK_UPDATE, + true); + settings.allowMissingDeletes = parameters.is(Parameters.LOADER_ALLOW_MISSING_DELETES, true); + settings.useBatching = parameters.is(Parameters.LOADER_USE_BATCHING, true); + settings.maxRowsBeforeCommit = parameters.getInt(Parameters.LOADER_MAX_ROWS_BEFORE_COMMIT, + 1000); + settings.usePrimaryKeysFromSource = parameters.is(Parameters.DB_USE_PKS_FROM_SOURCE, true); + settings.dontIncludeKeysInUpdateStatement = parameters.is( + Parameters.LOADER_DONT_INCLUDE_PKS_IN_UPDATE, false); + } + protected boolean filterData(Data data, DataContext ctx) { boolean continueToLoad = true; if (dataFilters != null) { @@ -259,7 +285,7 @@ protected int executeUpdateSql(Data data) { columnValues = (String[]) changedColumnValueList .toArray(new String[changedColumnValueList.size()]); String[] values = (String[]) ArrayUtils.addAll(columnValues, getPkData(data)); - transaction.prepare(this.statementBuilder.getSql(), -1, false); + transaction.prepare(this.statementBuilder.getSql(), -1); return execute(data, values); } else { // There was no change to apply @@ -282,23 +308,20 @@ protected String[] getPkData(Data data) { } protected void executeInsertSql(Data data, boolean batchMode) { - if (this.statementBuilder == null || this.lastData == null - || this.lastData.getEventType() != DataEventType.INSERT) { + transaction.setInBatchMode(batchMode); + if (requireNewStatement(data)) { this.statementBuilder = getStatementBuilder(DmlType.INSERT, null, targetTable.getColumns()); - transaction.prepare(this.statementBuilder.getSql(), settings.maxRowsBeforeBatchFlush, - batchMode); + transaction.prepare(this.statementBuilder.getSql(), settings.maxRowsBeforeBatchFlush); } execute(data, data.toParsedRowData()); } protected int executeDeleteSql(Data data, boolean batchMode) { - if (this.statementBuilder == null || this.lastData == null - || this.lastData.getEventType() != DataEventType.DELETE) { + if (requireNewStatement(data)) { this.statementBuilder = getStatementBuilder(DmlType.DELETE, targetTable.getPrimaryKeyColumnsArray(), targetTable.getColumns()); - transaction.prepare(this.statementBuilder.getSql(), settings.maxRowsBeforeBatchFlush, - batchMode); + transaction.prepare(this.statementBuilder.getSql(), settings.maxRowsBeforeBatchFlush); } return execute(data, data.toParsedPkData()); } @@ -428,6 +451,7 @@ final private StatementBuilder getStatementBuilder(DmlType dmlType, Column[] loo } private void commit() { + flush(); this.transaction.commit(); uncommittedRows = 0; } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReader.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReader.java index 697ccb703c..08e598b72b 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReader.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReader.java @@ -75,7 +75,7 @@ public Data nextData(DataContext context) { TriggerBuilder triggerBuilder = this.dbPlatform.getTriggerBuilder(); String sql = triggerBuilder.createTableExtractSql(tableToRead, this.dbPlatform .getParameters().is(Parameters.DB_SUPPORT_BIG_LOBS, false)); - this.readCursor = connection.query(sql, new DataMapper()); + this.readCursor = connection.queryForCursor(sql, new DataMapper()); } if (readCursor != null) { data = readCursor.next(); diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/resources/IResourceFactory.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/resources/IResourceFactory.java index 5435b29265..803c583ce1 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/resources/IResourceFactory.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/resources/IResourceFactory.java @@ -1,4 +1,4 @@ - package org.jumpmind.symmetric.core.resources; +package org.jumpmind.symmetric.core.resources; import java.io.InputStream; @@ -7,7 +7,7 @@ public interface IResourceFactory { public InputStream getRawResource(String name); - + public XmlPullParser getXml(String name); - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlConnection.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlConnection.java index 9eacc801d1..2937b2af5e 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlConnection.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlConnection.java @@ -1,5 +1,8 @@ package org.jumpmind.symmetric.core.sql; +import java.util.List; +import java.util.Map; + import org.jumpmind.symmetric.core.db.IDbPlatform; /** @@ -13,6 +16,19 @@ public interface ISqlConnection { public int queryForInt(String sql); + public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper, + Object[] values, int[] types); + + public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper); + + public List> query(String sql); + + public List> query(String sql, Object[] args, int[] types); + + public List query(String sql, ISqlRowMapper mapper); + + public List query(String sql, ISqlRowMapper mapper, Object[] args, int[] types); + public int update(String sql); public int update(String... sql); @@ -21,15 +37,10 @@ public interface ISqlConnection { public int update(String sql, Object[] values, int[] types); - public ISqlReadCursor query(String sql, ISqlRowMapper mapper, - Object[] values, int[] types); - - public ISqlReadCursor query(String sql, ISqlRowMapper mapper); - public void testConnection(); public SqlException translate(Exception ex); - + public ISqlTransaction startSqlTransaction(); } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlReadCursor.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlReadCursor.java index 90acaf7c75..6470ed86d0 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlReadCursor.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlReadCursor.java @@ -3,6 +3,7 @@ public interface ISqlReadCursor { public T next(); + public void close(); - + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlTransaction.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlTransaction.java index 2ede8dbe02..7a6216ea74 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlTransaction.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/ISqlTransaction.java @@ -3,24 +3,26 @@ import java.util.List; public interface ISqlTransaction { - + public boolean isInBatchMode(); - + + public void setInBatchMode(boolean batchMode); + public void commit(); - + public void rollback(); - + public void close(); - + /** * Each time the SQL changes it needs to be submitted for preparation */ - public void prepare(String sql, int flushSize, boolean batchMode); - + public void prepare(String sql, int flushSize); + public int update(T marker, Object[] values, int[] types); - + public int flush(); - - public List getUnflushedMarkers(); - + + public List getUnflushedMarkers(boolean clear); + } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlConstants.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlConstants.java index ad18eedce7..9d891c5642 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlConstants.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlConstants.java @@ -5,6 +5,6 @@ abstract public class SqlConstants { public static final String ALWAYS_TRUE_CONDITION = "1=1"; public static final int DEFAULT_QUERY_TIMEOUT_SECONDS = 300; - + public static final int DEFAULT_STREAMING_FETCH_SIZE = 1000; } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlException.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlException.java index a1d34e3611..1cae9d2e2d 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlException.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlException.java @@ -18,6 +18,6 @@ public SqlException(String message) { public SqlException(Throwable cause) { super(cause); - } + } } diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlScript.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlScript.java index 4bbcb6e284..fc259ae8cb 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlScript.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/SqlScript.java @@ -145,7 +145,8 @@ protected List parseLines(List script) { public void execute(final boolean autoCommit) { ISqlConnection connection = platform.getSqlConnection(); - connection.update(autoCommit, failOnError, commitRate, statements.toArray(new String[statements.size()])); + connection.update(autoCommit, failOnError, commitRate, + statements.toArray(new String[statements.size()])); } private String trimComments(String line) { diff --git a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/StatementBuilder.java b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/StatementBuilder.java index 6f2355369a..c1dbaf02d4 100644 --- a/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/StatementBuilder.java +++ b/future/symmetric3-core/src/main/java/org/jumpmind/symmetric/core/sql/StatementBuilder.java @@ -16,11 +16,11 @@ * "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 org.jumpmind.symmetric.core.sql; - + * under the License. + */ + +package org.jumpmind.symmetric.core.sql; + import java.sql.Types; import java.util.ArrayList; import java.util.HashSet; @@ -30,233 +30,233 @@ import org.jumpmind.symmetric.core.common.NotImplementedException; import org.jumpmind.symmetric.core.model.Column; - /** * Builds a SQL DML statement */ public class StatementBuilder { - - public enum DmlType { - INSERT, UPDATE, DELETE, COUNT - }; - - protected DmlType dmlType; - - protected String sql; - - protected int[] types; - - protected String quote; - - protected Column[] keys; - - protected Column[] columns; - - protected Column[] preFilteredColumns; - - public StatementBuilder(DmlType type, String tableName, Column[] keys, Column[] columns, - Column[] preFilteredColumns, boolean isDateOverrideToTimestamp, String identifierQuoteString) { - this.keys = keys; - this.columns = columns; - this.preFilteredColumns = preFilteredColumns; - quote = identifierQuoteString == null ? "" : identifierQuoteString; - if (type == DmlType.INSERT) { - sql = buildInsertSql(tableName, columns); - types = buildTypes(columns, isDateOverrideToTimestamp); - } else if (type == DmlType.UPDATE) { - sql = buildUpdateSql(tableName, keys, columns); - types = buildTypes(keys, columns, isDateOverrideToTimestamp); - } else if (type == DmlType.DELETE) { - sql = buildDeleteSql(tableName, keys); - types = buildTypes(keys, isDateOverrideToTimestamp); - } else if (type == DmlType.COUNT) { - sql = buildCountSql(tableName, keys); - types = buildTypes(keys, isDateOverrideToTimestamp); - } else { - throw new NotImplementedException("Unimplemented SQL type: " + type); - } - dmlType = type; - } - - protected Column[] removeKeysFromColumns(Column[] keys, Column[] columns) { - Column[] columnsWithoutKeys = new Column[columns.length - keys.length]; - Set keySet = new HashSet(); - CollectionUtils.addAll(keySet, keys); - int n = 0; - for (int i = 0; i < columns.length; i++) { - Column column = columns[i]; - if (!keySet.contains(column)) { - columnsWithoutKeys[n++] = column; - } - } - return columnsWithoutKeys; - } - - protected int[] buildTypes(Column[] keys, Column[] columns, boolean isDateOverrideToTimestamp) { - int[] columnTypes = buildTypes(columns, isDateOverrideToTimestamp); - int[] keyTypes = buildTypes(keys, isDateOverrideToTimestamp); - return CollectionUtils.addAll(columnTypes, keyTypes); - } - - protected int[] buildTypes(Column[] columns, boolean isDateOverrideToTimestamp) { - ArrayList list = new ArrayList(columns.length); - for (int i = 0; i < columns.length; i++) { - if (columns[i] != null) { - list.add(columns[i].getTypeCode()); - } - } - int[] types = new int[list.size()]; - int index = 0; - for (Integer type : list) { - if (type == Types.DATE && isDateOverrideToTimestamp) { - type = Types.TIMESTAMP; - } else if (type == Types.FLOAT || type == Types.DOUBLE) { - type = Types.DECIMAL; - } - types[index++] = type; - } - return types; - } - - public String buildInsertSql(String tableName, String[] columnNames) { - StringBuilder sql = new StringBuilder("insert into " + tableName + "("); - appendColumns(sql, columnNames); - sql.append(") values ("); - appendColumnQuestions(sql, columnNames.length); - sql.append(")"); - return sql.toString(); - } - - public String buildInsertSql(String tableName, Column[] columns) { - StringBuilder sql = new StringBuilder("insert into " + tableName + "("); - int columnCount = appendColumns(sql, columns); - sql.append(") values ("); - appendColumnQuestions(sql, columnCount); - sql.append(")"); - return sql.toString(); - } - - public String buildUpdateSql(String tableName, String[] keyNames, String[] columnNames) { - StringBuilder sql = new StringBuilder("update ").append(tableName).append(" set "); - appendColumnEquals(sql, columnNames, ", "); - sql.append(" where "); - appendColumnEquals(sql, keyNames, " and "); - return sql.toString(); - } - - public String buildUpdateSql(String tableName, Column[] keyColumns, Column[] columns) { - StringBuilder sql = new StringBuilder("update ").append(tableName).append(" set "); - appendColumnEquals(sql, columns, ", "); - sql.append(" where "); - appendColumnEquals(sql, keyColumns, " and "); - return sql.toString(); - } - - public String buildDeleteSql(String tableName, String[] keyNames) { - StringBuilder sql = new StringBuilder("delete from ").append(tableName).append(" where "); - appendColumnEquals(sql, keyNames, " and "); - return sql.toString(); - } - - public String buildDeleteSql(String tableName, Column[] keyColumns) { - StringBuilder sql = new StringBuilder("delete from ").append(tableName).append(" where "); - appendColumnEquals(sql, keyColumns, " and "); - return sql.toString(); - } - - public String buildCountSql(String tableName, Column[] keyColumns) { - StringBuilder sql = new StringBuilder("select count(*) from ").append(tableName).append( - " where "); - appendColumnEquals(sql, keyColumns, " and "); - return sql.toString(); - } - - public void appendColumnEquals(StringBuilder sql, String[] names, String separator) { - for (int i = 0; i < names.length; i++) { - sql.append(quote).append(names[i]).append(quote).append(" = ?").append( - i + 1 < names.length ? separator : ""); - } - } - - public void appendColumnEquals(StringBuilder sql, Column[] columns, String separator) { - int existingCount = 0; - for (int i = 0; i < columns.length; i++) { - if (columns[i] != null) { - if (existingCount++ > 0) { - sql.append(separator); - } - sql.append(quote).append(columns[i].getName()).append(quote).append(" = ?"); - } - } - } - - public void appendColumns(StringBuilder sql, String[] names) { - for (int i = 0; i < names.length; i++) { - sql.append(quote).append(names[i]).append(quote) - .append(i + 1 < names.length ? "," : ""); - } - } - - public int appendColumns(StringBuilder sql, Column[] columns) { - int existingCount = 0; - for (int i = 0; i < columns.length; i++) { - if (columns[i] != null) { - if (existingCount++ > 0) { - sql.append(","); - } - sql.append(quote).append(columns[i].getName()).append(quote); - } - } - return existingCount; - } - - public void appendColumnQuestions(StringBuilder sql, int number) { - for (int i = 0; i < number; i++) { - sql.append("?").append(i + 1 < number ? "," : ""); - } - } - - public String getSql() { - return sql; - } - - public DmlType getDmlType() { - return dmlType; - } - - public int[] getTypes() { - return types; - } - - public Column[] getColumns() { - return columns; - } - - public Column[] getColumnKeyMetaData(boolean prefiltered) { - if (prefiltered) { - return (Column[]) CollectionUtils.addAll(preFilteredColumns, keys); - } else { - return (Column[]) CollectionUtils.addAll(columns, keys); - } - } - - public Column[] getMetaData(boolean prefiltered) { - switch (dmlType) { - case UPDATE: - return getColumnKeyMetaData(prefiltered); - case INSERT: - return getColumns(); - case DELETE: - return getKeys(); - } - return null; - } - - public Column[] getKeys() { - return keys; - } - - public Column[] getPreFilteredColumns() { - return preFilteredColumns; - } + + public enum DmlType { + INSERT, UPDATE, DELETE, COUNT + }; + + protected DmlType dmlType; + + protected String sql; + + protected int[] types; + + protected String quote; + + protected Column[] keys; + + protected Column[] columns; + + protected Column[] preFilteredColumns; + + public StatementBuilder(DmlType type, String tableName, Column[] keys, Column[] columns, + Column[] preFilteredColumns, boolean isDateOverrideToTimestamp, + String identifierQuoteString) { + this.keys = keys; + this.columns = columns; + this.preFilteredColumns = preFilteredColumns; + quote = identifierQuoteString == null ? "" : identifierQuoteString; + if (type == DmlType.INSERT) { + sql = buildInsertSql(tableName, columns); + types = buildTypes(columns, isDateOverrideToTimestamp); + } else if (type == DmlType.UPDATE) { + sql = buildUpdateSql(tableName, keys, columns); + types = buildTypes(keys, columns, isDateOverrideToTimestamp); + } else if (type == DmlType.DELETE) { + sql = buildDeleteSql(tableName, keys); + types = buildTypes(keys, isDateOverrideToTimestamp); + } else if (type == DmlType.COUNT) { + sql = buildCountSql(tableName, keys); + types = buildTypes(keys, isDateOverrideToTimestamp); + } else { + throw new NotImplementedException("Unimplemented SQL type: " + type); + } + dmlType = type; + } + + protected Column[] removeKeysFromColumns(Column[] keys, Column[] columns) { + Column[] columnsWithoutKeys = new Column[columns.length - keys.length]; + Set keySet = new HashSet(); + CollectionUtils.addAll(keySet, keys); + int n = 0; + for (int i = 0; i < columns.length; i++) { + Column column = columns[i]; + if (!keySet.contains(column)) { + columnsWithoutKeys[n++] = column; + } + } + return columnsWithoutKeys; + } + + protected int[] buildTypes(Column[] keys, Column[] columns, boolean isDateOverrideToTimestamp) { + int[] columnTypes = buildTypes(columns, isDateOverrideToTimestamp); + int[] keyTypes = buildTypes(keys, isDateOverrideToTimestamp); + return CollectionUtils.addAll(columnTypes, keyTypes); + } + + protected int[] buildTypes(Column[] columns, boolean isDateOverrideToTimestamp) { + ArrayList list = new ArrayList(columns.length); + for (int i = 0; i < columns.length; i++) { + if (columns[i] != null) { + list.add(columns[i].getTypeCode()); + } + } + int[] types = new int[list.size()]; + int index = 0; + for (Integer type : list) { + if (type == Types.DATE && isDateOverrideToTimestamp) { + type = Types.TIMESTAMP; + } else if (type == Types.FLOAT || type == Types.DOUBLE) { + type = Types.DECIMAL; + } + types[index++] = type; + } + return types; + } + + public String buildInsertSql(String tableName, String[] columnNames) { + StringBuilder sql = new StringBuilder("insert into " + tableName + "("); + appendColumns(sql, columnNames); + sql.append(") values ("); + appendColumnQuestions(sql, columnNames.length); + sql.append(")"); + return sql.toString(); + } + + public String buildInsertSql(String tableName, Column[] columns) { + StringBuilder sql = new StringBuilder("insert into " + tableName + "("); + int columnCount = appendColumns(sql, columns); + sql.append(") values ("); + appendColumnQuestions(sql, columnCount); + sql.append(")"); + return sql.toString(); + } + + public String buildUpdateSql(String tableName, String[] keyNames, String[] columnNames) { + StringBuilder sql = new StringBuilder("update ").append(tableName).append(" set "); + appendColumnEquals(sql, columnNames, ", "); + sql.append(" where "); + appendColumnEquals(sql, keyNames, " and "); + return sql.toString(); + } + + public String buildUpdateSql(String tableName, Column[] keyColumns, Column[] columns) { + StringBuilder sql = new StringBuilder("update ").append(tableName).append(" set "); + appendColumnEquals(sql, columns, ", "); + sql.append(" where "); + appendColumnEquals(sql, keyColumns, " and "); + return sql.toString(); + } + + public String buildDeleteSql(String tableName, String[] keyNames) { + StringBuilder sql = new StringBuilder("delete from ").append(tableName).append(" where "); + appendColumnEquals(sql, keyNames, " and "); + return sql.toString(); + } + + public String buildDeleteSql(String tableName, Column[] keyColumns) { + StringBuilder sql = new StringBuilder("delete from ").append(tableName).append(" where "); + appendColumnEquals(sql, keyColumns, " and "); + return sql.toString(); + } + + public String buildCountSql(String tableName, Column[] keyColumns) { + StringBuilder sql = new StringBuilder("select count(*) from ").append(tableName).append( + " where "); + appendColumnEquals(sql, keyColumns, " and "); + return sql.toString(); + } + + public void appendColumnEquals(StringBuilder sql, String[] names, String separator) { + for (int i = 0; i < names.length; i++) { + sql.append(quote).append(names[i]).append(quote).append(" = ?") + .append(i + 1 < names.length ? separator : ""); + } + } + + public void appendColumnEquals(StringBuilder sql, Column[] columns, String separator) { + int existingCount = 0; + for (int i = 0; i < columns.length; i++) { + if (columns[i] != null) { + if (existingCount++ > 0) { + sql.append(separator); + } + sql.append(quote).append(columns[i].getName()).append(quote).append(" = ?"); + } + } + } + + public void appendColumns(StringBuilder sql, String[] names) { + for (int i = 0; i < names.length; i++) { + sql.append(quote).append(names[i]).append(quote) + .append(i + 1 < names.length ? "," : ""); + } + } + + public int appendColumns(StringBuilder sql, Column[] columns) { + int existingCount = 0; + for (int i = 0; i < columns.length; i++) { + if (columns[i] != null) { + if (existingCount++ > 0) { + sql.append(","); + } + sql.append(quote).append(columns[i].getName()).append(quote); + } + } + return existingCount; + } + + public void appendColumnQuestions(StringBuilder sql, int number) { + for (int i = 0; i < number; i++) { + sql.append("?").append(i + 1 < number ? "," : ""); + } + } + + public String getSql() { + return sql; + } + + public DmlType getDmlType() { + return dmlType; + } + + public int[] getTypes() { + return types; + } + + public Column[] getColumns() { + return columns; + } + + public Column[] getColumnKeyMetaData(boolean prefiltered) { + if (prefiltered) { + return (Column[]) CollectionUtils.addAll(preFilteredColumns, keys); + } else { + return (Column[]) CollectionUtils.addAll(columns, keys); + } + } + + public Column[] getMetaData(boolean prefiltered) { + switch (dmlType) { + case UPDATE: + return getColumnKeyMetaData(prefiltered); + case INSERT: + return getColumns(); + case DELETE: + return getKeys(); + } + return null; + } + + public Column[] getKeys() { + return keys; + } + + public Column[] getPreFilteredColumns() { + return preFilteredColumns; + } } \ No newline at end of file diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDataSource.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDataSource.java index 0873dd0516..27af65304b 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDataSource.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDataSource.java @@ -21,65 +21,65 @@ import javax.sql.DataSource; - /** * Abstract base class for Spring's {@link javax.sql.DataSource} * implementations, taking care of the padding. - * - *

'Padding' in the context of this class means default implementations - * for certain methods from the DataSource interface, such as + * + *

+ * 'Padding' in the context of this class means default implementations for + * certain methods from the DataSource interface, such as * {@link #getLoginTimeout()}, {@link #setLoginTimeout(int)}, and so forth. - * + * * @author Juergen Hoeller * @since 07.05.2003 * @see DriverManagerDataSource */ public abstract class AbstractDataSource implements DataSource { - - /** - * Returns 0, indicating the default system timeout is to be used. - */ - public int getLoginTimeout() throws SQLException { - return 0; - } - /** - * Setting a login timeout is not supported. - */ - public void setLoginTimeout(int timeout) throws SQLException { - throw new UnsupportedOperationException("setLoginTimeout"); - } + /** + * Returns 0, indicating the default system timeout is to be used. + */ + public int getLoginTimeout() throws SQLException { + return 0; + } - /** - * LogWriter methods are not supported. - */ - public PrintWriter getLogWriter() { - throw new UnsupportedOperationException("getLogWriter"); - } + /** + * Setting a login timeout is not supported. + */ + public void setLoginTimeout(int timeout) throws SQLException { + throw new UnsupportedOperationException("setLoginTimeout"); + } - /** - * LogWriter methods are not supported. - */ - public void setLogWriter(PrintWriter pw) throws SQLException { - throw new UnsupportedOperationException("setLogWriter"); - } + /** + * LogWriter methods are not supported. + */ + public PrintWriter getLogWriter() { + throw new UnsupportedOperationException("getLogWriter"); + } + /** + * LogWriter methods are not supported. + */ + public void setLogWriter(PrintWriter pw) throws SQLException { + throw new UnsupportedOperationException("setLogWriter"); + } - //--------------------------------------------------------------------- - // Implementation of JDBC 4.0's Wrapper interface - //--------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Implementation of JDBC 4.0's Wrapper interface + // --------------------------------------------------------------------- - @SuppressWarnings("unchecked") - public T unwrap(Class iface) throws SQLException { - if (!DataSource.class.equals(iface)) { - throw new SQLException("DataSource of type [" + getClass().getName() + - "] can only be unwrapped as [javax.sql.DataSource], not as [" + iface.getName()); - } - return (T) this; - } + @SuppressWarnings("unchecked") + public T unwrap(Class iface) throws SQLException { + if (!DataSource.class.equals(iface)) { + throw new SQLException("DataSource of type [" + getClass().getName() + + "] can only be unwrapped as [javax.sql.DataSource], not as [" + + iface.getName()); + } + return (T) this; + } - public boolean isWrapperFor(Class iface) throws SQLException { - return DataSource.class.equals(iface); - } + public boolean isWrapperFor(Class iface) throws SQLException { + return DataSource.class.equals(iface); + } } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDriverBasedDataSource.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDriverBasedDataSource.java index f2d51fdf20..947a75b0c6 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDriverBasedDataSource.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/AbstractDriverBasedDataSource.java @@ -20,11 +20,10 @@ import java.sql.SQLException; import java.util.Properties; - /** * Abstract base class for JDBC {@link javax.sql.DataSource} implementations * that operate on a JDBC {@link java.sql.Driver}. - * + * * @author Juergen Hoeller * @since 2.5.5 * @see DriverDataSource @@ -32,128 +31,141 @@ */ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource { - private String url; - - private String username; - - private String password; - - private Properties connectionProperties; - - - /** - * Set the JDBC URL to use for connecting through the Driver. - * @see java.sql.Driver#connect(String, java.util.Properties) - */ - public void setUrl(String url) { - this.url = url.trim(); - } - - /** - * Return the JDBC URL to use for connecting through the Driver. - */ - public String getUrl() { - return this.url; - } - - /** - * Set the JDBC username to use for connecting through the Driver. - * @see java.sql.Driver#connect(String, java.util.Properties) - */ - public void setUsername(String username) { - this.username = username; - } - - /** - * Return the JDBC username to use for connecting through the Driver. - */ - public String getUsername() { - return this.username; - } - - /** - * Set the JDBC password to use for connecting through the Driver. - * @see java.sql.Driver#connect(String, java.util.Properties) - */ - public void setPassword(String password) { - this.password = password; - } - - /** - * Return the JDBC password to use for connecting through the Driver. - */ - public String getPassword() { - return this.password; - } - - /** - * Specify arbitrary connection properties as key/value pairs, - * to be passed to the Driver. - *

Can also contain "user" and "password" properties. However, - * any "username" and "password" bean properties specified on this - * DataSource will override the corresponding connection properties. - * @see java.sql.Driver#connect(String, java.util.Properties) - */ - public void setConnectionProperties(Properties connectionProperties) { - this.connectionProperties = connectionProperties; - } - - /** - * Return the connection properties to be passed to the Driver, if any. - */ - public Properties getConnectionProperties() { - return this.connectionProperties; - } - - - /** - * This implementation delegates to getConnectionFromDriver, - * using the default username and password of this DataSource. - * @see #getConnectionFromDriver(String, String) - * @see #setUsername - * @see #setPassword - */ - public Connection getConnection() throws SQLException { - return getConnectionFromDriver(getUsername(), getPassword()); - } - - /** - * This implementation delegates to getConnectionFromDriver, - * using the given username and password. - * @see #getConnectionFromDriver(String, String) - */ - public Connection getConnection(String username, String password) throws SQLException { - return getConnectionFromDriver(username, password); - } - - - /** - * Build properties for the Driver, including the given username and password (if any), - * and obtain a corresponding Connection. - * @param username the name of the user - * @param password the password to use - * @return the obtained Connection - * @throws SQLException in case of failure - * @see java.sql.Driver#connect(String, java.util.Properties) - */ - protected Connection getConnectionFromDriver(String username, String password) throws SQLException { - Properties props = new Properties(getConnectionProperties()); - if (username != null) { - props.setProperty("user", username); - } - if (password != null) { - props.setProperty("password", password); - } - return getConnectionFromDriver(props); - } - - /** - * Obtain a Connection using the given properties. - *

Template method to be implemented by subclasses. - * @param props the merged connection properties - * @return the obtained Connection - * @throws SQLException in case of failure - */ - protected abstract Connection getConnectionFromDriver(Properties props) throws SQLException; + private String url; + + private String username; + + private String password; + + private Properties connectionProperties; + + /** + * Set the JDBC URL to use for connecting through the Driver. + * + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + public void setUrl(String url) { + this.url = url.trim(); + } + + /** + * Return the JDBC URL to use for connecting through the Driver. + */ + public String getUrl() { + return this.url; + } + + /** + * Set the JDBC username to use for connecting through the Driver. + * + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Return the JDBC username to use for connecting through the Driver. + */ + public String getUsername() { + return this.username; + } + + /** + * Set the JDBC password to use for connecting through the Driver. + * + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Return the JDBC password to use for connecting through the Driver. + */ + public String getPassword() { + return this.password; + } + + /** + * Specify arbitrary connection properties as key/value pairs, to be passed + * to the Driver. + *

+ * Can also contain "user" and "password" properties. However, any + * "username" and "password" bean properties specified on this DataSource + * will override the corresponding connection properties. + * + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + public void setConnectionProperties(Properties connectionProperties) { + this.connectionProperties = connectionProperties; + } + + /** + * Return the connection properties to be passed to the Driver, if any. + */ + public Properties getConnectionProperties() { + return this.connectionProperties; + } + + /** + * This implementation delegates to getConnectionFromDriver, + * using the default username and password of this DataSource. + * + * @see #getConnectionFromDriver(String, String) + * @see #setUsername + * @see #setPassword + */ + public Connection getConnection() throws SQLException { + return getConnectionFromDriver(getUsername(), getPassword()); + } + + /** + * This implementation delegates to getConnectionFromDriver, + * using the given username and password. + * + * @see #getConnectionFromDriver(String, String) + */ + public Connection getConnection(String username, String password) throws SQLException { + return getConnectionFromDriver(username, password); + } + + /** + * Build properties for the Driver, including the given username and + * password (if any), and obtain a corresponding Connection. + * + * @param username + * the name of the user + * @param password + * the password to use + * @return the obtained Connection + * @throws SQLException + * in case of failure + * @see java.sql.Driver#connect(String, java.util.Properties) + */ + protected Connection getConnectionFromDriver(String username, String password) + throws SQLException { + Properties props = new Properties(getConnectionProperties()); + if (username != null) { + props.setProperty("user", username); + } + if (password != null) { + props.setProperty("password", password); + } + return getConnectionFromDriver(props); + } + + /** + * Obtain a Connection using the given properties. + *

+ * Template method to be implemented by subclasses. + * + * @param props + * the merged connection properties + * @return the obtained Connection + * @throws SQLException + * in case of failure + */ + protected abstract Connection getConnectionFromDriver(Properties props) throws SQLException; } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/DriverDataSourceProperties.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/DriverDataSourceProperties.java index 22a935eca6..660115913e 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/DriverDataSourceProperties.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/datasource/DriverDataSourceProperties.java @@ -20,7 +20,7 @@ public class DriverDataSourceProperties extends Properties { public DriverDataSourceProperties(String file) { load(new File(file)); } - + public DriverDataSourceProperties(File file) { load(file); } @@ -31,7 +31,7 @@ public DriverDataSourceProperties() { public void store(String file) { store(new File(file)); } - + public DataSource getDataSource() { return getDataSource(System.getProperty("db.default", getProperty("db.default", "h2"))); } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/AbstractJdbcDbPlatform.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/AbstractJdbcDbPlatform.java index 236eb56379..6260bcef6c 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/AbstractJdbcDbPlatform.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/AbstractJdbcDbPlatform.java @@ -17,36 +17,37 @@ abstract public class AbstractJdbcDbPlatform extends AbstractDbPlatform implemen protected DataSource dataSource; - protected JdbcModelReader jdbcModelReader; + protected JdbcModelReader jdbcModelReader; public AbstractJdbcDbPlatform(DataSource dataSource, Parameters parameters) { super(parameters); this.dataSource = dataSource; } - + public ISqlConnection getSqlConnection() { return getJdbcSqlConnection(); } - + public JdbcSqlConnection getJdbcSqlConnection() { return new JdbcSqlConnection(this); } - + public Database findDatabase(String catalogName, String schemaName) { return jdbcModelReader.getDatabase(catalogName, schemaName, null); - } - + } + public String getAlterScriptFor(Table... tables) { StringWriter writer = new StringWriter(); sqlBuilder.setWriter(writer); Database desiredModel = new Database(); desiredModel.addTables(tables); - + Database currentModel = new Database(); for (Table table : tables) { - currentModel.addTable(jdbcModelReader.readTable(table.getCatalogName(), table.getSchemaName(), table.getTableName(), false, false)); + currentModel.addTable(jdbcModelReader.readTable(table.getCatalogName(), + table.getSchemaName(), table.getTableName(), false, false)); } - + sqlBuilder.alterDatabase(currentModel, desiredModel); return writer.toString(); @@ -56,14 +57,13 @@ public Table findTable(String tableName) { return findTable(null, null, tableName, false); } - public Table findTable(String catalogName, String schemaName, String tableName, - boolean useCache) { + public Table findTable(String catalogName, String schemaName, String tableName, boolean useCache) { Table cachedTable = cachedModel.findTable(catalogName, schemaName, tableName); if (cachedTable == null || !useCache) { Table justReadTable = jdbcModelReader.readTable(catalogName, schemaName, tableName, !parameters.is(Parameters.DB_METADATA_IGNORE_CASE, true), parameters.is(Parameters.DB_USE_ALL_COLUMNS_AS_PK_IF_NONE_FOUND, false)); - + if (cachedTable != null) { cachedModel.removeTable(cachedTable); } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/IJdbcDbPlatform.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/IJdbcDbPlatform.java index bba108cec2..9101d2a908 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/IJdbcDbPlatform.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/IJdbcDbPlatform.java @@ -8,10 +8,10 @@ public interface IJdbcDbPlatform extends IDbPlatform { - public ILobHandler getLobHandler(); - + public ILobHandler getLobHandler(); + public DataSource getDataSource(); - + public JdbcSqlConnection getJdbcSqlConnection(); - + } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcDbPlatformFactory.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcDbPlatformFactory.java index 04d26d4ebc..b8c2be82d3 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcDbPlatformFactory.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcDbPlatformFactory.java @@ -21,7 +21,8 @@ public class JdbcDbPlatformFactory { public static IJdbcDbPlatform createPlatform(DataSource dataSource, Parameters parameters) { String platformId = lookupPlatformId(dataSource, true); - AbstractJdbcDbPlatform platform = createNewPlatformInstance(platformId, dataSource, parameters); + AbstractJdbcDbPlatform platform = createNewPlatformInstance(platformId, dataSource, + parameters); if (platform == null) { platformId = lookupPlatformId(dataSource, false); platform = createNewPlatformInstance(platformId, dataSource, parameters); @@ -35,7 +36,8 @@ private static AbstractJdbcDbPlatform createNewPlatformInstance(String databaseN if (platformClass != null) { try { - Constructor constructor = platformClass.getConstructor(DataSource.class, Parameters.class); + Constructor constructor = platformClass.getConstructor(DataSource.class, + Parameters.class); return (AbstractJdbcDbPlatform) constructor.newInstance(dataSource, parameters); } catch (Exception ex) { throw new SqlException("Could not create platform for database " + databaseName, ex); diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcModelReader.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcModelReader.java index 05eadc77db..1931771760 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcModelReader.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/JdbcModelReader.java @@ -447,7 +447,7 @@ public Database execute(Connection con) throws SQLException { log.log(LogLevel.INFO, ex, "Cannot determine the catalog name from connection."); } db.addTables(readTables(con, catalog, schema, tableTypes)); - + // Note that we do this here instead of in readTable since // platforms may redefine the readTable method whereas it is // highly unlikely that this method gets redefined @@ -571,34 +571,33 @@ protected Table readTableCaseSensitive(String catalogName, String schemaName, : schemaName; final String catalog = StringUtils.isBlank(catalogName) ? platform.getDefaultCatalog() : catalogName; - table = platform.getJdbcSqlConnection() - .execute(new IConnectionCallback

() { - public Table execute(Connection c) throws SQLException { - Table table = null; - DatabaseMetaDataWrapper metaData = new DatabaseMetaDataWrapper(); - metaData.setMetaData(c.getMetaData()); - metaData.setCatalog(catalog); - metaData.setSchemaPattern(schema); - metaData.setTableTypes(getDefaultTableTypes()); - ResultSet tableData = null; - try { - tableData = metaData.getTables(getTableNamePattern(tableName)); - while (tableData != null && tableData.next()) { - Map values = readColumns(tableData, - initColumnsForTable()); - table = readTable(c, metaData, values); - } - } finally { - JdbcSqlConnection.close(tableData); - } - - if (makeAllColumnsPKsIfNoneFound) { - makeAllColumnsPrimaryKeysIfNoPrimaryKeysFound(table); - } - - return table; + table = platform.getJdbcSqlConnection().execute(new IConnectionCallback
() { + public Table execute(Connection c) throws SQLException { + Table table = null; + DatabaseMetaDataWrapper metaData = new DatabaseMetaDataWrapper(); + metaData.setMetaData(c.getMetaData()); + metaData.setCatalog(catalog); + metaData.setSchemaPattern(schema); + metaData.setTableTypes(getDefaultTableTypes()); + ResultSet tableData = null; + try { + tableData = metaData.getTables(getTableNamePattern(tableName)); + while (tableData != null && tableData.next()) { + Map values = readColumns(tableData, + initColumnsForTable()); + table = readTable(c, metaData, values); } - }); + } finally { + JdbcSqlConnection.close(tableData); + } + + if (makeAllColumnsPKsIfNoneFound) { + makeAllColumnsPrimaryKeysIfNoPrimaryKeysFound(table); + } + + return table; + } + }); } catch (SqlException ex) { log.log(LogLevel.WARN, ex); } @@ -632,8 +631,8 @@ protected void makeAllColumnsPrimaryKeysIfNoPrimaryKeysFound(Table table) { * @return The table or null if the result set row did not * contain a valid table */ - protected Table readTable(Connection c, DatabaseMetaDataWrapper metaData, Map values) - throws SQLException { + protected Table readTable(Connection c, DatabaseMetaDataWrapper metaData, + Map values) throws SQLException { String tableName = (String) values.get("TABLE_NAME"); Table table = null; @@ -1000,8 +999,8 @@ protected void readForeignKey(DatabaseMetaDataWrapper metaData, Map readIndices(Connection c, DatabaseMetaDataWrapper metaData, String tableName) - throws SQLException { + protected Collection readIndices(Connection c, DatabaseMetaDataWrapper metaData, + String tableName) throws SQLException { Map indices = new LinkedHashMap(); ResultSet indexData = null; diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2DbPlatform.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2DbPlatform.java index 145619df02..cf31081f46 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2DbPlatform.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2DbPlatform.java @@ -29,7 +29,7 @@ public H2DbPlatform(DataSource dataSource, Parameters parameters) { platformInfo.addNativeTypeMapping(Types.DATALINK, "BINARY", Types.BINARY); platformInfo.addNativeTypeMapping(Types.BIT, "BOOLEAN", Types.BIT); - + platformInfo.addNativeTypeMapping(Types.NUMERIC, "DECIMAL", Types.DECIMAL); platformInfo.addNativeTypeMapping(Types.BINARY, "BINARY", Types.BINARY); platformInfo.addNativeTypeMapping(Types.BLOB, "BLOB", Types.BLOB); @@ -48,7 +48,7 @@ public H2DbPlatform(DataSource dataSource, Parameters parameters) { platformInfo.setBlankCharColumnSpacePadded(true); platformInfo.setNonBlankCharColumnSpacePadded(false); platformInfo.setRequiresAutoCommitFalseToSetFetchSize(false); - + this.jdbcModelReader = new H2JdbcModelReader(this); this.sqlBuilder = new H2SqlBuilder(this); this.triggerBuilder = new H2TriggerBuilder(this); diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2JdbcModelReader.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2JdbcModelReader.java index 6112aa5dbe..97b01071b7 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2JdbcModelReader.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/h2/H2JdbcModelReader.java @@ -25,7 +25,8 @@ public H2JdbcModelReader(IJdbcDbPlatform platform) { } @Override - protected Column readColumn(DatabaseMetaDataWrapper metaData, Map values) throws SQLException { + protected Column readColumn(DatabaseMetaDataWrapper metaData, Map values) + throws SQLException { Column column = super.readColumn(metaData, values); if (values.get("CHARACTER_MAXIMUM_LENGTH") != null) { column.setSize(values.get("CHARACTER_MAXIMUM_LENGTH").toString()); @@ -61,21 +62,22 @@ protected List initColumnsForColumn() { } @Override - protected boolean isInternalForeignKeyIndex(DatabaseMetaDataWrapper metaData, Table table, ForeignKey fk, - Index index) { + protected boolean isInternalForeignKeyIndex(DatabaseMetaDataWrapper metaData, Table table, + ForeignKey fk, Index index) { String name = index.getName(); return name != null && name.startsWith("CONSTRAINT_INDEX_"); } @Override - protected boolean isInternalPrimaryKeyIndex(DatabaseMetaDataWrapper metaData, Table table, Index index) { + protected boolean isInternalPrimaryKeyIndex(DatabaseMetaDataWrapper metaData, Table table, + Index index) { String name = index.getName(); return name != null && name.startsWith("PRIMARY_KEY_"); } - + @Override - protected Table readTable(Connection c, DatabaseMetaDataWrapper metaData, Map values) - throws SQLException { + protected Table readTable(Connection c, DatabaseMetaDataWrapper metaData, + Map values) throws SQLException { Table table = super.readTable(c, metaData, values); if (table != null) { diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/oracle/OracleDbPlatform.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/oracle/OracleDbPlatform.java index a493ca924b..bfa8c55e1f 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/oracle/OracleDbPlatform.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/db/oracle/OracleDbPlatform.java @@ -16,7 +16,7 @@ public class OracleDbPlatform extends AbstractJdbcDbPlatform { public OracleDbPlatform(DataSource dataSource, Parameters parameters) { super(dataSource, parameters); - + platformInfo.setMaxIdentifierLength(30); platformInfo.setIdentityStatusReadingSupported(false); @@ -60,7 +60,7 @@ public OracleDbPlatform(DataSource dataSource, Parameters parameters) { platformInfo.setBlankCharColumnSpacePadded(true); platformInfo.setNonBlankCharColumnSpacePadded(true); platformInfo.setRequiresAutoCommitFalseToSetFetchSize(false); - + this.jdbcModelReader = new OracleJdbcModelReader(this); this.sqlBuilder = new OracleSqlBuilder(this); diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/IConnectionCallback.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/IConnectionCallback.java index 725aefb2d3..9a874cf6d8 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/IConnectionCallback.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/IConnectionCallback.java @@ -6,5 +6,5 @@ public interface IConnectionCallback { public T execute(Connection con) throws SQLException; - + } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/ILobHandler.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/ILobHandler.java index 967571c885..f53502aacc 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/ILobHandler.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/ILobHandler.java @@ -7,27 +7,37 @@ public interface ILobHandler { /** * Set the given content as bytes on the given statement, using the given - * parameter index. Might simply invoke PreparedStatement.setBytes - * or create a Blob instance for it, depending on the database and driver. - * @param ps the PreparedStatement to the set the content on - * @param paramIndex the parameter index to use - * @param content the content as byte array, or null for SQL NULL - * @throws SQLException if thrown by JDBC methods + * parameter index. Might simply invoke + * PreparedStatement.setBytes or create a Blob instance for it, + * depending on the database and driver. + * + * @param ps + * the PreparedStatement to the set the content on + * @param paramIndex + * the parameter index to use + * @param content + * the content as byte array, or null for SQL NULL + * @throws SQLException + * if thrown by JDBC methods * @see java.sql.PreparedStatement#setBytes */ - void setBlobAsBytes(PreparedStatement ps, int paramIndex, byte[] content) - throws SQLException; - + void setBlobAsBytes(PreparedStatement ps, int paramIndex, byte[] content) throws SQLException; + /** * Set the given content as String on the given statement, using the given - * parameter index. Might simply invoke PreparedStatement.setString - * or create a Clob instance for it, depending on the database and driver. - * @param ps the PreparedStatement to the set the content on - * @param paramIndex the parameter index to use - * @param content the content as String, or null for SQL NULL - * @throws SQLException if thrown by JDBC methods + * parameter index. Might simply invoke + * PreparedStatement.setString or create a Clob instance for + * it, depending on the database and driver. + * + * @param ps + * the PreparedStatement to the set the content on + * @param paramIndex + * the parameter index to use + * @param content + * the content as String, or null for SQL NULL + * @throws SQLException + * if thrown by JDBC methods * @see java.sql.PreparedStatement#setBytes */ - void setClobAsString(PreparedStatement ps, int paramIndex, String content) - throws SQLException; + void setClobAsString(PreparedStatement ps, int paramIndex, String content) throws SQLException; } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/INativeConnectionExtractor.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/INativeConnectionExtractor.java index dbb75ddece..3f4e48b63e 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/INativeConnectionExtractor.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/INativeConnectionExtractor.java @@ -8,10 +8,14 @@ public interface INativeConnectionExtractor { /** * Retrieve the underlying native JDBC Connection for the given Connection. * Supposed to return the given Connection if not capable of unwrapping. - * @param con the Connection handle, potentially wrapped by a connection pool - * @return the underlying native JDBC Connection, if possible; - * else, the original Connection - * @throws SQLException if thrown by JDBC methods + * + * @param con + * the Connection handle, potentially wrapped by a connection + * pool + * @return the underlying native JDBC Connection, if possible; else, the + * original Connection + * @throws SQLException + * if thrown by JDBC methods */ Connection getNativeConnection(Connection con) throws SQLException; } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlConnection.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlConnection.java index a7703f1970..31c0900c0c 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlConnection.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlConnection.java @@ -8,7 +8,9 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.sql.DataSource; @@ -59,19 +61,15 @@ public int queryForInt(String sql) { } } - public ISqlReadCursor query(String sql, ISqlRowMapper mapper) { - return query(sql, mapper, null, null); + public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper) { + return queryForCursor(sql, mapper, null, null); } - public ISqlReadCursor query(String sql, ISqlRowMapper mapper, Object[] values, - int[] types) { + public ISqlReadCursor queryForCursor(String sql, ISqlRowMapper mapper, + Object[] values, int[] types) { return new JdbcSqlReadCursor(sql, values, types, mapper, this.dbPlatform); } - public ISqlTransaction startSqlTransaction() { - return new JdbcSqlTransaction(this); - } - public T queryForObject(final String sql, Class clazz, final Object... args) { return execute(new IConnectionCallback() { @SuppressWarnings("unchecked") @@ -95,6 +93,45 @@ public T execute(Connection con) throws SQLException { }); } + public List> query(String sql) { + return query(sql, null, null); + } + + public List> query(String sql, Object[] args, int[] types) { + return query(sql, new ISqlRowMapper>() { + public Map mapRow(java.util.Map row) { + return row; + } + }, args, types); + } + + public List query(String sql, ISqlRowMapper mapper) { + return query(sql, mapper, null, null); + } + + public List query(String sql, ISqlRowMapper mapper, Object[] args, int[] types) { + ISqlReadCursor cursor = queryForCursor(sql, mapper, args, types); + try { + T next = null; + List list = new ArrayList(); + do { + next = cursor.next(); + if (next != null) { + list.add(next); + } + } while (next != null); + return list; + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + public ISqlTransaction startSqlTransaction() { + return new JdbcSqlTransaction(this); + } + public int update(String sql) { return update(sql, null, null); } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransaction.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransaction.java index c9d5b14b33..57518d78e5 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransaction.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransaction.java @@ -110,7 +110,7 @@ public int flush() { } return rowsUpdated; } - + protected void removeMarkersThatWereSuccessful(BatchUpdateException ex) { int[] updateCounts = ex.getUpdateCounts(); Iterator it = markers.iterator(); @@ -124,13 +124,12 @@ protected void removeMarkersThatWereSuccessful(BatchUpdateException ex) { } } - public void prepare(String sql, int flushSize, boolean useBatching) { + public void prepare(String sql, int flushSize) { try { if (this.markers.size() > 0) { throw new IllegalStateException( "Cannot prepare a new batch before the last batch has been flushed."); } - setInBatchMode(useBatching); this.numberOfRowsBeforeBatchFlush = flushSize; pstmt = dbConnection.prepareStatement(sql); } catch (SQLException ex) { @@ -161,8 +160,12 @@ public int update(Object marker, Object[] values, int[] types) { return rowsUpdated; } - public List getUnflushedMarkers() { - return markers; + public List getUnflushedMarkers(boolean clear) { + List ret = new ArrayList(markers); + if (clear) { + markers.clear(); + } + return ret; } /** diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/StatementCreatorUtil.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/StatementCreatorUtil.java index ea31581288..3cc38c3199 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/StatementCreatorUtil.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/sql/StatementCreatorUtil.java @@ -67,18 +67,17 @@ public abstract class StatementCreatorUtil { javaTypeToSqlTypeMap.put(Blob.class, Types.BLOB); javaTypeToSqlTypeMap.put(Clob.class, Types.CLOB); } - - public static void setValues(PreparedStatement ps, Object[] args, int[] argTypes, ILobHandler lobHandler) throws SQLException { + + public static void setValues(PreparedStatement ps, Object[] args, int[] argTypes, + ILobHandler lobHandler) throws SQLException { for (int i = 1; i <= args.length; i++) { - Object arg = args[i-1]; - int argType = argTypes[i-1]; + Object arg = args[i - 1]; + int argType = argTypes[i - 1]; if (argType == Types.BLOB && lobHandler != null) { lobHandler.setBlobAsBytes(ps, i, (byte[]) arg); - } - else if (argType == Types.CLOB && lobHandler != null) { + } else if (argType == Types.CLOB && lobHandler != null) { lobHandler.setClobAsString(ps, i, (String) arg); - } - else { + } else { setParameterValue(ps, i, argType, arg); } } diff --git a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyProperties.java b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyProperties.java index cc6304e9fe..349eaaeeb2 100644 --- a/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyProperties.java +++ b/future/symmetric3-jdbc/src/main/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyProperties.java @@ -16,7 +16,7 @@ public class TableCopyProperties extends DriverDataSourceProperties { public TableCopyProperties(String file) { load(new File(file)); } - + public TableCopyProperties(File file) { load(file); } diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/AbstractDatabaseTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/AbstractDatabaseTest.java index 07aa80d2a0..7a84d11a94 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/AbstractDatabaseTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/AbstractDatabaseTest.java @@ -3,6 +3,10 @@ import javax.sql.DataSource; import org.hsqldb.types.Types; +import org.jumpmind.symmetric.core.common.Log; +import org.jumpmind.symmetric.core.common.LogFactory; +import org.jumpmind.symmetric.core.common.LogLevel; +import org.jumpmind.symmetric.core.common.StringUtils; import org.jumpmind.symmetric.core.db.IDbPlatform; import org.jumpmind.symmetric.core.io.FileUtils; import org.jumpmind.symmetric.core.model.Column; @@ -18,6 +22,8 @@ abstract public class AbstractDatabaseTest { + final protected Log log = LogFactory.getLog(getClass()); + static protected IJdbcDbPlatform platform; protected static IJdbcDbPlatform getPlatform() { @@ -73,16 +79,23 @@ protected void insertTestTableRows(int count) { } protected int count(String tableName) { + return count(tableName, null); + } + + protected int count(String tableName, String where) { IDbPlatform platform = getPlatform(false); ISqlConnection connection = platform.getSqlConnection(); - return connection.queryForInt(String.format("select count(*) from %s", tableName)); + return connection.queryForInt(String.format("select count(*) from %s %s %s", tableName, + StringUtils.isNotBlank(where) ? "where" : "", StringUtils.isNotBlank(where) ? where + : "")); } protected void prepareInsertIntoTestTable(ISqlTransaction transaction, String tableName, int flushAt, boolean batchMode) { + transaction.setInBatchMode(batchMode); transaction.prepare( String.format("insert into %s (TEST_ID, TEST_TEXT) values(?, ?)", tableName), - flushAt, batchMode); + flushAt); } protected int batchInsertIntoTestTable(int numberToInsert, int numberToStartAt, @@ -95,4 +108,11 @@ protected int batchInsertIntoTestTable(int numberToInsert, int numberToStartAt, } return updatedCount; } + + protected void printOutTable(String tableName) { + log.log(LogLevel.INFO, + getPlatform().getSqlConnection() + .query(String.format("select * from %s", tableName)).toString()); + } + } diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriterTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriterTest.java index 5fc69bea29..07d3f4c576 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriterTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlDataWriterTest.java @@ -38,7 +38,7 @@ public void testOneRowInsertOneRowUpdate() { String.format("select TEST_TEXT from %s where TEST_ID=?", testTable.getTableName()), String.class, 1)); } - + @Test public void testOneRowInsertOneRowDelete() { writeToTestTable(new Data(testTable.getTableName(), DataEventType.INSERT, "1,\"test\""), @@ -46,7 +46,30 @@ public void testOneRowInsertOneRowDelete() { Assert.assertEquals(0, count(testTable.getTableName())); } - protected void writeToTestTable(Data... datas) { + @Test + public void testOneRowInsertFallbackToUpdate() { + insertTestTableRows(10); + Assert.assertEquals(10, count(testTable.getTableName())); + int existingId = getPlatform().getSqlConnection().queryForInt( + String.format("select min(TEST_ID) from %s", testTable.getTableName())); + Assert.assertEquals(1, + count(testTable.getTableName(), String.format("TEST_ID=%d", existingId))); + Assert.assertEquals( + 0, + count(testTable.getTableName(), + String.format("TEST_ID=%d and TEST_TEXT='new value'", existingId))); + Batch batch = writeToTestTable(new Data(testTable.getTableName(), DataEventType.INSERT, + String.format("%d,\"new value\"", existingId))); + Assert.assertEquals(10, count(testTable.getTableName())); + Assert.assertEquals(1, batch.getFallbackUpdateCount()); + Assert.assertEquals( + 1, + count(testTable.getTableName(), + String.format("TEST_ID=%d and TEST_TEXT='new value'", existingId))); + Assert.assertEquals(1, batch.getInsertCount()); + } + + protected Batch writeToTestTable(Data... datas) { SqlDataWriter writer = new SqlDataWriter(getPlatform(), new Parameters()); writer.open(writer.createDataContext()); Batch batch = new Batch(); @@ -57,5 +80,6 @@ protected void writeToTestTable(Data... datas) { } writer.finishBatch(batch); writer.close(); + return batch; } } diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReaderTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReaderTest.java index 25ff9f21df..8fe8b8e6d5 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReaderTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/core/process/sql/SqlTableDataReaderTest.java @@ -27,7 +27,7 @@ public void testSimpleTableWithNoCondition() throws Exception { Assert.assertEquals(testTable, nextTable); for (int i = 0; i < 100; i++) { Data data = reader.nextData(ctx); - Assert.assertNotNull("Null data on the " + i + " element",data); + Assert.assertNotNull("Null data on the " + i + " element", data); } Data data = reader.nextData(ctx); Assert.assertNull(data); diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/db/JdbcPlatformTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/db/JdbcPlatformTest.java index f968761f3c..89ec049b37 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/db/JdbcPlatformTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/db/JdbcPlatformTest.java @@ -16,18 +16,20 @@ public class JdbcPlatformTest extends AbstractDatabaseTest { public void testJdbcPlatformFactory() { IJdbcDbPlatform platform = getPlatform(true); Assert.assertNotNull(platform); - } - + } + @Test public void testCreateTable() { IJdbcDbPlatform platform = getPlatform(true); - Table table = new Table("test", - new Column("test_id", TypeMap.NUMERIC, "10,2", false, true, true)); + Table table = new Table("test", new Column("test_id", TypeMap.NUMERIC, "10,2", false, true, + true)); ISqlConnection sqlConnection = platform.getSqlConnection(); String alterSql = platform.getAlterScriptFor(table); Assert.assertFalse(StringUtils.isBlank(alterSql)); sqlConnection.update(alterSql); alterSql = platform.getAlterScriptFor(table); - Assert.assertTrue("There should have been no changes to the table. Instead, we received the alter script: " + alterSql,StringUtils.isBlank(alterSql)); + Assert.assertTrue( + "There should have been no changes to the table. Instead, we received the alter script: " + + alterSql, StringUtils.isBlank(alterSql)); } } diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransactionTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransactionTest.java index 156f93b8cd..97cac38c67 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransactionTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/sql/JdbcSqlTransactionTest.java @@ -35,7 +35,7 @@ public void testSuccessfulBatchInserts() { // committed, but in single connection databases the database is still // locked at this point. // Assert.assertEquals(0, count(testTable.getTableName())); - Assert.assertEquals(0, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(0, transaction.getUnflushedMarkers(true).size()); transaction.commit(); transaction.close(); @@ -50,9 +50,9 @@ public void testRollbackBatchInserts() { int flushAt = 11; prepareInsertIntoTestTable(transaction, testTable.getTableName(), flushAt, true); Assert.assertEquals(flushAt, batchInsertIntoTestTable(12, 1, transaction)); - Assert.assertEquals(1, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(1, transaction.getUnflushedMarkers(false).size()); Assert.assertEquals(1, transaction.flush()); - Assert.assertEquals(0, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(0, transaction.getUnflushedMarkers(false).size()); transaction.rollback(); transaction.close(); @@ -67,7 +67,7 @@ public void testDataIntegrityViolationInBatchMode() { int flushAt = 10; prepareInsertIntoTestTable(transaction, testTable.getTableName(), flushAt, true); Assert.assertEquals(flushAt, batchInsertIntoTestTable(10, 1, transaction)); - Assert.assertEquals(0, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(0, transaction.getUnflushedMarkers(false).size()); prepareInsertIntoTestTable(transaction, testTable.getTableName(), flushAt, true); try { Assert.assertEquals(0, batchInsertIntoTestTable(2, 11, transaction)); @@ -75,7 +75,7 @@ public void testDataIntegrityViolationInBatchMode() { transaction.flush(); Assert.fail("This should have failed"); } catch (DataIntegrityViolationException ex) { - Assert.assertEquals(4, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(4, transaction.getUnflushedMarkers(false).size()); } transaction.commit(); @@ -95,7 +95,7 @@ public void testNonBatchSuccessfulUpdates() { // committed, but in single connection databases the database is still // locked at this point. // Assert.assertEquals(0, count(testTable.getTableName())); - Assert.assertEquals(0, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(0, transaction.getUnflushedMarkers(false).size()); transaction.commit(); transaction.close(); @@ -109,7 +109,7 @@ public void testDataIntegrityViolationInNonBatchMode() { ISqlTransaction transaction = connection.startSqlTransaction(); prepareInsertIntoTestTable(transaction, testTable.getTableName(), -1, true); Assert.assertEquals(10, batchInsertIntoTestTable(10, 1, transaction)); - Assert.assertEquals(0, transaction.getUnflushedMarkers().size()); + Assert.assertEquals(0, transaction.getUnflushedMarkers(false).size()); prepareInsertIntoTestTable(transaction, testTable.getTableName(), -1, true); try { Assert.assertEquals(2, batchInsertIntoTestTable(2, 11, transaction)); diff --git a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyPropertiesTest.java b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyPropertiesTest.java index 0f9af153b6..b183df7bf6 100644 --- a/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyPropertiesTest.java +++ b/future/symmetric3-jdbc/src/test/java/org/jumpmind/symmetric/jdbc/tools/copy/TableCopyPropertiesTest.java @@ -13,11 +13,12 @@ public void testTableCopyProperties() throws Exception { TableCopyProperties properties = new TableCopyProperties(); properties.loadExample(); } - + @Test - public void testGetTargetDataSource() { + public void testGetTargetDataSource() { FileUtils.deleteDirectory("target/h2"); - TableCopyProperties properties = new TableCopyProperties("src/test/resources/test-tablecopy.properties"); + TableCopyProperties properties = new TableCopyProperties( + "src/test/resources/test-tablecopy.properties"); DataSource dataSource = properties.getTargetDataSource(); JdbcSqlConnection template = new JdbcSqlConnection(dataSource); template.update("create table test (test varchar(100))");