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

com.parship.roperty.persistence.jpa.JpaPersistence Maven / Gradle / Ivy

package com.parship.roperty.persistence.jpa;

import com.parship.roperty.DomainSpecificValue;
import com.parship.roperty.DomainSpecificValueFactory;
import com.parship.roperty.KeyValues;
import com.parship.roperty.KeyValuesFactory;
import com.parship.roperty.Persistence;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

public class JpaPersistence implements Persistence {

    private RopertyKeyDAO ropertyKeyDAO;

    private RopertyValueDAO ropertyValueDAO;

    private TransactionManager transactionManager;

    @Override
    public KeyValues load(String key, KeyValuesFactory keyValuesFactory, DomainSpecificValueFactory domainSpecificValueFactory) {
        Validate.notBlank(key, "Key must not be empty");
        Validate.notNull(keyValuesFactory, "Key values factory must no be null");
        Validate.notNull(domainSpecificValueFactory, "Domain specific value factory must not be null");

        RopertyKey ropertyKey = ropertyKeyDAO.loadRopertyKey(key);
        if (ropertyKey == null) {
            return null;
        }

        return load(ropertyKey, keyValuesFactory, domainSpecificValueFactory);
    }

    private KeyValues load(RopertyKey ropertyKey, KeyValuesFactory keyValuesFactory, DomainSpecificValueFactory domainSpecificValueFactory) {
        Validate.notNull(ropertyKey, "Roperty key must not be null");
        Validate.notNull(keyValuesFactory, "Key values factory must no be null");
        Validate.notNull(domainSpecificValueFactory, "Domain specific value factory must not be null");

        List ropertyValues = ropertyValueDAO.loadRopertyValues(ropertyKey);
        Validate.notEmpty(ropertyValues, "Could not find any values for key '%s'", ropertyKey.getId());

        return new RopertyValueTransformer()
                .withDomainSpecificValueFactory(domainSpecificValueFactory)
                .withKeyValuesFactory(keyValuesFactory)
                .transformValues(ropertyValues);
    }

    @Override
    public Map loadAll(KeyValuesFactory keyValuesFactory, DomainSpecificValueFactory domainSpecificValueFactory) {
        Validate.notNull(keyValuesFactory, "Key values factory must no be null");
        Validate.notNull(domainSpecificValueFactory, "Domain specific value factory must not be null");

        List ropertyKeys = ropertyKeyDAO.loadAllRopertyKeys();
        Map keyValuesMap = new HashMap<>(ropertyKeys.size());
        for (RopertyKey ropertyKey : ropertyKeys) {
            String key = ropertyKey.getId();
            KeyValues keyValues = load(ropertyKey, keyValuesFactory, domainSpecificValueFactory);
            Validate.notNull(keyValues, "No values found for key '%s'", key);
            keyValuesMap.put(key, keyValues);
        }

        return keyValuesMap;
    }

    @Override
    public Map reload(Map keyValuesMap, KeyValuesFactory keyValuesFactory, DomainSpecificValueFactory domainSpecificValueFactory) {
        Validate.notNull(keyValuesFactory, "Key values factory must no be null");
        Validate.notNull(domainSpecificValueFactory, "Domain specific value factory must not be null");

        Map result = new HashMap<>(keyValuesMap.size());

        for (String key : keyValuesMap.keySet()) {
            KeyValues keyValues = load(key, keyValuesFactory, domainSpecificValueFactory);
            if (keyValues != null) {
                result.put(key, keyValues);
            }
        }

        return result;
    }

    @Override
    public void store(String key, KeyValues keyValues, String changeSet) {
        Validate.notBlank(key, "Key must not be empty");
        Validate.notNull(keyValues, "Key values must not be null");
        Validate.notNull(transactionManager, "Transaction manager must no be null");

        transactionManager.begin();

        RopertyKey ropertyKey = ropertyKeyDAO.loadRopertyKey(key);
        String description = keyValues.getDescription();
        if (ropertyKey == null) {
            ropertyKey = new RopertyKey();
            ropertyKey.setId(key);
            ropertyKey.setDescription(description);
            transactionManager.persist(ropertyKey);
        }

        Set domainSpecificValues = keyValues.getDomainSpecificValues();
        if (domainSpecificValues == null) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Domain specific values were null for key values with description '%s'", description));
        }
        if (domainSpecificValues.isEmpty()) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Domain specific values were empty for key values with description '%s'", description));
        }

        storeDomainSpecificValues(ropertyKey, domainSpecificValues, changeSet);

        transactionManager.end();
    }

    private void storeDomainSpecificValues(RopertyKey key, Iterable domainSpecificValues, String changeSet) {
        String transformedChangeSet = emptyWhenNull(changeSet);
        for (DomainSpecificValue domainSpecificValue : domainSpecificValues) {
            Object rawValue = domainSpecificValue.getValue();
            String patternStr = domainSpecificValue.getPatternStr();
            if (patternStr == null) {
                transactionManager.end();
                throw new RopertyPersistenceException(String.format("Pattern for key '%s' must not be null", key.getId()));
            }
            if (domainSpecificValue.changeSetIs(nullWhenEmpty(changeSet))) {
                storeRopertyValue(key, patternStr, rawValue, transformedChangeSet);
            }
        }
    }

    private void storeRopertyValue(RopertyKey ropertyKey, String pattern, Object value, String changeSet) {
        RopertyValue ropertyValue = ropertyValueDAO.loadRopertyValue(ropertyKey, pattern, changeSet);
        if (ropertyValue == null) {
            RopertyValue newRopertyValue = createRopertyValue(ropertyKey, changeSet, value, pattern);
            transactionManager.persist(newRopertyValue);
        } else {
            boolean merge = mergeRopertyValue(ropertyValue, changeSet, value);
            if (merge) {
                transactionManager.merge(ropertyValue);
            }
        }
    }

    private static boolean mergeRopertyValue(RopertyValue original, String newChangeSet, Object newValue) {
        boolean merge = false;
        if (!Objects.equals(original.getChangeSet(), newChangeSet)) {
            original.setChangeSet(newChangeSet);
            merge = true;
        }
        if (!Objects.equals(original.getValue(), newValue)) {
            if (newValue == null) {
                original.setValue(null);
                merge = true;
            } else if (Serializable.class.isAssignableFrom(newValue.getClass())) {
                Serializable value = (Serializable) newValue;
                original.setValue(value);
                merge = true;
            } else {
                throw new RopertyPersistenceException(String.format("Cannot serialize value '%s'", newValue));
            }
        }
        return merge;
    }

    private static RopertyValue createRopertyValue(RopertyKey key, String changeSet, Object value, String pattern) {
        RopertyValue newRopertyValue = new RopertyValue();
        newRopertyValue.setKey(key);
        if (value != null && Serializable.class.isAssignableFrom(value.getClass())) {
            Serializable serializableValue = (Serializable) value;
            newRopertyValue.setValue(serializableValue);
        } else {
            throw new RopertyPersistenceException(String.format("Cannot serialize value '%s'", value));
        }
        newRopertyValue.setPattern(pattern);
        newRopertyValue.setChangeSet(changeSet);
        return newRopertyValue;
    }

    private static String nullWhenEmpty(String string) {
        if (StringUtils.isEmpty(string)) {
            return null;
        }

        return string;
    }

    private static String emptyWhenNull(String changeSet) {
        if (changeSet == null) {
            return "";
        }

        return changeSet;
    }

    @Override
    public void remove(String key, KeyValues keyValues, String changeSet) {
        Validate.notBlank(key, "Key must not be empty");

        transactionManager.begin();

        RopertyKey ropertyKey = ropertyKeyDAO.loadRopertyKey(key);
        if (ropertyKey == null) {
            transactionManager.end();
            return;
        }

        List ropertyValues = new LinkedList<>(ropertyValueDAO.loadRopertyValues(ropertyKey));
        if (ropertyValues.isEmpty()) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Could not find any values for key '%s'. This is an inconsistency that should not happen.", ropertyKey.getId()));
        }

        if (keyValues == null) {
            for (RopertyValue value : ropertyValues) {
                transactionManager.remove(value);
            }
            transactionManager.remove(ropertyKey);
        } else {
            removeKeyValues(ropertyKey, keyValues, ropertyValues);
        }

        transactionManager.end();
    }

    private void removeKeyValues(RopertyKey ropertyKey, KeyValues keyValues, List ropertyValues) {
        Set domainSpecificValues = keyValues.getDomainSpecificValues();
        int numDomainSpecificValues = domainSpecificValues.size();
        if (numDomainSpecificValues == 0) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Key values for key '%s' must contain domain specific values", ropertyKey.getId()));
        }

        int numRemovedValues = 0;

        for (DomainSpecificValue domainSpecificValue : domainSpecificValues) {
            for (Iterator itRopertyValue = ropertyValues.iterator(); itRopertyValue.hasNext(); ) {
                RopertyValue ropertyValue = itRopertyValue.next();
                if (ropertyValue.equals(domainSpecificValue)) {
                    transactionManager.remove(ropertyValue);
                    itRopertyValue.remove();
                    numRemovedValues++;
                }
            }
        }

        if (numDomainSpecificValues == numRemovedValues) {
            transactionManager.remove(ropertyKey);
        }
    }

    @Override
    public void remove(String key, DomainSpecificValue domainSpecificValue, String changeSet) {
        Validate.notBlank(key, "Key must not be empty");
        Validate.notNull(domainSpecificValue, "Domain specific value must not be null");

        transactionManager.begin();

        RopertyKey ropertyKey = ropertyKeyDAO.loadRopertyKey(key);
        if (ropertyKey == null) {
            transactionManager.end();
            return;
        }

        long numValues = ropertyValueDAO.getNumberOfValues(ropertyKey);

        String patternStr = domainSpecificValue.getPatternStr();

        Object value = domainSpecificValue.getValue();
        if (value == null) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Value for key '%s' must not be null", key));
        }
        if (!Serializable.class.isAssignableFrom(value.getClass())) {
            transactionManager.end();
            throw new RopertyPersistenceException(String.format("Domain specific value '%s' for key '%s' must be serializable", value, key));
        }

        RopertyValue ropertyValue = ropertyValueDAO.loadRopertyValue(ropertyKey, patternStr, emptyWhenNull(changeSet));
        if (ropertyValue == null) {
            transactionManager.end();
            return;
        }

        transactionManager.remove(ropertyValue);

        if (numValues == 1) {
            transactionManager.remove(ropertyKey);
        }

        transactionManager.end();
    }

    @Override
    public List findKeys(String substring) {
        return ropertyKeyDAO.findKeys(substring);
    }

    @Override
    public List getAllKeys() {
        List ropertyKeys = ropertyKeyDAO.loadAllRopertyKeys();
        List keys = new ArrayList<>(ropertyKeys.size());
        ropertyKeys.forEach(ropertyKey -> keys.add(ropertyKey.getId()));
        return keys;
    }

    public void setTransactionManager(TransactionManager transactionManager) {
        Validate.notNull(transactionManager, "Transaction manager must not be null");
        this.transactionManager = transactionManager;
    }

    public void setRopertyKeyDAO(RopertyKeyDAO ropertyKeyDAO) {
        Validate.notNull(ropertyKeyDAO, "Roperty key DAO must not be null");
        this.ropertyKeyDAO = ropertyKeyDAO;
    }

    public void setRopertyValueDAO(RopertyValueDAO ropertyValueDAO) {
        Validate.notNull(ropertyValueDAO, "Roperty value DAO must no be null");
        this.ropertyValueDAO = ropertyValueDAO;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy