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

org.ogema.channels.Driver 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.channels;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.ogema.core.application.AppID;
import org.ogema.core.channelmanager.ChannelAccessException;
import org.ogema.core.channelmanager.ChannelConfiguration;
import org.ogema.core.channelmanager.driverspi.ChannelDriver;
import org.ogema.core.channelmanager.driverspi.ChannelLocator;
import org.ogema.core.channelmanager.driverspi.ChannelScanListener;
import org.ogema.core.channelmanager.driverspi.DeviceListener;
import org.ogema.core.channelmanager.driverspi.DeviceLocator;
import org.ogema.core.channelmanager.driverspi.DeviceScanListener;
import org.ogema.core.channelmanager.driverspi.NoSuchChannelException;
import org.ogema.core.channelmanager.driverspi.NoSuchDeviceException;
import org.ogema.core.channelmanager.driverspi.NoSuchInterfaceException;
import org.ogema.core.channelmanager.driverspi.SampledValueContainer;
import org.ogema.core.channelmanager.driverspi.ValueContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Driver is responsible to hold the ChannelDriver reference, 
 * manages the list of registered listen channels, the list of running device scans 
 * and the list of active channels for the driver.
 * 
 * It implements ChannelUpdateListener as only one listener can be registered per driver.
 * 
 * @author pau
 *
 */
class Driver {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	/** true, when the driver has been closed. Used to prohibit new actions after close() */
	private volatile boolean closed;
	
	/** the driver reference */
	private ChannelDriver driver;

	/** reference to the channel manager. used to get reader threads */
	private ReaderThreadFactory readerThreadFactory;

	private DeviceScanList deviceScanList = new DeviceScanList(this);

	/** map of all active channels on this driver */
	private final ConcurrentMap channels = new ConcurrentHashMap();
	
	private final ChannelUpdateListenerList channelUpdateListenerList = new ChannelUpdateListenerList(this, logger);
	
	private final DeviceListenerList deviceListenerList = new DeviceListenerList(this, logger);
	
	Driver(ReaderThreadFactory readerThreadFactory, ChannelDriver driver) {
		this.driver = driver;
		this.readerThreadFactory = readerThreadFactory;
	}
	
	String getId() {
		return driver.getDriverId();
	}
	
	String getDescription() {
		return driver.getDescription();
	}
	
	ChannelDriver getDriver() {
		return driver;
	}
	

	void addListenChannel(Channel channel) throws ChannelAccessException {
		channelUpdateListenerList.addListenChannel(channel);
	}

	void removeListenChannel(Channel channel) {
		channelUpdateListenerList.removeListenChannel(channel);
	}
	
	void readChannels(List channels) throws UnsupportedOperationException, IOException {
		driver.readChannels(channels);
	}
	
	void writeChannels(List channels)
			throws UnsupportedOperationException, IOException, NoSuchDeviceException, NoSuchChannelException {
		driver.writeChannels(channels);
	}

	void channelAdded(ChannelLocator channelLocator) {
		driver.channelAdded(channelLocator);
	}

	void channelRemoved(ChannelLocator channelLocator) {
		// FIXME ths leads to NPEs sometimes; in any case, uncontrolled code is called -> catch Exceptions or use separate thread
		driver.channelRemoved(channelLocator);
	}
	
	ChannelConfiguration addConfiguration(ChannelConfigurationImpl configuration) throws ChannelAccessException {

		Channel newChannel;
		Channel channel;
		ChannelConfiguration result = null;
		boolean tryAgain = false;

		do {
			// make channel adding and the closed check uninterruptible
			synchronized (this) {
				if (closed)
					throw new ChannelAccessException("driver has been closed.");

				// assume the channel does not exist
				newChannel = new Channel(this, configuration.getChannelLocator());
				channel = channels.putIfAbsent(newChannel.getChannelLocator(), newChannel);
				
				if (channel == null) {
					channel = newChannel;
				}
			}

			// if the channel is ever closed between putIfAbsent() and addConfiguration() just try again
			try {
				result = channel.addConfiguration(configuration);
			} catch (IllegalStateException e) {
				tryAgain = true;
			}

		} while (tryAgain);
		
		return result;
	}
	
	boolean removeConfiguration(ChannelConfiguration configuration) throws NoSuchChannelException {

		Channel channel;

		synchronized (this) {
			if (closed)
				return false;
	
			channel = channels.get(configuration.getChannelLocator());
		}
		
		if (channel == null)
			throw new NoSuchChannelException(configuration.getChannelLocator());

		return channel.removeConfiguration(configuration);
	}
	
	void channelClosed(Channel channel) {
		if (channels.remove(channel.getChannelLocator()) != null)
			channelRemoved(channel.getChannelLocator());
	}
	
	Configuration getConfiguration(ChannelConfiguration configuration) throws NoSuchChannelException {
		
		// find Channel
		Channel channel = channels.get(configuration.getChannelLocator());
		
		if (channel == null)
			throw new NoSuchChannelException(configuration.getChannelLocator());
		
		// ask Channel
		Configuration result = channel.getConfiguration(configuration);
		
		if (result == null)
			throw new NoSuchChannelException(configuration.getChannelLocator());
		
		return result;
	}

	void getChannels(List channels) {
		channels.addAll(this.channels.keySet());
	}

	ReaderThread getReaderThread(Channel channel) throws ChannelAccessException {
		return readerThreadFactory.getReaderThread(channel);
	}

	synchronized void close() {
		
		closed = true;
		
		deviceScanList.close();
		
		deviceListenerList.close();

		// close and remove all channels
		for (Channel channel : channels.values()) {
			channel.close();
		}
		
		channels.clear();
		
		channelUpdateListenerList.close();
	
		driver = null;
		readerThreadFactory = null;
	}

	List getChannelList(DeviceLocator deviceLocator) {
		return driver.getChannelList(deviceLocator);
	}

	void startChannelScan(DeviceLocator device, ChannelScanListener listener) {
		driver.startChannelScan(device, listener);
	}
	
	void removeAppID(AppID appID) {
		
		// remove device scanners
		deviceScanList.abortDeviceScanForAppID(appID);
		
		// remove device listeners
		deviceListenerList.removeDeviceListenersForApp(appID);

		// remove channels
		synchronized (this) {
			for (Channel channel : channels.values()) {
				channel.removeAppID(appID);
			}
		}
	}

	void removeDeviceListener(AppID appId, DeviceListener listener) {
		deviceListenerList.removeDeviceListener(appId, listener);
	}

	void addDeviceListener(AppID appId, DeviceListener listener) throws ChannelAccessException {
		deviceListenerList.addDeviceListener(appId, listener);
	}

	DeviceScanner startDeviceScan(String interfaceId, String filter, DeviceScanListener listener,
			AppID appID) throws UnsupportedOperationException, IOException, NoSuchInterfaceException {
		return deviceScanList.startDeviceScan(interfaceId, filter, listener, appID);
	}

	boolean abortDeviceScan(String interfaceId, String filter, AppID appID) {
		return deviceScanList.abortDeviceScan(interfaceId, filter, appID);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy