Update summaries when billing rate configuration changes. Refactor some of the billing rate variable names to be more clear.

This commit is contained in:
MarkBryanMilligan 2021-08-11 14:12:27 -05:00
parent cb774d1950
commit 77ceec745c
17 changed files with 264 additions and 39 deletions

View File

@ -1,6 +1,7 @@
package com.lanternsoftware.dataaccess.currentmonitor; package com.lanternsoftware.dataaccess.currentmonitor;
import com.lanternsoftware.datamodel.currentmonitor.Account; import com.lanternsoftware.datamodel.currentmonitor.Account;
import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
import com.lanternsoftware.datamodel.currentmonitor.Breaker; import com.lanternsoftware.datamodel.currentmonitor.Breaker;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup; import com.lanternsoftware.datamodel.currentmonitor.BreakerGroup;
@ -28,6 +29,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -159,6 +161,32 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
putBreakerGroupEnergy(summary); putBreakerGroupEnergy(summary);
} }
private void rebuildSummaries(int _accountId, Collection<BillingRate> _rates) {
logger.info("Rebuilding summaries due to a change in {} rates", CollectionUtils.size(_rates));
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute"));
if (firstMinute == null)
return;
TimeZone tz = getTimeZoneForAccount(_accountId);
Map<String, BillingRate> rates = CollectionUtils.transformToMap(_rates, _r->String.format("%d%d", DaoSerializer.toLong(_r.getBeginEffective()), DaoSerializer.toLong(_r.getEndEffective())));
for (BillingRate rate : rates.values()) {
Date start = rate.getBeginEffective();
Date end = rate.getEndEffective();
Date now = new Date();
if ((start == null) || start.before(firstMinute.getMinuteAsDate()))
start = firstMinute.getMinuteAsDate();
if ((end == null) || end.after(now))
end = now;
rebuildSummaries(_accountId, start, end);
if (rate.isRecursAnnually()) {
while (end.before(now)) {
start = DateUtils.addYears(start, 1, tz);
end = DateUtils.addYears(end, 1, tz);
rebuildSummaries(_accountId, start, end);
}
}
}
}
@Override @Override
public void rebuildSummaries(int _accountId) { public void rebuildSummaries(int _accountId) {
HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute")); HubPowerMinute firstMinute = proxy.queryOne(HubPowerMinute.class, new DaoQuery("account_id", _accountId), DaoSort.sort("minute"));
@ -228,8 +256,20 @@ public class MongoCurrentMonitorDao implements CurrentMonitorDao {
DaoQuery configQuery = new DaoQuery("_id", String.valueOf(_config.getAccountId())); DaoQuery configQuery = new DaoQuery("_id", String.valueOf(_config.getAccountId()));
BreakerConfig oldConfig = proxy.queryOne(BreakerConfig.class, configQuery); BreakerConfig oldConfig = proxy.queryOne(BreakerConfig.class, configQuery);
if (oldConfig != null) { if (oldConfig != null) {
proxy.saveEntity("config_archive", DaoSerializer.toDaoEntity(oldConfig));
_config.setVersion(oldConfig.getVersion() + 1); _config.setVersion(oldConfig.getVersion() + 1);
if (NullUtils.isNotIdentical(_config, oldConfig)) {
DaoEntity oldEntity = DaoSerializer.toDaoEntity(oldConfig);
oldEntity.put("_id", String.format("%d-%d", oldConfig.getAccountId(), oldConfig.getVersion()));
oldEntity.put("account_id", oldConfig.getAccountId());
oldEntity.put("archive_date", DaoSerializer.toLong(new Date()));
proxy.saveEntity("config_archive", oldEntity);
executor.submit(() -> {
List<BillingRate> changedRates = new ArrayList<>(_config.getBillingRates());
changedRates.removeAll(CollectionUtils.makeNotNull(oldConfig.getBillingRates()));
if (!changedRates.isEmpty())
rebuildSummaries(_config.getAccountId(), changedRates);
});
}
} }
proxy.save(_config); proxy.save(_config);
} }

View File

@ -1,7 +0,0 @@
package com.lanternsoftware.datamodel.currentmonitor;
public enum BillingMode {
ANY_DIRECTION,
CONSUMPTION,
PRODUCTION;
}

View File

@ -5,13 +5,14 @@ import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Objects;
import java.util.TimeZone; import java.util.TimeZone;
@DBSerializable @DBSerializable
public class BillingRate { public class BillingRate {
private int meter; private int meter;
private int dayBillingCycleStart; private int dayBillingCycleStart;
private BillingMode mode; private GridFlow flow;
private double rate; private double rate;
private BillingCurrency currency; private BillingCurrency currency;
private int timeOfDayStart; private int timeOfDayStart;
@ -38,12 +39,12 @@ public class BillingRate {
dayBillingCycleStart = _dayBillingCycleStart; dayBillingCycleStart = _dayBillingCycleStart;
} }
public BillingMode getMode() { public GridFlow getFlow() {
return mode; return flow;
} }
public void setMode(BillingMode _mode) { public void setFlow(GridFlow _flow) {
mode = _mode; flow = _flow;
} }
public double getRate() { public double getRate() {
@ -118,8 +119,8 @@ public class BillingRate {
recursAnnually = _recursAnnually; recursAnnually = _recursAnnually;
} }
public boolean isApplicable(BillingMode _mode, int _meter, double _monthKWh, Date _time, TimeZone _tz) { public boolean isApplicable(GridFlow _mode, int _meter, double _monthKWh, Date _time, TimeZone _tz) {
if ((mode != BillingMode.ANY_DIRECTION) && (mode != _mode)) if ((flow != GridFlow.BOTH) && (flow != _mode))
return false; return false;
if ((meter != -1) && (_meter != meter)) if ((meter != -1) && (_meter != meter))
return false; return false;
@ -160,11 +161,24 @@ public class BillingRate {
return rate * _kWh; return rate * _kWh;
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
BillingRate that = (BillingRate) _o;
return meter == that.meter && dayBillingCycleStart == that.dayBillingCycleStart && Double.compare(that.rate, rate) == 0 && timeOfDayStart == that.timeOfDayStart && timeOfDayEnd == that.timeOfDayEnd && Double.compare(that.monthKWhStart, monthKWhStart) == 0 && Double.compare(that.monthKWhEnd, monthKWhEnd) == 0 && recursAnnually == that.recursAnnually && flow == that.flow && currency == that.currency && Objects.equals(beginEffective, that.beginEffective) && Objects.equals(endEffective, that.endEffective);
}
@Override
public int hashCode() {
return Objects.hash(meter, dayBillingCycleStart, flow, rate, currency, timeOfDayStart, timeOfDayEnd, monthKWhStart, monthKWhEnd, beginEffective, endEffective, recursAnnually);
}
public BillingRate duplicate() { public BillingRate duplicate() {
BillingRate r = new BillingRate(); BillingRate r = new BillingRate();
r.setMeter(meter); r.setMeter(meter);
r.setDayBillingCycleStart(dayBillingCycleStart); r.setDayBillingCycleStart(dayBillingCycleStart);
r.setMode(mode); r.setFlow(flow);
r.setRate(rate); r.setRate(rate);
r.setCurrency(currency); r.setCurrency(currency);
r.setTimeOfDayStart(timeOfDayStart); r.setTimeOfDayStart(timeOfDayStart);

View File

@ -1,10 +1,13 @@
package com.lanternsoftware.datamodel.currentmonitor; package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Objects;
@DBSerializable() @DBSerializable()
public class Breaker { public class Breaker implements IIdentical<Breaker> {
private static final int TANDEM_BREAKER_MASK = 3072; private static final int TANDEM_BREAKER_MASK = 3072;
private static final int SPACE_MASK = 1023; private static final int SPACE_MASK = 1023;
private static final int TANDEM_BREAKER_A_MASK = 1024; private static final int TANDEM_BREAKER_A_MASK = 1024;
@ -137,7 +140,7 @@ public class Breaker {
} }
public double getLowPassFilter() { public double getLowPassFilter() {
return Math.abs(lowPassFilter) < 0.05 ? 1.6: lowPassFilter; return Math.abs(lowPassFilter) < 0.05 ? 1.6 : lowPassFilter;
} }
public void setLowPassFilter(double _lowPassFilter) { public void setLowPassFilter(double _lowPassFilter) {
@ -161,7 +164,7 @@ public class Breaker {
} }
public double getCalibrationFactor() { public double getCalibrationFactor() {
return calibrationFactor == 0.0?1.0:calibrationFactor; return calibrationFactor == 0.0 ? 1.0 : calibrationFactor;
} }
public void setCalibrationFactor(double _calibrationFactor) { public void setCalibrationFactor(double _calibrationFactor) {
@ -196,15 +199,15 @@ public class Breaker {
} }
public static int portToChip(int _port) { public static int portToChip(int _port) {
return (_port < 9)?1:0; return (_port < 9) ? 1 : 0;
} }
public static int portToPin(int _port) { public static int portToPin(int _port) {
return (_port < 9)?_port-1:_port-8; return (_port < 9) ? _port - 1 : _port - 8;
} }
public static int toPort(int _chip, int _pin) { public static int toPort(int _chip, int _pin) {
return (_chip == 0)?_pin+8:_pin+1; return (_chip == 0) ? _pin + 8 : _pin + 1;
} }
public static boolean isTandemBreakerA(int _space) { public static boolean isTandemBreakerA(int _space) {
@ -224,7 +227,7 @@ public class Breaker {
} }
public static int toSpace(int _id) { public static int toSpace(int _id) {
return _id & (TANDEM_BREAKER_MASK |SPACE_MASK); return _id & (TANDEM_BREAKER_MASK | SPACE_MASK);
} }
public static String toSpaceDisplay(int _space) { public static String toSpaceDisplay(int _space) {
@ -238,4 +241,23 @@ public class Breaker {
public int getSpaceIndex() { public int getSpaceIndex() {
return space & SPACE_MASK; return space & SPACE_MASK;
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
Breaker breaker = (Breaker) _o;
return panel == breaker.panel && space == breaker.space;
}
@Override
public boolean isIdentical(Breaker _o) {
if (this == _o) return true;
return panel == _o.panel && space == _o.space && meter == _o.meter && hub == _o.hub && port == _o.port && sizeAmps == _o.sizeAmps && Double.compare(_o.calibrationFactor, calibrationFactor) == 0 && Double.compare(_o.lowPassFilter, lowPassFilter) == 0 && doublePower == _o.doublePower && Objects.equals(name, _o.name) && Objects.equals(description, _o.description) && polarity == _o.polarity && type == _o.type && Objects.equals(key, _o.key);
}
@Override
public int hashCode() {
return Objects.hash(panel, space);
}
} }

View File

@ -1,6 +1,7 @@
package com.lanternsoftware.datamodel.currentmonitor; package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.DaoSerializer; import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
@ -8,9 +9,10 @@ import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
@DBSerializable(autogen = false) @DBSerializable(autogen = false)
public class BreakerConfig { public class BreakerConfig implements IIdentical<BreakerConfig> {
@PrimaryKey @PrimaryKey
private int accountId; private int accountId;
private List<Meter> meters; private List<Meter> meters;
@ -182,4 +184,23 @@ public class BreakerConfig {
public BillingCurrency getCurrency() { public BillingCurrency getCurrency() {
return CollectionUtils.getFirst(CollectionUtils.transformToSet(billingRates, BillingRate::getCurrency)); return CollectionUtils.getFirst(CollectionUtils.transformToSet(billingRates, BillingRate::getCurrency));
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
BreakerConfig that = (BreakerConfig) _o;
return accountId == that.accountId && CollectionUtils.isEqual(meters, that.meters) && CollectionUtils.isEqual(panels, that.panels) && CollectionUtils.isEqual(breakerHubs, that.breakerHubs) && CollectionUtils.isEqual(breakerGroups, that.breakerGroups) && CollectionUtils.isEqual(billingRates, that.billingRates);
}
@Override
public boolean isIdentical(BreakerConfig _o) {
if (this == _o) return true;
return accountId == _o.accountId && CollectionUtils.isIdentical(meters, _o.meters) && CollectionUtils.isIdentical(panels, _o.panels) && CollectionUtils.isIdentical(breakerHubs, _o.breakerHubs) && CollectionUtils.isIdentical(breakerGroups, _o.breakerGroups) && CollectionUtils.isEqual(billingRates, _o.billingRates);
}
@Override
public int hashCode() {
return Objects.hash(accountId, meters, panels, breakerHubs, breakerGroups, billingRates, version);
}
} }

View File

@ -2,18 +2,18 @@ package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.CollectionUtils; import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.NullUtils; import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import com.lanternsoftware.util.dao.annotations.PrimaryKey; import com.lanternsoftware.util.dao.annotations.PrimaryKey;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@DBSerializable() @DBSerializable()
public class BreakerGroup { public class BreakerGroup implements IIdentical<BreakerGroup> {
@PrimaryKey private String id; @PrimaryKey private String id;
private int accountId; private int accountId;
private String name; private String name;
@ -186,6 +186,15 @@ public class BreakerGroup {
return Objects.equals(id, that.id); return Objects.equals(id, that.id);
} }
@Override
public boolean isIdentical(BreakerGroup _o) {
if (this == _o)
return true;
if (_o == null)
return false;
return NullUtils.isEqual(id, _o.id) && accountId == _o.accountId && NullUtils.isEqual(name, _o.name) && CollectionUtils.isIdentical(subGroups, _o.subGroups) && CollectionUtils.isIdentical(breakers, _o.breakers);
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id); return Objects.hash(id);

View File

@ -96,8 +96,8 @@ public class BreakerGroupEnergy {
double secondFromGrid; double secondFromGrid;
for (Map.Entry<MeterMinute, MeterMinuteValues> meter : meters.entrySet()) { for (Map.Entry<MeterMinute, MeterMinuteValues> meter : meters.entrySet()) {
double monthkWh = monthFromGrid/3600000; double monthkWh = monthFromGrid/3600000;
List<BillingRate> consumptionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(BillingMode.CONSUMPTION, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone)); List<BillingRate> consumptionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.FROM, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
List<BillingRate> productionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(BillingMode.PRODUCTION, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone)); List<BillingRate> productionRates = CollectionUtils.filter(_rates, _r->_r.isApplicable(GridFlow.TO, meter.getKey().meter, monthkWh, meter.getKey().minute, timezone));
for (int i = 0; i < 60; i++) { for (int i = 0; i < 60; i++) {
secondFromGrid = meter.getValue().usage[i] - meter.getValue().solar[i]; secondFromGrid = meter.getValue().usage[i] - meter.getValue().solar[i];
monthFromGrid += secondFromGrid; monthFromGrid += secondFromGrid;
@ -351,7 +351,7 @@ public class BreakerGroupEnergy {
return charge(_selectedBreakers, true); return charge(_selectedBreakers, true);
} }
public double charge(Set<String> _selectedBreakers, BillingMode _mode) { public double charge(Set<String> _selectedBreakers, GridFlow _mode) {
return charge(_selectedBreakers, true, _mode); return charge(_selectedBreakers, true, _mode);
} }
@ -359,7 +359,7 @@ public class BreakerGroupEnergy {
return charge(_selectedBreakers, _includeSubgroups, null); return charge(_selectedBreakers, _includeSubgroups, null);
} }
public double charge(Set<String> _selectedBreakers, boolean _includeSubgroups, BillingMode _mode) { public double charge(Set<String> _selectedBreakers, boolean _includeSubgroups, GridFlow _mode) {
double charge = 0.0; double charge = 0.0;
if (_includeSubgroups) { if (_includeSubgroups) {
for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) { for (BreakerGroupEnergy group : CollectionUtils.makeNotNull(subGroups)) {
@ -368,7 +368,7 @@ public class BreakerGroupEnergy {
} }
if ((energyBlocks != null) && ((_selectedBreakers == null) || _selectedBreakers.contains(getGroupId()))) { if ((energyBlocks != null) && ((_selectedBreakers == null) || _selectedBreakers.contains(getGroupId()))) {
for (EnergyBlock energy : energyBlocks) { for (EnergyBlock energy : energyBlocks) {
if ((_mode == null) || ((_mode == BillingMode.PRODUCTION) && energy.getCharge() < 0.0) || (_mode == BillingMode.CONSUMPTION && energy.getCharge() > 0.0)) if ((_mode == null) || ((_mode == GridFlow.TO) && energy.getCharge() < 0.0) || (_mode == GridFlow.FROM && energy.getCharge() > 0.0))
charge += energy.getCharge(); charge += energy.getCharge();
} }
} }

View File

@ -1,10 +1,13 @@
package com.lanternsoftware.datamodel.currentmonitor; package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Objects;
@DBSerializable @DBSerializable
public class BreakerHub { public class BreakerHub implements IIdentical<BreakerHub> {
private int hub; private int hub;
private double voltageCalibrationFactor; private double voltageCalibrationFactor;
private double portCalibrationFactor; private double portCalibrationFactor;
@ -50,4 +53,23 @@ public class BreakerHub {
public void setBluetoothMac(String _bluetoothMac) { public void setBluetoothMac(String _bluetoothMac) {
bluetoothMac = _bluetoothMac; bluetoothMac = _bluetoothMac;
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
BreakerHub that = (BreakerHub) _o;
return hub == that.hub;
}
@Override
public boolean isIdentical(BreakerHub _o) {
if (this == _o) return true;
return hub == _o.hub && Double.compare(_o.voltageCalibrationFactor, voltageCalibrationFactor) == 0 && Double.compare(_o.portCalibrationFactor, portCalibrationFactor) == 0 && frequency == _o.frequency && Objects.equals(bluetoothMac, _o.bluetoothMac);
}
@Override
public int hashCode() {
return Objects.hash(hub);
}
} }

View File

@ -1,9 +1,12 @@
package com.lanternsoftware.datamodel.currentmonitor; package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Objects;
@DBSerializable @DBSerializable
public class BreakerPanel { public class BreakerPanel implements IIdentical<BreakerPanel> {
private int accountId; private int accountId;
private String name; private String name;
private int index; private int index;
@ -49,4 +52,23 @@ public class BreakerPanel {
public void setMeter(int _meter) { public void setMeter(int _meter) {
meter = _meter; meter = _meter;
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
BreakerPanel that = (BreakerPanel) _o;
return accountId == that.accountId && index == that.index;
}
@Override
public boolean isIdentical(BreakerPanel _o) {
if (this == _o) return true;
return accountId == _o.accountId && index == _o.index && spaces == _o.spaces && meter == _o.meter && Objects.equals(name, _o.name);
}
@Override
public int hashCode() {
return Objects.hash(accountId, index);
}
} }

View File

@ -0,0 +1,7 @@
package com.lanternsoftware.datamodel.currentmonitor;
public enum GridFlow {
BOTH,
FROM,
TO;
}

View File

@ -1,9 +1,12 @@
package com.lanternsoftware.datamodel.currentmonitor; package com.lanternsoftware.datamodel.currentmonitor;
import com.lanternsoftware.util.IIdentical;
import com.lanternsoftware.util.dao.annotations.DBSerializable; import com.lanternsoftware.util.dao.annotations.DBSerializable;
import java.util.Objects;
@DBSerializable @DBSerializable
public class Meter { public class Meter implements IIdentical<Meter> {
private int accountId; private int accountId;
private int index; private int index;
private String name; private String name;
@ -31,4 +34,24 @@ public class Meter {
public void setName(String _name) { public void setName(String _name) {
name = _name; name = _name;
} }
@Override
public boolean equals(Object _o) {
if (this == _o) return true;
if (_o == null || getClass() != _o.getClass()) return false;
Meter meter = (Meter) _o;
return accountId == meter.accountId && index == meter.index;
}
@Override
public boolean isIdentical(Meter _o) {
if (this == _o) return true;
if (_o == null) return false;
return accountId == _o.accountId && index == _o.index && Objects.equals(name, _o.name);
}
@Override
public int hashCode() {
return Objects.hash(accountId, index);
}
} }

View File

@ -1,7 +1,7 @@
package com.lanternsoftware.datamodel.currentmonitor.dao; package com.lanternsoftware.datamodel.currentmonitor.dao;
import com.lanternsoftware.datamodel.currentmonitor.BillingCurrency; import com.lanternsoftware.datamodel.currentmonitor.BillingCurrency;
import com.lanternsoftware.datamodel.currentmonitor.BillingMode; import com.lanternsoftware.datamodel.currentmonitor.GridFlow;
import com.lanternsoftware.datamodel.currentmonitor.BillingRate; import com.lanternsoftware.datamodel.currentmonitor.BillingRate;
import com.lanternsoftware.util.dao.AbstractDaoSerializer; import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity; import com.lanternsoftware.util.dao.DaoEntity;
@ -29,7 +29,7 @@ public class BillingRateSerializer extends AbstractDaoSerializer<BillingRate>
DaoEntity d = new DaoEntity(); DaoEntity d = new DaoEntity();
d.put("meter", _o.getMeter()); d.put("meter", _o.getMeter());
d.put("day_billing_cycle_start", _o.getDayBillingCycleStart()); d.put("day_billing_cycle_start", _o.getDayBillingCycleStart());
d.put("mode", DaoSerializer.toEnumName(_o.getMode())); d.put("flow", DaoSerializer.toEnumName(_o.getFlow()));
d.put("rate", _o.getRate()); d.put("rate", _o.getRate());
d.put("unit", DaoSerializer.toEnumName(_o.getCurrency())); d.put("unit", DaoSerializer.toEnumName(_o.getCurrency()));
d.put("time_of_day_start", _o.getTimeOfDayStart()); d.put("time_of_day_start", _o.getTimeOfDayStart());
@ -48,7 +48,7 @@ public class BillingRateSerializer extends AbstractDaoSerializer<BillingRate>
BillingRate o = new BillingRate(); BillingRate o = new BillingRate();
o.setMeter(DaoSerializer.getInteger(_d, "meter")); o.setMeter(DaoSerializer.getInteger(_d, "meter"));
o.setDayBillingCycleStart(DaoSerializer.getInteger(_d, "day_billing_cycle_start")); o.setDayBillingCycleStart(DaoSerializer.getInteger(_d, "day_billing_cycle_start"));
o.setMode(DaoSerializer.getEnum(_d, "mode", BillingMode.class)); o.setFlow(DaoSerializer.getEnum(_d, "flow", GridFlow.class, GridFlow.BOTH));
o.setRate(DaoSerializer.getDouble(_d, "rate")); o.setRate(DaoSerializer.getDouble(_d, "rate"));
o.setCurrency(DaoSerializer.getEnum(_d, "unit", BillingCurrency.class)); o.setCurrency(DaoSerializer.getEnum(_d, "unit", BillingCurrency.class));
o.setTimeOfDayStart(DaoSerializer.getInteger(_d, "time_of_day_start")); o.setTimeOfDayStart(DaoSerializer.getInteger(_d, "time_of_day_start"));

View File

@ -1,8 +1,10 @@
package com.lanternsoftware.currentmonitor.servlet; package com.lanternsoftware.currentmonitor.servlet;
import com.lanternsoftware.currentmonitor.context.Globals; import com.lanternsoftware.currentmonitor.context.Globals;
import com.lanternsoftware.util.dao.auth.AuthCode;
import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig; import com.lanternsoftware.datamodel.currentmonitor.BreakerConfig;
import com.lanternsoftware.util.dao.auth.AuthCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.annotation.WebServlet; import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -10,6 +12,8 @@ import javax.servlet.http.HttpServletResponse;
@WebServlet("/config/*") @WebServlet("/config/*")
public class ConfigServlet extends SecureServlet { public class ConfigServlet extends SecureServlet {
private static final Logger logger = LoggerFactory.getLogger(ConfigServlet.class);
@Override @Override
protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) { protected void get(AuthCode _authCode, HttpServletRequest _req, HttpServletResponse _rep) {
if (isPath(_req, 0, "bin")) if (isPath(_req, 0, "bin"))
@ -29,6 +33,7 @@ public class ConfigServlet extends SecureServlet {
_rep.setStatus(401); _rep.setStatus(401);
return; return;
} }
logger.info("Received config for account {}", config.getAccountId());
Globals.dao.putConfig(config); Globals.dao.putConfig(config);
} }
} }

View File

@ -177,6 +177,30 @@ public class CollectionUtils {
return _arr[_arr.length - 1]; return _arr[_arr.length - 1];
} }
public static <T> boolean isEqual(Collection<T> _l1, Collection<T> _l2) {
if (size(_l1) != size(_l2))
return false;
Iterator<T> i1 = _l1.iterator();
Iterator<T> i2 = _l2.iterator();
while (i1.hasNext()) {
if (NullUtils.isNotEqual(i1.next(), i2.next()))
return false;
}
return true;
}
public static <T extends IIdentical<T>> boolean isIdentical(Collection<T> _l1, Collection<T> _l2) {
if (size(_l1) != size(_l2))
return false;
Iterator<T> i1 = _l1.iterator();
Iterator<T> i2 = _l2.iterator();
while (i1.hasNext()) {
if (NullUtils.isNotIdentical(i1.next(), i2.next()))
return false;
}
return true;
}
public static <T> boolean contains(Collection<T> _coll, T _t) { public static <T> boolean contains(Collection<T> _coll, T _t) {
if (_coll == null) if (_coll == null)
return false; return false;

View File

@ -1,11 +1,11 @@
package com.lanternsoftware.util; package com.lanternsoftware.util;
import java.sql.Time;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
public abstract class DateUtils { public abstract class DateUtils {
@ -405,6 +405,14 @@ public abstract class DateUtils {
return dateFormat(_format, _tz).format(_dt); return dateFormat(_format, _tz).format(_dt);
} }
public static String formatDate(int _format, TimeZone _tz, Date _dt) {
if (_dt == null)
return null;
DateFormat format = DateFormat.getDateInstance(_format, Locale.getDefault());
format.setTimeZone(_tz);
return format.format(_dt);
}
public static Date parse(String _format, String _date) { public static Date parse(String _format, String _date) {
return parse(_format, TimeZone.getTimeZone("UTC"), _date); return parse(_format, TimeZone.getTimeZone("UTC"), _date);
} }

View File

@ -0,0 +1,5 @@
package com.lanternsoftware.util;
public interface IIdentical<T> {
boolean isIdentical(T _other);
}

View File

@ -23,6 +23,16 @@ public class NullUtils {
return (b == null); return (b == null);
} }
public static <T extends IIdentical<T>> boolean isNotIdentical(T a, T b) {
return !isIdentical(a, b);
}
public static <T extends IIdentical<T>> boolean isIdentical(T a, T b) {
if (a != null)
return (b != null) && a.isIdentical(b);
return (b == null);
}
public static <T> boolean isNotEqual(T a, T b, IEquals<T> _equals) { public static <T> boolean isNotEqual(T a, T b, IEquals<T> _equals) {
return !isEqual(a, b, _equals); return !isEqual(a, b, _equals);
} }