/* ===================================================================
* DatumDataSourceLoggerJob.java
*
* Created Dec 1, 2009 4:35:24 PM
*
* Copyright 2007-2009 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.LinkedList;
import java.util.List;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
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;
/**
* Job to collect data from a {@link DatumDataSource} and persist that via a
* {@link DatumDao}.
*
* <p>
* This job simply calls {@link DatumDataSource#readCurrentDatum()} and if that
* returns a non-null object, passes that to {@link DatumDao#storeDatum(Datum)}.
* In essence, this job is for reading the current data available on some device
* and then persisting it to a (probably local) database.
* </p>
*
* <p>
* If the configured {@code datumDataSource} implements
* {@link MultiDatumDataSource} and the Class returned by
* {@link MultiDatumDataSource#getMultiDatumType()} is assignable to the Class
* returned by {@link DatumDataSource#getDatumType()} then
* {@link MultiDatumDataSource#readMultipleDatum()} will be called instead of
* {@link DatumDataSource#readCurrentDatum()}. Each {@code Datum} returned in
* the resulting Collection will be persisted to the configured {@link DatumDao}
* .
* </p>
*
* <p>
* The configurable properties of this class are:
* </p>
*
* <dl class="class-properties">
* <dt>datumDataSource</dt>
* <dd>The {@link DatumDataSource} to collect the data from. The
* {@link DatumDataSource#readCurrentDatum()} method will be called to get the
* currently available data.</dd>
*
* <dt>datumDao</dt>
* <dd>The {@link DatumDao} to persist the collected data to. The
* {@link DatumDao#storeDatum(Datum)} method will be called with the
* {@link Datum} returned by {@link DatumDataSource#readCurrentDatum()}, if it
* is non-null.</dd>
* </dl>
*
* @param <T>
* the Datum type for this job
* @author matt
* @version 2.0
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class DatumDataSourceLoggerJob<T extends Datum> extends AbstractJob {
private List<DatumDataSource<T>> datumDataSources = null;
private DatumDao<T> datumDao = null;
@Override
protected void executeInternal(JobExecutionContext jobContext) throws Exception {
for ( DatumDataSource<T> datumDataSource : datumDataSources ) {
try {
if ( log.isDebugEnabled() ) {
log.debug("Collecting [{}] from [{}]",
datumDataSource.getDatumType().getSimpleName(), datumDataSource);
}
Collection<T> datumList = null;
if ( datumDataSource instanceof MultiDatumDataSource<?> ) {
datumList = readMultiDatum(datumDataSource);
}
if ( datumList == null ) {
T datum = datumDataSource.readCurrentDatum();
if ( datum != null ) {
datumList = new LinkedList<T>();
datumList.add(datum);
}
}
if ( datumList == null || datumList.isEmpty() ) {
if ( log.isInfoEnabled() ) {
log.info("No data returned from [{}]", datumDataSource);
}
continue;
}
if ( log.isInfoEnabled() ) {
log.info("Got Datum to persist: {}", (datumList.size() == 1
? datumList.iterator().next().toString() : datumList.toString()));
}
for ( T datum : datumList ) {
try {
datumDao.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);
}
}
} catch ( Throwable e ) {
logThrowable(e);
}
}
}
@SuppressWarnings("unchecked")
private Collection<T> readMultiDatum(DatumDataSource<T> datumDataSource) {
MultiDatumDataSource<T> multi = (MultiDatumDataSource<T>) datumDataSource;
if ( !datumDataSource.getDatumType().isAssignableFrom(multi.getMultiDatumType()) ) {
return null;
}
return multi.readMultipleDatum();
}
public DatumDataSource<T> getDatumDataSource() {
return datumDataSources == null || datumDataSources.size() < 1 ? null : datumDataSources.get(0);
}
public void setDatumDataSource(DatumDataSource<T> datumDataSource) {
if ( this.datumDataSources == null ) {
this.datumDataSources = new ArrayList<DatumDataSource<T>>(2);
}
this.datumDataSources.clear();
this.datumDataSources.add(datumDataSource);
}
public List<DatumDataSource<T>> getDatumDataSources() {
return datumDataSources;
}
public void setDatumDataSources(List<DatumDataSource<T>> datumDataSources) {
this.datumDataSources = datumDataSources;
}
public DatumDao<T> getDatumDao() {
return datumDao;
}
public void setDatumDao(DatumDao<T> datumDao) {
this.datumDao = datumDao;
}
}