blob: 97abd18297aa95dd4e46034fc7afdaa2348be03c [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.ofbiz.entity.datasource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import org.ofbiz.base.concurrent.ExecutionPool;
import org.ofbiz.base.util.Debug;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericNotImplementedException;
import org.ofbiz.entity.GenericPK;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.config.model.Datasource;
import org.ofbiz.entity.config.EntityConfigUtil;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.jdbc.SqlJdbcUtil;
import org.ofbiz.entity.model.ModelEntity;
import org.ofbiz.entity.model.ModelField;
import org.ofbiz.entity.model.ModelFieldTypeReader;
import org.ofbiz.entity.model.ModelRelation;
import org.ofbiz.entity.util.EntityFindOptions;
import org.ofbiz.entity.util.EntityListIterator;
/**
* Partial GenericHelper implementation that is entirely memory-based,
* to be used for simple unit testing (can't do anything beyond searches
* for primary keys, findByOr and findByAnd).
*
*/
public class MemoryHelper implements GenericHelper {
public static final String module = MemoryHelper.class.getName();
private static Map<String, HashMap<GenericPK, GenericValue>> cache = new HashMap<String, HashMap<GenericPK, GenericValue>>();
private static final ThreadGroup MEMORY_HELPER_THREAD_GROUP = new ThreadGroup("MemoryHelper");
public static void clearCache() {
cache = new HashMap<String, HashMap<GenericPK, GenericValue>>();
}
private String helperName;
protected ExecutorService executor;
private boolean addToCache(GenericValue value) {
if (value == null) {
return false;
}
if (!veryifyValue(value)) {
return false;
}
value = (GenericValue) value.clone();
HashMap<GenericPK, GenericValue> entityCache = cache.get(value.getEntityName());
if (entityCache == null) {
entityCache = new HashMap<GenericPK, GenericValue>();
cache.put(value.getEntityName(), entityCache);
}
entityCache.put(value.getPrimaryKey(), value);
return true;
}
private GenericValue findFromCache(GenericPK pk) {
if (pk == null) {
return null;
}
HashMap<GenericPK, GenericValue> entityCache = cache.get(pk.getEntityName());
if (entityCache == null) {
return null;
}
GenericValue value = entityCache.get(pk);
if (value == null) {
return null;
} else {
return (GenericValue) value.clone();
}
}
private int removeFromCache(GenericPK pk) {
if (pk == null) {
return 0;
}
HashMap<GenericPK, GenericValue> entityCache = cache.get(pk.getEntityName());
if (entityCache == null) {
return 0;
}
Object o = entityCache.remove(pk);
if (o == null) {
return 0;
} else {
return 1;
}
}
private int removeFromCache(String entityName, EntityCondition condition) {
if (entityName == null || condition == null) {
return 0;
}
HashMap<GenericPK, GenericValue> entityCache = cache.get(entityName);
if (entityCache == null) {
return 0;
}
Iterator<GenericValue> it = entityCache.values().iterator();
int count = 0;
while (it.hasNext()) {
GenericValue value = it.next();
if (condition.entityMatches(value)) {
it.remove();
count++;
}
}
return count;
}
private boolean isAndMatch(Map<String, Object> values, Map<String, Object> fields) {
for (Map.Entry<String, Object> mapEntry: fields.entrySet()) {
if (mapEntry.getValue() == null) {
if (values.get(mapEntry.getKey()) != null) {
return false;
}
} else {
try {
if (!mapEntry.getValue().equals(values.get(mapEntry.getKey()))) {
return false;
}
} catch (Exception e) {
return false;
}
}
}
return true;
}
private boolean isOrMatch(Map<String, Object> values, Map<String, Object> fields) {
for (Map.Entry<String, Object> mapEntry: fields.entrySet()) {
if (mapEntry.getValue() == null) {
if (values.get(mapEntry.getKey()) == null) {
return true;
}
} else {
try {
if (mapEntry.getValue().equals(values.get(mapEntry.getKey()))) {
return true;
}
} catch (Exception e) {
Debug.logError(e, module);
}
}
}
return false;
}
private boolean veryifyValue(GenericValue value) {
ModelEntity me = value.getModelEntity();
// make sure the PKs exist
for (Iterator<ModelField> iterator = me.getPksIterator(); iterator.hasNext();) {
ModelField field = iterator.next();
if (!value.containsKey(field.getName())) {
return false;
}
}
// make sure the value doesn't have any extra (unknown) fields
for (Map.Entry<String, Object> entry: value.entrySet()) {
if (me.getField(entry.getKey()) == null) {
return false;
}
}
// make sure all fields that are in the value are of the right type
for (Iterator<ModelField> iterator = me.getFieldsIterator(); iterator.hasNext();) {
ModelField field = iterator.next();
Object o = value.get(field.getName());
int typeValue = 0;
try {
typeValue = SqlJdbcUtil.getType(modelFieldTypeReader.getModelFieldType(field.getType()).getJavaType());
} catch (GenericNotImplementedException e) {
return false;
}
if (o != null) {
switch (typeValue) {
case 1:
if (!(o instanceof String)) {
return false;
}
break;
case 2:
if (!(o instanceof java.sql.Timestamp)) {
return false;
}
break;
case 3:
if (!(o instanceof java.sql.Time)) {
return false;
}
break;
case 4:
if (!(o instanceof java.sql.Date)) {
return false;
}
break;
case 5:
if (!(o instanceof Integer)) {
return false;
}
break;
case 6:
if (!(o instanceof Long)) {
return false;
}
break;
case 7:
if (!(o instanceof Float)) {
return false;
}
break;
case 8:
if (!(o instanceof Double)) {
return false;
}
break;
case 10:
if (!(o instanceof Boolean)) {
return false;
}
break;
}
}
}
return true;
}
private ModelFieldTypeReader modelFieldTypeReader;
public MemoryHelper(String helperName) {
this.helperName = helperName;
modelFieldTypeReader = ModelFieldTypeReader.getModelFieldTypeReader(helperName);
Datasource datasourceInfo = EntityConfigUtil.getDatasource(helperName);
this.executor = ExecutionPool.getExecutor(MEMORY_HELPER_THREAD_GROUP, "OFBiz-entity-datasource(" + helperName + ")", datasourceInfo.getMaxWorkerPoolSize(), false);
}
public String getHelperName() {
return helperName;
}
public <T> Future<T> submitWork(Callable<T> callable) throws GenericEntityException {
return this.executor.submit(callable);
}
public GenericValue create(GenericValue value) throws GenericEntityException {
if (addToCache(value)) {
return value;
} else {
return null;
}
}
public GenericValue create(GenericPK primaryKey) throws GenericEntityException {
return create(GenericValue.create(primaryKey));
}
public GenericValue findByPrimaryKey(GenericPK primaryKey) throws GenericEntityException {
return findFromCache(primaryKey);
}
public GenericValue findByPrimaryKeyPartial(GenericPK primaryKey, Set<String> keys) throws GenericEntityException {
GenericValue value = findFromCache(primaryKey);
value.setFields(value.getFields(keys));
return value;
}
public List<GenericValue> findAllByPrimaryKeys(List<GenericPK> primaryKeys) throws GenericEntityException {
ArrayList<GenericValue> result = new ArrayList<GenericValue>(primaryKeys.size());
for (GenericPK pk: primaryKeys) {
result.add(this.findByPrimaryKey(pk));
}
return result;
}
public int removeByPrimaryKey(GenericPK primaryKey) throws GenericEntityException {
return removeFromCache(primaryKey);
}
public List<GenericValue> findByAnd(ModelEntity modelEntity, Map<String, Object> fields, List<String> orderBy) throws GenericEntityException {
HashMap<GenericPK, GenericValue> entityCache = cache.get(modelEntity.getEntityName());
if (entityCache == null) {
return Collections.emptyList();
}
ArrayList<GenericValue> result = new ArrayList<GenericValue>();
for (GenericValue value: entityCache.values()) {
if (isAndMatch(value.getAllFields(), fields)) {
result.add(value);
}
}
return result;
}
public List<GenericValue> findByAnd(ModelEntity modelEntity, List<EntityCondition> expressions, List<String> orderBy) throws GenericEntityException {
return null;
}
public List<GenericValue> findByLike(ModelEntity modelEntity, Map<String, Object> fields, List<String> orderBy) throws GenericEntityException {
return null;
}
public List<GenericValue> findByOr(ModelEntity modelEntity, Map<String, Object> fields, List<String> orderBy) throws GenericEntityException {
HashMap<GenericPK, GenericValue> entityCache = cache.get(modelEntity.getEntityName());
if (entityCache == null) {
return Collections.emptyList();
}
ArrayList<GenericValue> result = new ArrayList<GenericValue>();
for (GenericValue value: entityCache.values()) {
if (isOrMatch(value.getAllFields(), fields)) {
result.add(value);
}
}
return result;
}
public List<GenericValue> findByOr(ModelEntity modelEntity, List<EntityCondition> expressions, List<String> orderBy) throws GenericEntityException {
return null;
}
public List<GenericValue> findByCondition(ModelEntity modelEntity, EntityCondition entityCondition,
Collection<String> fieldsToSelect, List<String> orderBy) throws GenericEntityException {
return null;
}
public List<GenericValue> findByMultiRelation(GenericValue value, ModelRelation modelRelationOne, ModelEntity modelEntityOne,
ModelRelation modelRelationTwo, ModelEntity modelEntityTwo, List<String> orderBy) throws GenericEntityException {
return null;
}
public EntityListIterator findListIteratorByCondition(ModelEntity modelEntity, EntityCondition whereEntityCondition,
EntityCondition havingEntityCondition, Collection<String> fieldsToSelect, List<String> orderBy, EntityFindOptions findOptions)
throws GenericEntityException {
return null;
}
public long findCountByCondition(ModelEntity modelEntity, EntityCondition whereEntityCondition, EntityCondition havingEntityCondition, EntityFindOptions findOptions) throws GenericEntityException {
return 0;
}
public int removeByAnd(ModelEntity modelEntity, Map<String, Object> fields) throws GenericEntityException {
HashMap<GenericPK, GenericValue> entityCache = cache.get(modelEntity.getEntityName());
if (entityCache == null) {
return 0;
}
ArrayList<GenericPK> removeList = new ArrayList<GenericPK>();
for (Map.Entry<GenericPK, GenericValue> mapEntry: entityCache.entrySet()) {
GenericValue value = mapEntry.getValue();
if (isAndMatch(value.getAllFields(), fields)) {
removeList.add(mapEntry.getKey());
}
}
return removeAll(removeList);
}
public int removeByCondition(ModelEntity modelEntity, EntityCondition condition) throws GenericEntityException {
return removeFromCache(modelEntity.getEntityName(), condition);
}
public int storeByCondition(ModelEntity modelEntity, Map<String, ? extends Object> fieldsToSet, EntityCondition condition) throws GenericEntityException {
return 0;
}
public int store(GenericValue value) throws GenericEntityException {
if (addToCache(value)) {
return 1;
} else {
return 0;
}
}
public int storeAll(List<GenericValue> values) throws GenericEntityException {
int count = 0;
for (GenericValue gv: values) {
if (addToCache(gv)) {
count++;
}
}
return count;
}
public int removeAll(List<GenericPK> dummyPKs) throws GenericEntityException {
int count = 0;
for (GenericPK pk: dummyPKs) {
count = count + removeFromCache(pk);
}
return count;
}
public void checkDataSource(Map<String, ModelEntity> modelEntities, List<String> messages, boolean addMissing) throws GenericEntityException {
messages.add("checkDataSource not implemented for MemoryHelper");
}
}