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

org.ogema.resourcemanager.impl.transaction.TransactionImpl Maven / Gradle / Ivy

/**
 * Copyright 2011-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
 *
 * 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 org.ogema.resourcemanager.impl.transaction;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.ogema.core.application.ApplicationManager;
import org.ogema.core.channelmanager.measurements.BooleanValue;
import org.ogema.core.channelmanager.measurements.FloatValue;
import org.ogema.core.channelmanager.measurements.IntegerValue;
import org.ogema.core.channelmanager.measurements.LongValue;
import org.ogema.core.channelmanager.measurements.StringValue;
import org.ogema.core.channelmanager.measurements.Value;
import org.ogema.core.model.Resource;
import org.ogema.core.model.array.ArrayResource;
import org.ogema.core.model.array.BooleanArrayResource;
import org.ogema.core.model.array.ByteArrayResource;
import org.ogema.core.model.array.FloatArrayResource;
import org.ogema.core.model.array.IntegerArrayResource;
import org.ogema.core.model.array.StringArrayResource;
import org.ogema.core.model.array.TimeArrayResource;
import org.ogema.core.model.schedule.Schedule;
import org.ogema.core.model.simple.BooleanResource;
import org.ogema.core.model.simple.FloatResource;
import org.ogema.core.model.simple.IntegerResource;
import org.ogema.core.model.simple.SingleValueResource;
import org.ogema.core.model.simple.StringResource;
import org.ogema.core.model.simple.TimeResource;
import org.ogema.core.resourcemanager.NoSuchResourceException;
import org.ogema.core.resourcemanager.ResourceAccess;
import org.ogema.core.resourcemanager.VirtualResourceException;
import org.ogema.core.timeseries.ReadOnlyTimeSeries;
import org.ogema.resourcemanager.impl.ResourceDBManager;
import org.ogema.tools.timeseries.api.MemoryTimeSeries;
import org.ogema.tools.timeseries.implementations.ArrayTimeSeries;
import org.slf4j.Logger;

/**
 * Implementation for the Transaction interface. The implementation shall work
 * against the API as much as possible, not needing any methods defined in only
 * the implementation. A necessary exception to this is that the transaction
 * must be able to lock and unlock the resource graph for reading, writing,
 * activating and deactivating.
 *
 * FIXME since this also supports virtual resources, the casting to the target
 * type should also be checked at the time of reading/writing, and a suitable
 * error handling for this is required.
 *
 * @author Timo Fischer, Fraunhofer IWES
 */
@SuppressWarnings("deprecation")
public class TransactionImpl implements org.ogema.core.resourcemanager.Transaction {

    @SuppressWarnings("unused")
    private final Logger m_logger;
    private final ResourceDBManager m_dbMan;
    private final ApplicationManager m_appMan;

    // Maps between resources containing a value and their to-write and last-read values.
    private final Map> m_boolMap = new HashMap<>();
    private final Map> m_floatMap = new HashMap<>();
    private final Map> m_intMap = new HashMap<>();
    private final Map> m_stringMap = new HashMap<>();
    private final Map> m_timeMap = new HashMap<>();
    private final Map> m_byteArrayMap = new HashMap<>();
    private final Map> m_floatArrayMap = new HashMap<>();
    private final Map> m_intArrayMap = new HashMap<>();
    private final Map> m_booleanArrayMap = new HashMap<>();
    private final Map> m_stringArrayMap = new HashMap<>();
    private final Map> m_longArrayMap = new HashMap<>();
    private final Map> m_scheduleMap = new HashMap<>();

    // List of resources that do not contain a value (used in activation/de-activation)
    private final Set m_complexResources = new HashSet<>();

    public TransactionImpl(ResourceDBManager dbMan, ApplicationManager appMan) {
        m_dbMan = dbMan;
        m_appMan = appMan;
        m_logger = org.slf4j.LoggerFactory.getLogger("Transaction-" + appMan.getAppID());

    }

    private Collection getAllPathsWithValues() {
        final Collection result = new ArrayList<>();
        result.addAll(m_boolMap.keySet());
        result.addAll(m_floatMap.keySet());
        result.addAll(m_intMap.keySet());
        result.addAll(m_stringMap.keySet());
        result.addAll(m_timeMap.keySet());
        result.addAll(m_byteArrayMap.keySet());
        result.addAll(m_floatArrayMap.keySet());
        result.addAll(m_intArrayMap.keySet());
        result.addAll(m_booleanArrayMap.keySet());
        result.addAll(m_stringArrayMap.keySet());
        result.addAll(m_longArrayMap.keySet());
        result.addAll(m_scheduleMap.keySet());
        return result;
    }

    private Collection getAllPaths() {
        final Collection result = getAllPathsWithValues();
        result.addAll(m_complexResources);
        return result;
    }

    @Override
    public void addTree(Resource rootResource, boolean addReferencedSubresources) {
        final List resources;
        if (addReferencedSubresources) {
            resources = rootResource.getSubResources(true);
        } else {
            resources = rootResource.getDirectSubResources(true);
        }
        resources.add(rootResource);
        addResources(resources);
    }

    @Override
    public void addResource(Resource resource) {
        final Class resType = resource.getResourceType();
        final String path = resource.getPath();

        if (SingleValueResource.class.isAssignableFrom(resType)) {
            if (BooleanResource.class.isAssignableFrom(resType)) {
                m_boolMap.put(path, new RwPair());
                return;
            }
            if (FloatResource.class.isAssignableFrom(resType)) {
                m_floatMap.put(path, new RwPair());
                return;
            }
            if (IntegerResource.class.isAssignableFrom(resType)) {
                m_intMap.put(path, new RwPair());
                return;
            }
            if (StringResource.class.isAssignableFrom(resType)) {
                m_stringMap.put(path, new RwPair());
                return;
            }
            if (TimeResource.class.isAssignableFrom(resType)) {
                m_timeMap.put(path, new RwPair());
                return;
            }
            throw new UnsupportedOperationException("Cannot handle SingleValueResource of type " + resType.getCanonicalName());
        }

        if (ArrayResource.class.isAssignableFrom(resType)) {
            if (ByteArrayResource.class.isAssignableFrom(resType)) {
                m_byteArrayMap.put(path, new RwPair());
                return;
            }
            if (FloatArrayResource.class.isAssignableFrom(resType)) {
                m_floatArrayMap.put(path, new RwPair());
                return;
            }
            if (IntegerArrayResource.class.isAssignableFrom(resType)) {
                m_intArrayMap.put(path, new RwPair());
                return;
            }
            if (BooleanArrayResource.class.isAssignableFrom(resType)) {
                m_booleanArrayMap.put(path, new RwPair());
                return;
            }
            if (StringArrayResource.class.isAssignableFrom(resType)) {
                m_stringArrayMap.put(path, new RwPair());
                return;
            }
            if (TimeArrayResource.class.isAssignableFrom(resType)) {
                m_longArrayMap.put(path, new RwPair());
                return;
            }

            // legacy support for deprecated types
            if (org.ogema.core.model.simple.OpaqueResource.class.isAssignableFrom(resType)) {
                m_byteArrayMap.put(path, new RwPair());
                return;
            }

            throw new UnsupportedOperationException("Cannot handle ArrayResource of type " + resType.getCanonicalName());
        }

        // schedules
        if (Schedule.class.isAssignableFrom(resType)) {
            m_scheduleMap.put(path, new RwPair());
            return;
        }

        // neither SingleValueResource, nor ArrayResource, not Schedule: Assume complex resource
        m_complexResources.add(path);
    }

    @Override
    public void addResources(Collection resources) {
        for (Resource resource : resources) {
            addResource(resource);
        }
    }

    @Override
    public Collection getResources() {
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        final Collection paths = getAllPaths();
        final List result = new ArrayList<>(paths.size());
        for (String path : paths) {
            result.add(resAcc.getResource(path));
        }
        return result;
    }

    @Override
    @SuppressWarnings("unchecked")
    public  Collection getResources(Class resourceType) {
        final Collection all = getResources();
        final Collection result = new ArrayList<>();
        for (Resource resource : all) {
            if (resourceType.isAssignableFrom(resource.getResourceType())) {
                result.add((T) resource);
            }
        }
        return result;
    }

    /**
     * Remove all entries of resource from the map for which the paths fits.
     */
    private  void removeByPath(Resource resource, Map> map) {
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        final Set paths = map.keySet();
        for (String path : paths) {
            final Resource entry = resAcc.getResource(path);
            if (resource.equalsPath(entry)) {
                map.remove(path);
            }
        }
    }

    /**
     * Remove all entries of resource from the map for which the location fits.
     */
    private  void removeByLocation(Resource resource, Map> map) {
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        final Set paths = map.keySet();
        for (String path : paths) {
            final Resource entry = resAcc.getResource(path);
            if (resource.equalsLocation(entry)) {
                map.remove(path);
            }
        }
    }

    /**
     * Remove the resource from all maps if it has the same path as a map entry.
     */
    private void removeByPath(Resource resource) {
        removeByPath(resource, m_boolMap);
        removeByPath(resource, m_floatMap);
        removeByPath(resource, m_intMap);
        removeByPath(resource, m_byteArrayMap);
        removeByPath(resource, m_stringMap);
        removeByPath(resource, m_timeMap);
        removeByPath(resource, m_booleanArrayMap);
        removeByPath(resource, m_floatArrayMap);
        removeByPath(resource, m_intArrayMap);
        removeByPath(resource, m_stringArrayMap);
        removeByPath(resource, m_longArrayMap);
        removeByPath(resource, m_scheduleMap);
        m_complexResources.remove(resource.getPath());
    }

    /**
     * Remove the resource from all maps if it has the same path as a map entry.
     */
    private void removeByLocation(Resource resource) {
        removeByLocation(resource, m_boolMap);
        removeByLocation(resource, m_floatMap);
        removeByLocation(resource, m_intMap);
        removeByLocation(resource, m_byteArrayMap);
        removeByLocation(resource, m_stringMap);
        removeByLocation(resource, m_timeMap);
        removeByLocation(resource, m_booleanArrayMap);
        removeByLocation(resource, m_floatArrayMap);
        removeByLocation(resource, m_intArrayMap);
        removeByLocation(resource, m_stringArrayMap);
        removeByLocation(resource, m_longArrayMap);
        removeByLocation(resource, m_scheduleMap);

        // treatment for complex resources
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        final Iterator iter = m_complexResources.iterator();
        while (iter.hasNext()) {
            final String path = iter.next();
            final Resource existingResource = resAcc.getResource(path);
            if (existingResource.equalsLocation(resource)) {
                iter.remove();
            }
        }
    }

    @Override
    public void removeResources(Collection resources) {
        for (Resource resource : resources) {
            removeByPath(resource);
        }
    }

    @Override
    public void removeResourcesByLocation(Collection resources) {
        for (Resource resource : resources) {
            removeByLocation(resource);
        }
    }

    // ---- Getters ----
    /**
     * Tries to find the entry for the resource in the map and returns its
     * associated read value, if possible. Throws a NoSuchResourcException, if
     * the resource could not be found in the application. This is the generic
     * version of the typed get methods.
     */
    private static  T getReadEntry(Resource resource, Map> map) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!map.containsKey(path)) {
            throw new NoSuchResourceException("Can not get a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it.");
        }
        final RwPair pair = map.get(path);
        return pair.read;
    }

    @Override
    public Float getFloat(FloatResource resource) throws NoSuchResourceException {
        return getReadEntry(resource, m_floatMap);
    }

    @Override
    public Integer getInteger(IntegerResource resource) throws NoSuchResourceException {
        return getReadEntry(resource, m_intMap);
    }

    @Override
    public Boolean getBoolean(BooleanResource resource) throws NoSuchResourceException {
        return getReadEntry(resource, m_boolMap);
    }

    @Override
    public String getString(StringResource resource) throws NoSuchResourceException {
        return getReadEntry(resource, m_stringMap);
    }

    @Override
    public Long getTime(TimeResource resource) throws NoSuchResourceException {
        return getReadEntry(resource, m_timeMap);
    }

    @Override
    @Deprecated
    public byte[] getByteArray(org.ogema.core.model.simple.OpaqueResource resource) throws NoSuchResourceException {
        final byte[] values = getReadEntry(resource, m_byteArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public byte[] getByteArray(ByteArrayResource resource) throws NoSuchResourceException {
        final byte[] values = getReadEntry(resource, m_byteArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public float[] getFloatArray(FloatArrayResource resource) throws NoSuchResourceException {
        final float[] values = getReadEntry(resource, m_floatArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public int[] getIntegerArray(IntegerArrayResource resource) throws NoSuchResourceException {
        final int[] values = getReadEntry(resource, m_intArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public boolean[] getBooleanArray(BooleanArrayResource resource) throws NoSuchResourceException {
        final boolean[] values = getReadEntry(resource, m_booleanArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public long[] getTimeArray(TimeArrayResource resource) throws NoSuchResourceException {
        final long[] values = getReadEntry(resource, m_longArrayMap);
        return (values != null) ? values.clone() : null;
    }

    @Override
    public String[] getStringArray(StringArrayResource resource) throws NoSuchResourceException {
        final String[] values = getReadEntry(resource, m_stringArrayMap);
        return (values != null) ? values.clone() : null;
    }

    // ---- Setters ----
    @Override
    public void setFloat(FloatResource resource, float value) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_floatMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_floatMap.get(path);
        pair.write = value;
    }

    @Override
    public void setInteger(IntegerResource resource, int value) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_intMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_intMap.get(path);
        pair.write = value;
    }

    @Override
    public void setBoolean(BooleanResource resource, boolean value) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_boolMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_boolMap.get(path);
        pair.write = value;
    }

    @Override
    public void setString(StringResource resource, String value) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_stringMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_stringMap.get(path);
        pair.write = value;
    }

    @Override
    public void setTime(TimeResource resource, long value) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_timeMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_timeMap.get(path);
        pair.write = value;
    }

    @Override
    @Deprecated
    public void setByteArray(org.ogema.core.model.simple.OpaqueResource resource, byte[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_byteArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_byteArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setByteArray(ByteArrayResource resource, byte[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_byteArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_byteArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setFloatArray(FloatArrayResource resource, float[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_floatArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_floatArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setIntegerArray(IntegerArrayResource resource, int[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_intArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_intArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setBooleanArray(BooleanArrayResource resource, boolean[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_booleanArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_booleanArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setStringArray(StringArrayResource resource, String[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_stringArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_stringArrayMap.get(path);
        pair.write = values;
    }

    @Override
    public void setTimeArray(TimeArrayResource resource, long[] values) throws NoSuchResourceException {
        final String path = resource.getPath();
        if (!m_longArrayMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for resource " + resource.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_longArrayMap.get(path);
        pair.write = values;
    }

    // ---- Read and Write ----
    @Override
    public void read() {
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        // start transaction: lock resource graph.
        m_dbMan.lockStructureRead();
        m_dbMan.lockRead();
        try {
            for (String path : m_boolMap.keySet()) {
                final BooleanResource resource = (BooleanResource) resAcc.getResource(path);
                final Boolean value = (resource.exists()) ? resource.getValue() : null;
                final RwPair pair = m_boolMap.get(path);
                pair.read = value;
            }
            for (String path : m_floatMap.keySet()) {
                final FloatResource resource = (FloatResource) resAcc.getResource(path);
                final Float value = (resource.exists()) ? resource.getValue() : null;
                final RwPair pair = m_floatMap.get(path);
                pair.read = value;
            }
            for (String path : m_intMap.keySet()) {
                final IntegerResource resource = (IntegerResource) resAcc.getResource(path);
                final Integer value = (resource.exists()) ? resource.getValue() : null;
                final RwPair pair = m_intMap.get(path);
                pair.read = value;
            }
            for (String path : m_byteArrayMap.keySet()) {
                final Resource untypedResource = resAcc.getResource(path);
                if (untypedResource instanceof ByteArrayResource) {
                    final ByteArrayResource resource = (ByteArrayResource) untypedResource;
                    final byte[] value = (resource.exists()) ? resource.getValues() : null;
                    final RwPair pair = m_byteArrayMap.get(path);
                    pair.read = value;
                } else if (untypedResource instanceof org.ogema.core.model.simple.OpaqueResource) { // case for deprecated OpaqueResources
                    final org.ogema.core.model.simple.OpaqueResource resource = (org.ogema.core.model.simple.OpaqueResource) untypedResource;
                    final byte[] value = (resource.exists()) ? resource.getValue() : null;
                    final RwPair pair = m_byteArrayMap.get(path);
                    pair.read = value;
                }
            }
            for (String path : m_stringMap.keySet()) {
                final StringResource resource = (StringResource) resAcc.getResource(path);
                final String value = (resource.exists()) ? resource.getValue() : null;
                final RwPair pair = m_stringMap.get(path);
                pair.read = value;
            }
            for (String path : m_timeMap.keySet()) {
                final TimeResource resource = (TimeResource) resAcc.getResource(path);
                final Long value = (resource.exists()) ? resource.getValue() : null;
                final RwPair pair = m_timeMap.get(path);
                pair.read = value;
            }

            // arrays
            for (String path : m_floatArrayMap.keySet()) {
                final FloatArrayResource resource = (FloatArrayResource) resAcc.getResource(path);
                final float[] value = (resource.exists()) ? resource.getValues() : null;
                final RwPair pair = m_floatArrayMap.get(path);
                pair.read = value;
            }
            for (String path : m_intArrayMap.keySet()) {
                final IntegerArrayResource resource = (IntegerArrayResource) resAcc.getResource(path);
                final int[] value = (resource.exists()) ? resource.getValues() : null;
                final RwPair pair = m_intArrayMap.get(path);
                pair.read = value;
            }
            for (String path : m_booleanArrayMap.keySet()) {
                final BooleanArrayResource resource = (BooleanArrayResource) resAcc.getResource(path);
                final boolean[] value = (resource.exists()) ? resource.getValues() : null;
                final RwPair pair = m_booleanArrayMap.get(path);
                pair.read = value;
            }
            for (String path : m_stringArrayMap.keySet()) {
                final StringArrayResource resource = (StringArrayResource) resAcc.getResource(path);
                final String[] value = (resource.exists()) ? resource.getValues() : null;
                final RwPair pair = m_stringArrayMap.get(path);
                pair.read = value;
            }
            for (String path : m_longArrayMap.keySet()) {
                final TimeArrayResource resource = (TimeArrayResource) resAcc.getResource(path);
                final long[] value = (resource.exists()) ? resource.getValues() : null;
                final RwPair pair = m_longArrayMap.get(path);
                pair.read = value;
            }

            readSchedules(resAcc);
        } finally {
            // transaction finished: unlock the graph.
            m_dbMan.unlockRead();
            m_dbMan.unlockStructureRead();
        }
    }

    @Override
    public void write() throws VirtualResourceException {
        final ResourceAccess resAcc = m_appMan.getResourceAccess();
        // start transaction: lock resource graph.
        m_dbMan.lockWrite();
        m_dbMan.startTransaction();
        try {
            // check that all resources exist, throw an exception if not.
            for (Resource resource : getResources()) {
                if (!resource.exists()) {
                    throw new VirtualResourceException("Could not perform write transaction: Target resource at " + resource.getPath() + " does not exist.");
                }
            }

            // simple resources
            for (String path : m_boolMap.keySet()) {
                final BooleanResource resource = (BooleanResource) resAcc.getResource(path);
                final RwPair pair = m_boolMap.get(path);
                final Boolean value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValue();
                } else {
                    resource.setValue(value);
                    pair.read = resource.getValue();
                }
            }
            for (String path : m_floatMap.keySet()) {
                final FloatResource resource = (FloatResource) resAcc.getResource(path);
                final RwPair pair = m_floatMap.get(path);
                final Float value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValue();
                } else {
                    resource.setValue(value);
                    pair.read = resource.getValue();
                }
            }
            for (String path : m_intMap.keySet()) {
                final IntegerResource resource = (IntegerResource) resAcc.getResource(path);
                final RwPair pair = m_intMap.get(path);
                final Integer value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValue();
                } else {
                    resource.setValue(value);
                    pair.read = resource.getValue();
                }
            }
            for (String path : m_byteArrayMap.keySet()) {
                final Resource untypedResource = resAcc.getResource(path);
                if (untypedResource instanceof ByteArrayResource) {
                    final ByteArrayResource resource = (ByteArrayResource) untypedResource;
                    final RwPair pair = m_byteArrayMap.get(path);
                    final byte[] value = pair.write;
                    if (!resource.exists()) {
                        pair.read = null;
                    } else if (value == null) {
                        pair.read = resource.getValues();
                    } else {
                        resource.setValues(value);
                        pair.read = resource.getValues();
                    }
                } else if (untypedResource instanceof org.ogema.core.model.simple.OpaqueResource) {
                    final org.ogema.core.model.simple.OpaqueResource resource = (org.ogema.core.model.simple.OpaqueResource) untypedResource;
                    final RwPair pair = m_byteArrayMap.get(path);
                    final byte[] value = pair.write;
                    if (!resource.exists()) {
                        pair.read = null;
                    } else if (value == null) {
                        pair.read = resource.getValue();
                    } else {
                        resource.setValue(value);
                        pair.read = resource.getValue();
                    }
                }
            }
            for (String path : m_stringMap.keySet()) {
                final StringResource resource = (StringResource) resAcc.getResource(path);
                final RwPair pair = m_stringMap.get(path);
                final String value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValue();
                } else {
                    resource.setValue(value);
                    pair.read = resource.getValue();
                }
            }
            for (String path : m_timeMap.keySet()) {
                final TimeResource resource = (TimeResource) resAcc.getResource(path);
                final RwPair pair = m_timeMap.get(path);
                final Long value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValue();
                } else {
                    resource.setValue(value);
                    pair.read = resource.getValue();
                }
            }

            // arrays
            for (String path : m_booleanArrayMap.keySet()) {
                final BooleanArrayResource resource = (BooleanArrayResource) resAcc.getResource(path);
                final RwPair pair = m_booleanArrayMap.get(path);
                final boolean[] value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValues();
                } else {
                    resource.setValues(value);
                    pair.read = resource.getValues();
                }
            }
            for (String path : m_floatArrayMap.keySet()) {
                final FloatArrayResource resource = (FloatArrayResource) resAcc.getResource(path);
                final RwPair pair = m_floatArrayMap.get(path);
                final float[] value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValues();
                } else {
                    resource.setValues(value);
                    pair.read = resource.getValues();
                }
            }
            for (String path : m_intArrayMap.keySet()) {
                final IntegerArrayResource resource = (IntegerArrayResource) resAcc.getResource(path);
                final RwPair pair = m_intArrayMap.get(path);
                final int[] value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValues();
                } else {
                    resource.setValues(value);
                    pair.read = resource.getValues();
                }
            }
            for (String path : m_stringArrayMap.keySet()) {
                final StringArrayResource resource = (StringArrayResource) resAcc.getResource(path);
                final RwPair pair = m_stringArrayMap.get(path);
                final String[] value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValues();
                } else {
                    resource.setValues(value);
                    pair.read = resource.getValues();
                }
            }
            for (String path : m_longArrayMap.keySet()) {
                final TimeArrayResource resource = (TimeArrayResource) resAcc.getResource(path);
                final RwPair pair = m_longArrayMap.get(path);
                final long[] value = pair.write;
                if (!resource.exists()) {
                    pair.read = null;
                } else if (value == null) {
                    pair.read = resource.getValues();
                } else {
                    resource.setValues(value);
                    pair.read = resource.getValues();
                }
            }
            writeSchedules(resAcc);
        } finally {
        	m_dbMan.finishTransaction();
            // transaction finished: unlock resource graph
            m_dbMan.unlockWrite();
        }
    }

    @Override
    public void activate() {
        final Collection resources = getResources();
        m_dbMan.lockStructureWrite();
        m_dbMan.startTransaction();
        try {
            for (Resource resource : resources) {
                resource.activate(false);
            }
        } finally {
        	m_dbMan.finishTransaction();
            m_dbMan.unlockStructureWrite();
        }
    }

    @Override
    public void deactivate() {
        final Collection resources = getResources();
        m_dbMan.lockStructureWrite();
        m_dbMan.startTransaction();
        try {
            for (Resource resource : resources) {
                resource.deactivate(false);
            }
        } finally {
        	m_dbMan.finishTransaction();
            m_dbMan.unlockStructureWrite();
        }
    }

    /**
     * Gets the value type for a schedule by looking at its parent resource.
     */
    private static Class getValueType(Schedule schedule) {
        final Resource parent = schedule.getParent();
        if (parent == null) {
            throw new RuntimeException("Schedule at path " + schedule.getPath() + " does not seem to have a parent. Cannot determine the type of elements. OGEMA schedules must always have a simple non-array parent resource.");
        }
        final Class resType = parent.getResourceType();
        if (FloatResource.class.isAssignableFrom(resType)) {
            return FloatValue.class;
        } else if (IntegerResource.class.isAssignableFrom(resType)) {
            return IntegerValue.class;
        } else if (BooleanResource.class.isAssignableFrom(resType)) {
            return BooleanValue.class;
        } else if (StringResource.class.isAssignableFrom(resType)) {
            return StringValue.class;
        } else if (TimeResource.class.isAssignableFrom(resType)) {
            return LongValue.class;
        } else {
            throw new RuntimeException("Parent of schedule at path " + schedule.getPath() + " is of type " + resType.getCanonicalName() + ", which is not a valid base type for a schedule resource (alternatively, if you see this message the OGEMA code may be bugged).");
        }
    }

    @Override
    public void setSchedule(Schedule schedule, ReadOnlyTimeSeries function) throws NoSuchResourceException {
        final String path = schedule.getPath();
        if (!m_scheduleMap.containsKey(path)) {
            throw new NoSuchResourceException("Can not set a value for schedule " + schedule.toString() + " in transaction: Resource had not been registered before. Be sure to register the resource to the transaction with addResource(...) before trying to set a value for it");
        }
        final RwPair pair = m_scheduleMap.get(path);
        final Class valueType = getValueType(schedule);
        final MemoryTimeSeries state = new ArrayTimeSeries(function, valueType);
        pair.write = state;
    }

    @Override
    public ReadOnlyTimeSeries getSchedule(Schedule schedule) throws NoSuchResourceException {
        final MemoryTimeSeries data = getReadEntry(schedule, m_scheduleMap);
        return (data != null) ? data.clone() : null;
    }

    private void writeSchedules(ResourceAccess resAcc) {
        for (String path : m_scheduleMap.keySet()) {
            final Schedule schedule = (Schedule) resAcc.getResource(path);
            final RwPair pair = m_scheduleMap.get(path);
            final MemoryTimeSeries value = pair.write;
            if (!schedule.exists()) {
                pair.read = null;
            } else if (value == null) {
                if (pair.read == null) {
                    final Class valueType = getValueType(schedule);
                    pair.read = new ArrayTimeSeries(valueType);
                }
                pair.read.read(schedule);
            } else {
                value.write(schedule);
                if (pair.read == null) {
                    final Class valueType = getValueType(schedule);
                    pair.read = new ArrayTimeSeries(valueType);
                }
                pair.read.read(schedule);
            }
        }
    }

    private void readSchedules(ResourceAccess resAcc) {
        for (String path : m_scheduleMap.keySet()) {
            final Schedule schedule = (Schedule) resAcc.getResource(path);
            final RwPair pair = m_scheduleMap.get(path);
            if (!schedule.exists()) {
                pair.read = null;
                continue;
            }
            if (pair.read == null) {
                final Class valueType = getValueType(schedule);
                pair.read = new ArrayTimeSeries(valueType);
            }
            pair.read.read(schedule);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy