package com.feedly.cassandra.dao; /** * Used to create a counter column in a mapped cassandra entity. Cassandra forces counter columns to live in their own column family however * the mapping library allows for counters to be intermingled with normal columns for ease of use and clarity. In most cases, they behave * similarly to other columns. The exceptions are * <ul> * <li>They may not be included in general collections of the form Map<String, Object> or List<Object>, including unmapped columns. * They may be included in narrowed collections of the form Map<String, CounterColumn> or List<CounterColumn>.</li> * <li>Due to synchronization issues, counter columns can not be indexed.</li> * <li>TTL is not supported for counter columns.</li> * </ul> * * <p> * The key method is {@link #setIncrement(Long)}. This sets the value that is used to modify the counter in cassandra when the column is saved. * * @author kireet */ public final class CounterColumn { private Long _stored; private Long _increment; public CounterColumn() { } public CounterColumn(long incr) { _increment = incr; } CounterColumn(Long stored, Long incr) { _stored = stored; _increment = incr; } /** * Get the counter value stored in cassandra. Note this may or may not be accurate as the method makes no attempt to refresh the stored * counter value. * @return the last loaded counter value. */ public Long getStored() { return _stored; } //package protected - should only be set by library when loading the counter value void setStored(Long stored) { _stored = stored; } /** * Get the counter increment. * @return the value by which to change the counter. */ public long getIncrement() { return _increment == null ? 0 : _increment; } /** * Set the counter increment * @param increment the value by which to change the counter. */ public void setIncrement(long increment) { _increment = increment; } /** * indicates whether a value is available. I.e., has a value been loaded from cassandra. * @return the counter status */ boolean dirty() { return _increment != null; } /** * indicates whether a value is available. I.e., has a value been loaded from cassandra. * @return the counter status */ public boolean available() { return _stored != null; } /** * Gets the modified counter value. Note this may or may not be accurate as the method makes no attempt to refresh the stored counter * value. * @return the modified counter value using the last loaded value and current increment. */ public long value() { if(_stored == null) throw new IllegalStateException("stored counter value not loaded"); return _stored + (_increment == null ? 0 : _increment); } void reset() { _increment = null; } private boolean nullSafeEquals(Object o1, Object o2) { if(o1 == o2) return true; if(o1 == null || o2 == null) return false; return o1.equals(o2); } @Override public boolean equals(Object obj) { if(obj instanceof CounterColumn) { CounterColumn other = (CounterColumn) obj; return nullSafeEquals(_increment, other._increment) && nullSafeEquals(_stored, other._stored); } return false; } @Override public String toString() { return String.format("%s (%d)", _stored, _increment); } }