All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.agent.crnickl.mongodb.AccessMethodsForNumber Maven / Gradle / Ivy

There is a newer version: 2.0.1
Show newest version
/*
 *   Copyright 2012-2013 Hauser Olsson GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package ch.agent.crnickl.mongodb;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import ch.agent.crnickl.T2DBException;
import ch.agent.crnickl.T2DBMsg;
import ch.agent.crnickl.T2DBMsg.E;
import ch.agent.crnickl.api.Series;
import ch.agent.crnickl.api.Surrogate;
import ch.agent.crnickl.api.UpdatableSeries;
import ch.agent.crnickl.impl.ChronicleUpdatePolicy;
import ch.agent.crnickl.impl.Permission;
import ch.agent.crnickl.impl.ValueAccessMethods;
import ch.agent.t2.time.Range;
import ch.agent.t2.time.TimeDomain;
import ch.agent.t2.time.TimeIndex;
import ch.agent.t2.timeseries.Observation;
import ch.agent.t2.timeseries.TimeAddressable;
import ch.agent.t2.timeseries.TimeSeriesFactory;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

/**
 * An implementation of {@link ValueAccessMethods} for numeric data using {@link java.lang.Double}.
 *
 * @author Jean-Paul Vetterli
 */
public class AccessMethodsForNumber extends MongoDatabaseMethods implements ValueAccessMethods {
	
	/**
	 * Construct an access method object.
	 */
	public AccessMethodsForNumber() {
	}

	@Override
	public Range getRange(Series series) throws T2DBException {
		Range range = null;
		try {
			check(Permission.READ, series);
			Surrogate s = series.getSurrogate();
			BasicDBObject obj = (BasicDBObject) getObject(s, false);
			if (obj != null) {
				long first = obj.getLong(MongoDatabase.FLD_SER_FIRST);
				long last = obj.getLong(MongoDatabase.FLD_SER_LAST);
				range = new Range(series.getTimeDomain(), first, last);
			}
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50122, series.getName(true));
		}
		if (range == null)
			range = new Range(series.getTimeDomain());
		return range;
	}
	
	@Override
	public long getValues(Series series, Range range, TimeAddressable ts) throws T2DBException {
		if (range != null && range.isEmpty())
			return 0;
		long count = 0;
		try {
			check(Permission.READ, series);
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			count = extractValues(obj, range, ts);
		} catch (Exception e) {
			if (range == null)
				throw T2DBMsg.exception(e, E.E50121, series.getName(true));
			else
				throw T2DBMsg.exception(e, E.E50120, series.getName(true), range.toString());
		}
		return count;
	}
	
	private long extractValues(DBObject obj, Range range, TimeAddressable ts) throws Exception {
		if (range != null && range.isEmpty())
			return 0;
		long count = 0;
		@SuppressWarnings("unchecked")
		Map values = (Map) obj.get(MongoDatabase.FLD_SER_VALUES);
		for (String k : values.keySet()) {
			long t = Long.valueOf(k);
			if (range == null || range.isInRange(t)) {
				ts.put(t, values.get(k));
				count++;
			}
		}
		return count;
	}
	
	private Observation extractLastValue(BasicDBObject obj, TimeDomain domain, TimeIndex t) throws Exception {
		long first = obj.getLong(MongoDatabase.FLD_SER_FIRST);
		long last = obj.getLong(MongoDatabase.FLD_SER_LAST);
		Observation obs = null;
		long time = t == null ? last : t.asLong();
		if (last >= first && time >= first) {
			@SuppressWarnings("unchecked")
			Map values = (Map) obj.get(MongoDatabase.FLD_SER_VALUES);
			String key = null;
			if (time  >= last)
				key = Long.toString(last);
			else {
				TreeMap sorted = new TreeMap(values);
				key = sorted.headMap(Long.toString(time + 1)).lastKey();
			}
			obs = new Observation(domain.time(Long.valueOf(key)), values.get(key));
		}
		return obs;
	}
	
	private Observation extractFirstValue(BasicDBObject obj, TimeDomain domain, TimeIndex t) throws Exception {
		long first = obj.getLong(MongoDatabase.FLD_SER_FIRST);
		long last = obj.getLong(MongoDatabase.FLD_SER_LAST);
		Observation obs = null;
		long time = t == null ? first : t.asLong();
		if (last >= first && time <= last) {
			@SuppressWarnings("unchecked")
			Map values = (Map) obj.get(MongoDatabase.FLD_SER_VALUES);
			String key = null;
			if (time  <= first)
				key = Long.toString(first);
			else {
				TreeMap sorted = new TreeMap(values);
				key = sorted.tailMap(Long.toString(time)).firstKey();
			}
			obs = new Observation(domain.time(Long.valueOf(key)), values.get(key));
		}
		return obs;
	}
	
	@Override
	public Observation getFirst(Series series, TimeIndex time) throws T2DBException {
		try {
			check(Permission.READ, series);
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			return extractFirstValue((BasicDBObject) obj, series.getTimeDomain(),  time);
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50123, series.getName(true), time.toString());
		}
	}
	
	@Override
	public Observation getLast(Series series, TimeIndex time) throws T2DBException {
		try {
			check(Permission.READ, series);
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			return extractLastValue((BasicDBObject) obj, series.getTimeDomain(),  time);
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50124, series.getName(true), time.toString());
		}
	}

	@Override
	public boolean deleteValue(UpdatableSeries series, TimeIndex t, ChronicleUpdatePolicy policy) throws T2DBException {
		boolean done = false;
		try {
			check(Permission.MODIFY, series);
			policy.willDelete(series, t);
			policy.deleteValue(series, t);
			
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			// force sparse, so it's always possible to repair when there are excessive gaps
			TimeAddressable values = TimeSeriesFactory.make(series.getTimeDomain(), Double.class, true);
			extractValues(obj, null, values);
			if (values.getRange().isInRange(t)) {
				values.put(t, values.getMissingValue());
				done = true;
			}
			update(series, values);
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50113, series.getName(true), t.toString());
		} finally {
		}
		return done;
	}
	
	@Override
	public boolean updateSeries(UpdatableSeries series, Range range, ChronicleUpdatePolicy policy) throws T2DBException {
		boolean done = false;
		try {
			check(Permission.MODIFY, series);
			policy.willUpdate(series, range);
			done = policy.update(series, range);
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			// force sparse, so it's always possible to repair when there are excessive gaps
			TimeAddressable values = TimeSeriesFactory.make(series.getTimeDomain(), Double.class, true);
			extractValues(obj, null, values);
			if (values.setRange(range))
				done = true;
			update(series, values);
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50109, series.getName(true));
		} finally {
		}
		return done;
	}
	
	@Override
	public long updateValues(UpdatableSeries series, TimeAddressable values, ChronicleUpdatePolicy policy) throws T2DBException {
		long count = 0;
		
		try {
			check(Permission.MODIFY, series);
			Surrogate s = series.getSurrogate();
			DBObject obj = getObject(s, true);
			// force sparse, so it's always possible to repair when there are excessive gaps
			TimeAddressable current = TimeSeriesFactory.make(series.getTimeDomain(), Double.class, true);
			extractValues(obj, null, current);
			for(Observation obs : values) {
				current.put(obs.getIndex(), obs.getValue());
				count++;
			}
			update(series, current);
		} catch (Exception e) {
			throw T2DBMsg.exception(e, E.E50114, series.getName(true));
		}
		return count;
	}
	
	private void update(Series series, TimeAddressable values) throws T2DBException {
		com.mongodb.DBObject operation = null;
		Range range = values.getRange();
		Map data = new HashMap();
		for (Observation obs : values) {
			data.put(Long.toString(obs.getIndex()), obs.getValue());
		}
		operation = operation(Operator.SET, 
				MongoDatabase.FLD_SER_FIRST, range.getFirstIndex(),
				MongoDatabase.FLD_SER_LAST, range.getLastIndex(),
				MongoDatabase.FLD_SER_VALUES, data);
		
		Surrogate s = series.getSurrogate();
		getMongoDB(s).getSeries().update(asQuery(s.getId()), operation);
	}

	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy