/* ================================================================== * DatumDataSourceManagedLoggerJob.java - Aug 26, 2014 2:44:36 PM * * Copyright 2007-2014 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.node.job; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobExecutionContext; import org.quartz.PersistJobDataAfterExecution; import org.springframework.context.MessageSource; import org.springframework.dao.DuplicateKeyException; import net.solarnetwork.node.DatumDataSource; import net.solarnetwork.node.MultiDatumDataSource; import net.solarnetwork.node.dao.DatumDao; import net.solarnetwork.node.domain.Datum; import net.solarnetwork.node.settings.KeyedSettingSpecifier; import net.solarnetwork.node.settings.SettingSpecifier; import net.solarnetwork.node.settings.SettingSpecifierProvider; import net.solarnetwork.util.OptionalService; /** * Extension of {@link DatumDataSourceLoggerJob} designed to be used as a * managed service. * * <p> * This class implements {@link SettingSpecifierProvider} but delegates that API * to the configured {@link #getDatumDataSource()}. * </p> * * @author matt * @version 2.0 */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public class DatumDataSourceManagedLoggerJob<T extends Datum> extends AbstractJob implements SettingSpecifierProvider { private DatumDataSource<T> datumDataSource = null; private MultiDatumDataSource<T> multiDatumDataSource = null; private OptionalService<DatumDao<T>> datumDao = null; @Override protected void executeInternal(JobExecutionContext jobContext) throws Exception { try { if ( multiDatumDataSource != null ) { executeForMultiDatumDataSource(jobContext); } else { executeForDatumDataSource(jobContext); } } catch ( Throwable e ) { logThrowable(e); } } private void executeForDatumDataSource(JobExecutionContext jobContext) { if ( log.isDebugEnabled() ) { log.debug("Collecting [{}] from [{}]", datumDataSource.getDatumType().getSimpleName(), datumDataSource); } T datum = datumDataSource.readCurrentDatum(); if ( datum != null ) { persistDatum(Collections.singleton(datum)); } else { log.info("No data returned from [{}]", datumDataSource); } } private void executeForMultiDatumDataSource(JobExecutionContext jobContext) { if ( log.isDebugEnabled() ) { log.debug("Collecting [{}] from [{}]", multiDatumDataSource.getMultiDatumType().getSimpleName(), multiDatumDataSource); } Collection<T> datum = multiDatumDataSource.readMultipleDatum(); if ( datum != null && datum.size() > 0 ) { persistDatum(datum); } else { log.info("No data returned from [{}]", multiDatumDataSource); } } private void persistDatum(Collection<T> datumList) { if ( datumList == null || datumList.size() < 1 ) { return; } if ( log.isInfoEnabled() ) { log.info("Got Datum to persist: {}", (datumList.size() == 1 ? datumList.iterator().next().toString() : datumList.toString())); } DatumDao<T> dao = datumDao.service(); if ( dao == null ) { log.info("No DatumDao available to persist {}, not saving", datumList); return; } for ( T datum : datumList ) { try { dao.storeDatum(datum); log.debug("Persisted Datum {}", datum); } catch ( DuplicateKeyException e ) { // we ignore duplicate key exceptions, as we sometimes collect the same // datum multiple times for redundancy log.info("Duplicate datum {}; not persisting", datum); } } } private SettingSpecifierProvider getSettingSpecifierProvider() { if ( multiDatumDataSource instanceof SettingSpecifierProvider ) { return (SettingSpecifierProvider) multiDatumDataSource; } if ( datumDataSource instanceof SettingSpecifierProvider ) { return (SettingSpecifierProvider) datumDataSource; } return null; } @Override public String getSettingUID() { SettingSpecifierProvider delegate = getSettingSpecifierProvider(); if ( delegate != null ) { return delegate.getSettingUID(); } return getDatumDataSource().getClass().getName(); } @Override public String getDisplayName() { SettingSpecifierProvider delegate = getSettingSpecifierProvider(); if ( delegate != null ) { return delegate.getDisplayName(); } return null; } @Override public MessageSource getMessageSource() { SettingSpecifierProvider delegate = getSettingSpecifierProvider(); if ( delegate != null ) { return delegate.getMessageSource(); } return null; } @Override public List<SettingSpecifier> getSettingSpecifiers() { SettingSpecifierProvider delegate = getSettingSpecifierProvider(); if ( delegate == null ) { return Collections.emptyList(); } List<SettingSpecifier> result = new ArrayList<SettingSpecifier>(); final String prefix = (multiDatumDataSource != null ? "multiDatumDataSource." : "datumDataSource."); for ( SettingSpecifier spec : delegate.getSettingSpecifiers() ) { if ( spec instanceof KeyedSettingSpecifier<?> ) { KeyedSettingSpecifier<?> keyedSpec = (KeyedSettingSpecifier<?>) spec; result.add(keyedSpec.mappedTo(prefix)); } else { result.add(spec); } } return result; } public DatumDataSource<T> getDatumDataSource() { return datumDataSource; } public void setDatumDataSource(DatumDataSource<T> datumDataSource) { this.datumDataSource = datumDataSource; } public MultiDatumDataSource<T> getMultiDatumDataSource() { return multiDatumDataSource; } public void setMultiDatumDataSource(MultiDatumDataSource<T> multiDatumDataSource) { this.multiDatumDataSource = multiDatumDataSource; } public OptionalService<DatumDao<T>> getDatumDao() { return datumDao; } public void setDatumDao(OptionalService<DatumDao<T>> datumDao) { this.datumDao = datumDao; } }