Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.enterprisemath.dao.big.InMemoryBigEntityDao Maven / Gradle / Ivy
package com.enterprisemath.dao.big;
import com.enterprisemath.dao.filter.Criterium;
import com.enterprisemath.dao.filter.Direction;
import com.enterprisemath.dao.filter.Filter;
import com.enterprisemath.dao.filter.Operator;
import com.enterprisemath.dao.filter.Order;
import com.enterprisemath.utils.CsvUtils;
import com.enterprisemath.utils.Dates;
import com.enterprisemath.utils.DomainUtils;
import com.enterprisemath.utils.ValidationUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* Big entity data access layer which holds all objects in memory.
*
* @author radek.hecl
*/
public class InMemoryBigEntityDao implements BigEntityDao {
/**
* Builder object.
*/
public static class Builder {
/**
* Builds the result object.
*
* @return created object
*/
public InMemoryBigEntityDao build() {
return new InMemoryBigEntityDao(this);
}
}
/**
* Cache memory.
*/
private Map> cache = new HashMap>();
/**
* Creates new instance.
*
* @param builder builder object
*/
public InMemoryBigEntityDao(Builder builder) {
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
}
@Override
public void insertBigEntity(String type, BigEntity entity, InsertOptions options) {
if (!cache.containsKey(type)) {
cache.put(type, new ArrayList());
}
for (BigEntity ent : cache.get(type)) {
if (entity.getCode().equals(ent.getCode())) {
throw new RuntimeException("unique identification code violation exception: code = " + ent.getCode());
}
}
cache.get(type).add(entity);
}
@Override
public void insertBigEntities(String type, List entities, InsertOptions options) {
for (BigEntity ent : entities) {
insertBigEntity(type, ent, options);
}
}
@Override
public BigEntityIterator selectBigEntities(String type, Filter filter, Set fields, SelectOptions options) {
List filtered = selectByCriteria(type, filter.getCriteria());
List ordered = new ArrayList(filtered);
Collections.sort(ordered, new BigEntityComparator(filter.getOrders()));
int from = (int) filter.getFrom();
int limit = filter.getLimit() == null ? ordered.size() : filter.getLimit();
List res = new ArrayList(Math.min(limit, ordered.size()));
for (int i = from; i < from + limit && i < ordered.size(); ++i) {
BigEntity entity = ordered.get(i);
BigEntity.Builder resEntity = new BigEntity.Builder();
resEntity.setCode(entity.getCode());
for (String field : fields) {
resEntity.addField(field, entity.getFields().get(field));
}
res.add(resEntity.build());
}
return new EntIterator(res);
}
@Override
public long countBigEntities(String type, List> criteria, CountOptions options) {
return selectByCriteria(type, criteria).size();
}
@Override
public void updateBigEntity(String type, String code, BigEntityUpdate update, UpdateOptions options) {
if (update.getUpdateFields().isEmpty() && update.getDropFields().isEmpty()) {
return;
}
List entities = cache.get(type);
int index = -1;
for (int i = 0; i < entities.size(); ++i) {
if (entities.get(i).getCode().equals(code)) {
index = i;
break;
}
}
if (index == -1) {
return;
}
Map newFields = new HashMap(entities.get(index).getFields());
for (String fld : update.getUpdateFields().keySet()) {
newFields.put(fld, update.getUpdateFields().get(fld));
}
for (String fld : update.getDropFields()) {
newFields.remove(fld);
}
entities.set(index, new BigEntity.Builder().
setCode(code).
setFields(newFields).
build());
return;
}
@Override
public void deleteBigEntity(String type, String code, DeleteOptions options) {
List collection = cache.get(type);
if (collection == null) {
return;
}
for (int i = 0; i < collection.size(); ++i) {
if (collection.get(i).getCode().equals(code)) {
collection.remove(i);
return;
}
}
}
/**
* Selects entities by criteria.
*
* @param type type
* @param criteria criteria
* @return selected entities
*/
private List selectByCriteria(String type, List> criteria) {
List collection = cache.get(type);
if (collection == null) {
return Collections.emptyList();
}
List res = new ArrayList();
for (BigEntity entity : collection) {
boolean matched = true;
for (Criterium crit : criteria) {
Object critValue = crit.getValue();
if (critValue != null) {
if (critValue instanceof Enum>) {
critValue = ((Enum>) critValue).name();
}
else if (critValue instanceof Collection>) {
List vals = new ArrayList();
for (Object val : (Collection>) critValue) {
if (val != null && val instanceof Enum>) {
vals.add(((Enum>) val).name());
}
else {
vals.add(val);
}
}
critValue = vals;
}
}
Object entityValue = null;
if (crit.getColumn().equals("code")) {
entityValue = entity.getCode();
}
else {
entityValue = entity.getFields().get(crit.getColumn());
}
if (crit.getOperator().equals(Operator.EQUAL)) {
if (!DomainUtils.safeEquals(entityValue, critValue)) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.NOT_EQUAL)) {
if (DomainUtils.safeEquals(entityValue, critValue)) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.IN)) {
Collection col = (Collection) critValue;
if (!col.contains(entityValue)) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.GREATER)) {
ValidationUtils.guardInstanceOf(entityValue, Comparable.class, "value must be Comparable for greater criterium");
Comparable comparableVal = (Comparable) entityValue;
if (comparableVal.compareTo(critValue) <= 0) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.GREATER_OR_EQUAL)) {
ValidationUtils.guardInstanceOf(entityValue, Comparable.class, "value must be Comparable for greater or equal criterium");
Comparable comparableVal = (Comparable) entityValue;
if (comparableVal.compareTo(critValue) < 0) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.LESS)) {
ValidationUtils.guardInstanceOf(entityValue, Comparable.class, "value must be Comparable for less criterium");
Comparable comparableVal = (Comparable) entityValue;
if (comparableVal.compareTo(critValue) >= 0) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.LESS_OR_EQUAL)) {
ValidationUtils.guardInstanceOf(entityValue, Comparable.class, "value must be Comparable for less or equal criterium");
Comparable comparableVal = (Comparable) entityValue;
if (comparableVal.compareTo(critValue) > 0) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.LIKE)) {
ValidationUtils.guardInstanceOf(entityValue, String.class, "value must be String for like criterium");
String exp = (String) critValue;
exp = exp.replaceAll("%", ".*");
if (!((String) entityValue).matches(exp)) {
matched = false;
break;
}
}
else if (crit.getOperator().equals(Operator.LIKE_IGNORE_CASE)) {
ValidationUtils.guardInstanceOf(entityValue, String.class, "value must be String for like ignore case criterium");
String exp = (String) critValue;
exp = exp.replaceAll("%", ".*").toLowerCase();
if (!((String) entityValue).toLowerCase().matches(exp)) {
matched = false;
break;
}
}
else {
throw new RuntimeException("unsupported operator: " + crit);
}
}
if (matched) {
res.add(entity);
}
}
return res;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
/**
* Creates new instance.
*
* @return created instance
*/
public static InMemoryBigEntityDao create() {
return new InMemoryBigEntityDao.Builder().
build();
}
/**
* Creates new instance which is populated from the csv file.
*
* @param filePath path to the data file
* @return created instance
*/
public static InMemoryBigEntityDao createFromCsv(String filePath) {
try {
return createFromCsv(FileUtils.readFileToByteArray(new File(filePath)));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Creates new instance which is populated from the csv file.
*
* @param buf data buffer
* @return created instance
*/
public static InMemoryBigEntityDao createFromCsv(byte[] buf) {
List> csv = CsvUtils.parse(buf);
InMemoryBigEntityDao res = InMemoryBigEntityDao.create();
String collection = null;
List columns = null;
Map columnTypes = null;
for (List line : csv) {
if (line.isEmpty() || line.equals(Arrays.asList(""))) {
collection = null;
}
else if (collection == null) {
collection = line.get(0);
columns = null;
columnTypes = null;
}
else if (columns == null) {
columns = new ArrayList();
columnTypes = new HashMap();
for (String cell : line) {
if (cell.startsWith("(")) {
Map parts = separateBacket(cell);
columns.add(parts.get("out"));
columnTypes.put(parts.get("out"), parts.get("in"));
}
else {
columns.add(cell);
}
}
}
else {
BigEntity.Builder ent = new BigEntity.Builder();
for (int i = 0; i < line.size(); ++i) {
String column = columns.get(i);
String value = line.get(i);
String type = columnTypes.get(column);
if (value.startsWith("(")) {
Map parts = separateBacket(value);
value = parts.get("out");
type = parts.get("in");
}
if (type == null) {
type = "java.lang.String";
}
if (column.equals("code")) {
ValidationUtils.guardEquals("java.lang.String", type, "type must be java.lang.String for code: collection =" + collection);
ent.setCode(value);
}
else {
if (type.equals("not_defined")) {
continue;
}
if (type.equals("null")) {
ent.addField(column, null);
}
else if (type.equals("java.lang.String")) {
ent.addStringField(column, value);
}
else if (type.equals("java.lang.Boolean")) {
ent.addField(column, Boolean.valueOf(value));
}
else if (type.equals("java.lang.Integer")) {
ent.addField(column, Integer.valueOf(value));
}
else if (type.equals("java.lang.Double")) {
ent.addField(column, Double.valueOf(value));
}
else if (type.equals("java.util.Date")) {
ent.addField(column, Dates.parse(value, "yyyy/MM/dd HH:mm:ss.SSS"));
}
else {
throw new RuntimeException("unsupported column type, implement me: " + type);
}
}
}
res.insertBigEntity(collection, ent.build(), InsertOptions.createDefault());
}
}
return res;
}
/**
* Comparator for big entities.
*/
private static class BigEntityComparator implements Comparator {
/**
* Orders.
*/
private List> orders;
/**
* Creates new instance.
*
* @param orders orders
*/
public BigEntityComparator(List> orders) {
this.orders = DomainUtils.softCopyUnmodifiableList(orders);
}
@Override
public int compare(BigEntity o1, BigEntity o2) {
for (Order order : orders) {
Object val1 = order.getColumn().equals("code") ? o1.getCode() : o1.getFields().get(order.getColumn());
Object val2 = order.getColumn().equals("code") ? o2.getCode() : o2.getFields().get(order.getColumn());
ValidationUtils.guardInstanceOf(val1, Comparable.class, "val1 must be comparable");
ValidationUtils.guardInstanceOf(val2, Comparable.class, "val2 must be comparable");
Comparable val1Comp = (Comparable) val1;
Comparable val2Comp = (Comparable) val2;
int res = val1Comp.compareTo(val2Comp);
if (res != 0) {
if (order.getDirection().equals(Direction.ASCENDANT)) {
return res;
}
else if (order.getDirection().equals(Direction.DESCENDANT)) {
return -res;
}
else {
throw new RuntimeException("unknown direction: " + order.getDirection());
}
}
}
return 0;
}
}
/**
* Implementation of iterator for entities.
*/
private static class EntIterator implements BigEntityIterator {
/**
* Entities.
*/
private List entities;
/**
* Index.
*/
private int index = 0;
/**
* Lock object.
*/
private final Object lock = new Object();
/**
* Creates new instance.
*
* @param entities list of entities
*/
public EntIterator(List entities) {
this.entities = DomainUtils.softCopyList(entities);
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardNotNullCollection(entities, "entities cannot have null element");
}
@Override
public boolean isNextAvailable() {
synchronized (lock) {
return index < entities.size();
}
}
@Override
public BigEntity getNext() throws NoSuchElementException {
synchronized (lock) {
if (index >= entities.size()) {
throw new NoSuchElementException("iterator is consumed");
}
BigEntity res = entities.get(index);
index = index + 1;
return res;
}
}
}
/**
* Separates text in the bracket from other text.
*
* @param str string in the '(in)out' format
* @return map with 'in' and 'out' keys
*/
private static Map separateBacket(String str) {
String[] parts = str.split("\\)", 2);
if (parts.length == 1) {
return DomainUtils.createMap("in", parts[0].substring(1), "");
}
else {
return DomainUtils.createMap("in", parts[0].substring(1), "out", parts[1]);
}
}
}