stream.data.AssertTypes Maven / Gradle / Ivy
/*
* streams library
*
* Copyright (C) 2011-2014 by Christian Bockermann, Hendrik Blom
*
* streams is a library, API and runtime environment for processing high
* volume data streams. It is composed of three submodules "stream-api",
* "stream-core" and "stream-runtime".
*
* The streams library (and its submodules) is free software: you can
* redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The stream.ai library (and its submodules) 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package stream.data;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import stream.AbstractProcessor;
import stream.Data;
import stream.ProcessContext;
import stream.service.AssertionService;
/**
* This processor may be used to raise errors if any of the specified type
* checks fails for processed data items.
*
* @author Christian Bockermann
*
*/
public class AssertTypes extends AbstractProcessor implements AssertionService {
static Logger log = LoggerFactory.getLogger(AssertTypes.class);
String id = "AssertTypes";
String types[];
ExpectedDataTypes expected;
Long assertions = 0L;
Long assertionErrors = 0L;
/**
* @see stream.AbstractProcessor#init(stream.ProcessContext)
*/
@Override
public void init(ProcessContext ctx) throws Exception {
super.init(ctx);
if (types != null && types.length > 0) {
expected = new ExpectedDataTypes();
for (String typeDef : types) {
log.info("Parsing type-def {}", typeDef);
String[] tok = typeDef.split("::");
String key = tok[0];
String val = tok[1];
String type = val;
int len = -1;
int idx = val.lastIndexOf("[");
if (idx > 0) {
int end = val.indexOf("]", idx);
if (end > 0) {
len = new Integer(val.substring(idx + 1, end));
type = val.substring(0, idx);
}
}
Class> valType = Class.forName(type);
log.info(" {} ~> {}", key, valType);
if (len > 0) {
//
// need to create array of type 'type'
//
// Object array = Array.newInstance(valType, len);
expected.addArray(key, valType, len);
// expected.addType(key, array.getClass());
} else {
expected.addType(key, valType);
}
}
}
}
/**
* @see stream.Processor#process(stream.Data)
*/
@Override
public Data process(Data input) {
if (types == null || expected == null) {
return input;
} else {
assertions++;
Boolean typesOk = expected.check(input);
if (!typesOk)
assertionErrors++;
if (this.id != null) {
input.put(id, typesOk);
}
}
return input;
}
/**
* @return the types
*/
public String[] getTypes() {
return types;
}
/**
* @param types
* the types to set
*/
public void setTypes(String[] types) {
this.types = types;
}
/**
* @author chris
*
*/
public class ExpectedDataTypes {
Logger log = LoggerFactory.getLogger(ExpectedDataTypes.class);
Map> types = new LinkedHashMap>();
Map arrayLength = new LinkedHashMap();
public ExpectedDataTypes() {
}
public void addType(String key, Class> typeValue) {
types.put(key, typeValue);
arrayLength.remove(key);
}
public void addArray(String key, Class> typeValue, int len) {
types.put(key, typeValue);
arrayLength.put(key, len);
}
public boolean check(Data item) {
log.info("Checking {} types for item {}", types.keySet().size(),
item);
for (String key : types.keySet()) {
if (!item.containsKey(key)) {
log.error("Missing key '{}' in item {}!", key, item);
return false;
}
if (!checkType(key, item)) {
log.error("Value type mismatch for key '" + key
+ "', expected type: {} but found type: {}",
types.get(key), item.get(key).getClass());
return false;
}
}
return true;
}
protected boolean checkType(String key, Data item) {
if (!types.containsKey(key)) {
return true;
}
if (!item.containsKey(key)) {
log.info("No attribute found for key '{}'", key);
return false;
}
Class> type = item.get(key).getClass();
Class> expType = types.get(key);
Integer expLength = this.arrayLength.get(key);
if (expLength == null) {
log.info("Checking type {} against {}", expType, item.get(key)
.getClass());
return expType.equals(item.get(key).getClass());
} else {
if (!type.isArray()) {
log.error("Expected array type!");
return false;
}
if (!type.getComponentType().equals(expType)) {
log.error("Found array of type {} but {} was expected!",
type, expType);
return false;
}
if (expLength >= 0
&& expLength != Array.getLength(item.get(key))) {
int len = Array.getLength(item.get(key));
log.error(
"Array length mismatch! Found array of length {} but {} was expected!",
len, expLength);
return false;
}
}
return true;
}
protected boolean checkValues(String key, Serializable exp,
Serializable found) {
if (!valuesMatch(exp, found)) {
log.error("Value mismatch for key '{}'", key);
return false;
}
return true;
}
private boolean valuesMatch(Serializable val1, Serializable val2) {
if (val1 == val2)
return true;
if (val1 == null || val2 == null)
return false;
if (val1.getClass().isArray() && val2.getClass().isArray()) {
return arraysMatch(val1, val2);
}
if (!val1.getClass().equals(val2.getClass())) {
log.error("Value types differ: {} and {}", val1.getClass(),
val2.getClass());
return false;
}
return val1.equals(val2);
}
private boolean arraysMatch(Object array1, Object array2) {
Class> ct1 = array1.getClass().getComponentType();
Class> ct2 = array2.getClass().getComponentType();
if (!array1.getClass().getComponentType()
.equals(array2.getClass().getComponentType())) {
log.error("Component type mismatch for arrays: {}[] and {}[]",
ct1, ct2);
return false;
}
if (Array.getLength(array1) != Array.getLength(array2)) {
log.error("Array length mismatch!");
return false;
}
log.info("Arrays equal.");
return true;
}
}
/**
* @see stream.service.Service#reset()
*/
@Override
public void reset() throws Exception {
this.assertions = 0L;
this.assertionErrors = 0L;
}
/**
* @see stream.service.AssertionService#getAssertions()
*/
@Override
public Long getAssertions() {
return new Long(this.assertions);
}
/**
* @see stream.service.AssertionService#getAssertionErrors()
*/
@Override
public Long getAssertionErrors() {
return new Long(this.assertionErrors);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy