/* ================================================================== * GeneralDatumMapper.java - Apr 14, 2015 6:00:10 AM * * Copyright 2007-2015 SolarNetwork.net Dev Team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * ================================================================== */ package net.solarnetwork.central.in.biz.dao; import java.util.HashMap; import java.util.Map; import net.solarnetwork.central.datum.dao.GeneralLocationDatumDao; import net.solarnetwork.central.datum.domain.ConsumptionDatum; import net.solarnetwork.central.datum.domain.Datum; import net.solarnetwork.central.datum.domain.DatumMappingInfo; import net.solarnetwork.central.datum.domain.DayDatum; import net.solarnetwork.central.datum.domain.GeneralLocationDatum; import net.solarnetwork.central.datum.domain.GeneralNodeDatum; import net.solarnetwork.central.datum.domain.HardwareControlDatum; import net.solarnetwork.central.datum.domain.LocationDatum; import net.solarnetwork.central.datum.domain.NodeDatum; import net.solarnetwork.central.datum.domain.PowerDatum; import net.solarnetwork.central.datum.domain.PriceDatum; import net.solarnetwork.central.datum.domain.WeatherDatum; import net.solarnetwork.domain.GeneralLocationDatumSamples; import net.solarnetwork.domain.GeneralNodeDatumSamples; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Map {@link Datum} instances into {@link GeneralNodeDatum} instances, to help * migrate away from {@link Datum}. * * @author matt * @version 1.1 */ public class GeneralDatumMapper { private final DateTimeFormatter localTimeFormatter; private GeneralLocationDatumDao generalLocationDatumDao; private final Map<String, DatumMappingInfo> datumMappingInfoCache; private final Logger log = LoggerFactory.getLogger(getClass()); public GeneralDatumMapper() { super(); localTimeFormatter = new DateTimeFormatterBuilder().appendHourOfDay(2).appendLiteral(':') .appendMinuteOfHour(2).toFormatter(); datumMappingInfoCache = new HashMap<String, DatumMappingInfo>(16); } /** * Map a {@link Datum} object into a {@link GeneralNodeDatum} object. * * @param datum * The datum to map. * @return The mapped datum, or <em>null</em> if not supported. */ public GeneralNodeDatum mapDatum(Datum datum) { GeneralNodeDatum g = null; if ( datum instanceof ConsumptionDatum ) { g = mapConsumptionDatum((ConsumptionDatum) datum); } else if ( datum instanceof HardwareControlDatum ) { g = mapHardwareControlDatum((HardwareControlDatum) datum); } else if ( datum instanceof PowerDatum ) { g = mapPowerDatum((PowerDatum) datum); } log.trace("Mapped Datum {} to general form {}", datum, g); return g; } private GeneralNodeDatum mapBaseGeneralNodeDatumProperties(NodeDatum datum) { GeneralNodeDatum g = new GeneralNodeDatum(); g.setCreated(datum.getCreated() != null ? datum.getCreated() : new DateTime()); g.setNodeId(datum.getNodeId()); return g; } private GeneralNodeDatum mapConsumptionDatum(ConsumptionDatum datum) { assert datum != null; assert datum.getSourceId() != null; GeneralNodeDatumSamples samples = new GeneralNodeDatumSamples(); if ( datum.getWatts() != null ) { samples.putInstantaneousSampleValue("watts", datum.getWatts()); } if ( datum.getWattHourReading() != null ) { samples.putAccumulatingSampleValue("wattHours", datum.getWattHourReading()); } GeneralNodeDatum g = mapBaseGeneralNodeDatumProperties(datum); g.setSourceId(datum.getSourceId()); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } private GeneralNodeDatum mapHardwareControlDatum(HardwareControlDatum datum) { assert datum != null; // The source_id value could be in form source;prop where 'prop' is a property name. // If this is the case, we store only 'source' as the source_id, and name the JSON key the value of 'prop'. // If 'prop' is not defined, we name the JSON key 'val'. String[] source = (datum.getSourceId() != null ? datum.getSourceId() : "HardwareControl").split( ";", 2); String sourceId = source[0]; String propKey = "val"; if ( source.length > 1 ) { propKey = source[1]; } GeneralNodeDatumSamples samples = new GeneralNodeDatumSamples(); if ( datum.getIntegerValue() != null ) { samples.putStatusSampleValue(propKey, datum.getIntegerValue()); } else if ( datum.getFloatValue() != null ) { samples.putStatusSampleValue(propKey, datum.getFloatValue()); } GeneralNodeDatum g = mapBaseGeneralNodeDatumProperties(datum); g.setSourceId(sourceId); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } private GeneralNodeDatum mapPowerDatum(PowerDatum datum) { assert datum != null; assert datum.getSourceId() != null; GeneralNodeDatumSamples samples = new GeneralNodeDatumSamples(); if ( datum.getWatts() != null ) { samples.putInstantaneousSampleValue("watts", datum.getWatts()); } if ( datum.getWattHourReading() != null ) { samples.putAccumulatingSampleValue("wattHours", datum.getWattHourReading()); } GeneralNodeDatum g = mapBaseGeneralNodeDatumProperties(datum); g.setSourceId(datum.getSourceId()); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } /** * Map a {@link LocationDatum} object into a {@link GeneralLocationDatum} * object. * * @param datum * The datum to map. * @return The mapped datum, or <em>null</em> if not supported. */ public GeneralLocationDatum mapLocationDatum(LocationDatum datum) { GeneralLocationDatum g = null; if ( datum instanceof DayDatum ) { g = mapDayDatum((DayDatum) datum); } else if ( datum instanceof PriceDatum ) { g = mapPriceDatum((PriceDatum) datum); } else if ( datum instanceof WeatherDatum ) { g = mapWeatherDatum((WeatherDatum) datum); } log.trace("Mapped LocationDatum {} to general form {}", datum, g); return g; } private GeneralLocationDatum mapBaseGeneralLocationDatumProperties(LocationDatum datum) { GeneralLocationDatum g = new GeneralLocationDatum(); g.setCreated(datum.getCreated() != null ? datum.getCreated() : new DateTime()); g.setLocationId(datum.getLocationId()); return g; } private GeneralLocationDatum mapDayDatum(DayDatum datum) { assert datum != null; assert datum.getDay() != null; // get our mapping info to map source ID and location ID DatumMappingInfo info = getLocationDatumMappingInfo(datum); if ( info == null ) { return null; } GeneralLocationDatumSamples samples = new GeneralLocationDatumSamples(); if ( datum.getSunrise() != null ) { samples.putStatusSampleValue("sunrise", localTimeFormatter.print(datum.getSunrise())); } if ( datum.getSunset() != null ) { samples.putStatusSampleValue("sunset", localTimeFormatter.print(datum.getSunset())); } GeneralLocationDatum g = mapBaseGeneralLocationDatumProperties(datum); // creation date must be converted from local time to UTC DateTime day = datum.getDay().toDateTimeAtStartOfDay(DateTimeZone.forID(info.getTimeZoneId())); g.setCreated(day); g.setLocationId(info.getId()); g.setSourceId(info.getSourceId()); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } private GeneralLocationDatum mapWeatherDatum(WeatherDatum datum) { assert datum != null; assert datum.getInfoDate() != null; assert datum.getTemperatureCelsius() != null; // get our mapping info to map source ID and location ID DatumMappingInfo info = getLocationDatumMappingInfo(datum); if ( info == null ) { return null; } GeneralLocationDatumSamples samples = new GeneralLocationDatumSamples(); if ( datum.getTemperatureCelsius() != null ) { samples.putInstantaneousSampleValue("temp", datum.getTemperatureCelsius()); } if ( datum.getHumidity() != null ) { samples.putInstantaneousSampleValue("humidity", datum.getHumidity()); } if ( datum.getUvIndex() != null ) { samples.putInstantaneousSampleValue("uvIndex", datum.getUvIndex()); } if ( datum.getDewPoint() != null ) { samples.putInstantaneousSampleValue("dew", datum.getDewPoint()); } if ( datum.getBarometricPressure() != null ) { samples.putInstantaneousSampleValue("atm", (int) (datum.getBarometricPressure().floatValue() * 100)); } if ( datum.getVisibility() != null && datum.getVisibility().floatValue() < 1000f ) { samples.putInstantaneousSampleValue("visibility", (int) (datum.getVisibility().floatValue() * 1000)); } if ( datum.getSkyConditions() != null && datum.getSkyConditions().length() > 0 ) { samples.putStatusSampleValue("sky", datum.getSkyConditions()); } GeneralLocationDatum g = mapBaseGeneralLocationDatumProperties(datum); g.setCreated(datum.getInfoDate()); g.setLocationId(info.getId()); g.setSourceId(info.getSourceId()); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } private GeneralLocationDatum mapPriceDatum(PriceDatum datum) { assert datum != null; assert datum.getPrice() != null; // get our mapping info to map source ID and location ID DatumMappingInfo info = getLocationDatumMappingInfo(datum); if ( info == null ) { return null; } GeneralLocationDatumSamples samples = new GeneralLocationDatumSamples(); if ( datum.getPrice() != null ) { samples.putInstantaneousSampleValue("price", datum.getPrice()); } GeneralLocationDatum g = mapBaseGeneralLocationDatumProperties(datum); g.setCreated(datum.getCreated()); g.setLocationId(info.getId()); g.setSourceId(info.getSourceId()); if ( samples.getSampleData() != null && samples.getSampleData().size() > 0 ) { g.setSamples(samples); } return g; } private DatumMappingInfo getLocationDatumMappingInfo(LocationDatum datum) { final String key = datum.getClass().getSimpleName() + datum.getLocationId(); DatumMappingInfo info = datumMappingInfoCache.get(key); if ( info != null ) { return info; } info = generalLocationDatumDao.getMappingInfo(datum); if ( info != null ) { // note we're not concerned with thread safety here, assuming we might do DAO lookup more than once but that's OK datumMappingInfoCache.put(key, info); } return info; } public void setGeneralLocationDatumDao(GeneralLocationDatumDao generalLocationDatumDao) { this.generalLocationDatumDao = generalLocationDatumDao; } }