blob: 82d429c397a258a86121acf49a206552c0f2ff1a [file] [log] [blame]
/*
* Copyright (c) 2017 CEA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* CEA - initial API and implementation
*/
package org.eclipse.sensinact.gateway.generic;
import org.eclipse.sensinact.gateway.api.core.Resource;
import org.eclipse.sensinact.gateway.api.core.Resource.UpdatePolicy;
import org.eclipse.sensinact.gateway.common.bundle.Mediator;
import org.eclipse.sensinact.gateway.common.primitive.Modifiable;
import org.eclipse.sensinact.gateway.core.DefaultResourceConfigBuilder;
import org.eclipse.sensinact.gateway.core.ModelConfiguration;
import org.eclipse.sensinact.gateway.core.ResourceConfigBuilder;
import org.eclipse.sensinact.gateway.core.ResourceImpl;
import org.eclipse.sensinact.gateway.core.ServiceImpl;
import org.eclipse.sensinact.gateway.core.ServiceProviderImpl;
import org.eclipse.sensinact.gateway.core.security.AccessNodeImpl;
import org.eclipse.sensinact.gateway.core.security.AccessTreeImpl;
import org.eclipse.sensinact.gateway.generic.packet.Packet;
import org.eclipse.sensinact.gateway.generic.parser.Commands;
import org.eclipse.sensinact.gateway.generic.parser.FixedProviders;
import org.eclipse.sensinact.gateway.generic.parser.XmlResourceConfigHandler;
import org.eclipse.sensinact.gateway.util.ReflectUtils;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Manages IO for a set of {@link ServiceProvider}s
*
* @author <a href="mailto:christophe.munilla@cea.fr">Christophe Munilla</a>
*/
public class ExtModelConfiguration<P extends Packet> extends ModelConfiguration {
/**
* Returns true if the two bytes arrays passed as parameters are equals
* (same content)
*
* @param base the first of the two bytes arrays to compare
* @param compare the second of the two bytes arrays to compare
* @return true if the two bytes arrays passed as parameters are equals;
* false otherwise
*/
public static boolean compareBytesArrays(byte[] base, byte[] compare) {
if (base == null) {
return compare == null;
}
if (compare == null) {
return false;
}
if (base.length != compare.length) {
return false;
}
for (int index = 0; index < base.length; index++) {
if (base[index] != compare[index]) {
return false;
}
}
return true;
}
/**
* Defines whether the {@link Task}s management has to be
* unsynchronous
*/
protected boolean isDesynchronized;
/**
* Defines whether at initialization time the registered
* {@link Task}s have to be stored waiting for their processing
*/
protected boolean lockedAtInitializationTime;
/**
* the handled {@link Packet} type
*/
protected Class<P> packetType;
/**
* The {@link ConnectorCustomizer} to attach to the
* connector to be built
*/
protected ConnectorCustomizer<P> customizer;
/**
* The {@link Connector} type to be built by this ExtModelConfiguration
*/
protected Class<? extends Connector<P>> connectorType;
/**
* the set of {@link Task.CommandType}
*/
protected Commands commands;
/**
* the initial set of service providers map to their profile
*/
protected Map<String, String> fixedProviders;
/**
* Constructor
*
* @param mediator
* the {@link Mediator} allowing the ExtModelConfiguration to be instantiated to interact
* with the OSGi host environment
* @param accessTree
* the {@link AccessTree} defining the secured access rights applying on sensiNact
* resource model instances configured by the ExtModelConfiguration to be instantiated
* @param packetType
* @param configurationFile
* @param defaults
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public ExtModelConfiguration(
Mediator mediator,
AccessTreeImpl<? extends AccessNodeImpl<?>> accessTree,
Class<P> packetType,
String configurationFile,
Map<String, String> defaults)
throws ParserConfigurationException, SAXException, IOException {
this(mediator,
accessTree,
packetType,
new DefaultResourceConfigBuilder(),
configurationFile,
defaults);
}
/**
* Constructor
*
* @param mediator
* the {@link Mediator} allowing the ExtModelConfiguration to be instantiated to interact
* with the OSGi host environment
* @param accessTree
* the {@link AccessTree} defining the secured access rights applying on sensiNact
* resource model instances configured by the ExtModelConfiguration to be instantiated
* @param packetType
* @param defaultResourceConfigBuilder
* @param configurationFile
* @param defaults
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public ExtModelConfiguration(
Mediator mediator,
AccessTreeImpl<? extends AccessNodeImpl<?>> accessTree,
Class<P> packetType,
ResourceConfigBuilder defaultResourceConfigBuilder,
String configurationFile,
Map<String, String> defaults)
throws ParserConfigurationException, SAXException, IOException {
this(
mediator,
accessTree,
packetType,
defaultResourceConfigBuilder,
configurationFile,
defaults,
ExtServiceProviderImpl.class,
ExtServiceImpl.class,
ExtResourceImpl.class);
}
/**
* Constructor
*
* @param mediator the {@link Mediator} allowing the ExtModelConfiguration
* to be instantiated to interact with the OSGi host environment
* @param accessTree the {@link AccessTree} defining the secured access
* rights applying on sensiNact resource model instances configured
* by the ExtModelConfiguration to be instantiated
* @param packetType
* @param defaultResourceConfigBuilder
* @param configurationFile
* @param defaults
* @param defaultServiceProviderType
* @param defaultServiceType
* @param defaultResourceType
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
protected ExtModelConfiguration(
Mediator mediator,
AccessTreeImpl<?> accessTree,
Class<P> packetType,
ResourceConfigBuilder defaultResourceConfigBuilder,
String configurationFile,
Map<String, String> defaults,
Class<? extends ExtServiceProviderImpl> defaultServiceProviderType,
Class<? extends ExtServiceImpl> defaultServiceType,
Class<? extends ExtResourceImpl> defaultResourceType)
throws ParserConfigurationException, SAXException, IOException {
this(mediator,
accessTree,
packetType,
defaultResourceConfigBuilder,
configurationFile != null?mediator.getContext().getBundle().getResource(configurationFile):null,
defaults,
defaultServiceProviderType,
defaultServiceType,
defaultResourceType);
}
/**
* Constructor
*
* @param mediator the {@link Mediator} allowing the ExtModelConfiguration
* to be instantiated to interact with the OSGi host environment
* @param accessTree the {@link AccessTree} defining the secured access
* rights applying on sensiNact resource model instances configured
* by the ExtModelConfiguration to be instantiated
* @param packetType
* @param defaultResourceConfigBuilder
* @param configurationFile
* @param defaults
* @param defaultServiceProviderType
* @param defaultServiceType
* @param defaultResourceType
*
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public ExtModelConfiguration(
Mediator mediator,
AccessTreeImpl<?> accessTree,
Class<P> packetType,
ResourceConfigBuilder defaultResourceConfigBuilder,
URL configurationFile,
Map<String, String> defaults,
Class<? extends ExtServiceProviderImpl> defaultServiceProviderType,
Class<? extends ExtServiceImpl> defaultServiceType,
Class<? extends ExtResourceImpl> defaultResourceType)
throws ParserConfigurationException, SAXException, IOException {
super(
mediator,
accessTree,
defaultResourceConfigBuilder,
defaultServiceProviderType,
defaultServiceType,
defaultResourceType);
this.packetType = packetType;
super.setResourceConfigType(ExtResourceConfig.class);
XmlResourceConfigHandler handler = ExtResourceConfig.loadFromXml(mediator, configurationFile);
Map<String, String> builtFixedProviders = new HashMap<String, String>();
Map<String, List<String>> builtFixed = new HashMap<String, List<String>>();
Map<String, List<String>> builtProfiles = new HashMap<String, List<String>>();
if (handler != null) {
this.commands = handler.getCommandDefinitions();
FixedProviders fixedProviders = handler.getDeviceDefinitions();
builtFixedProviders.putAll(fixedProviders.getProviderMap());
builtFixed.putAll(fixedProviders.getFixedMap());
builtProfiles.putAll(handler.getProfiles());
super.addResourceConfigCatalog(new ExtResourceConfigCatalog(handler, defaults));
} else {
this.commands = new Commands(null);
}
//load all xml catalogs from org.eclipse.sensinact.gateway.catalog
//can we imagine to replace the initial mechanism of the declared xml resources description file ?
Enumeration<URL> catalogs = mediator.getContext().getBundle().findEntries(
"/org/eclipse/sensinact/gateway/catalog/", "*.xml", false);
if(catalogs!= null) {
while(catalogs.hasMoreElements()){
URL catalog = catalogs.nextElement();
if(catalog==null||!catalog.toExternalForm().endsWith(".xml")) {
continue;
}
try {
handler = ExtResourceConfig.loadFromXml(mediator, catalog);
if(handler == null) {
continue;
}
FixedProviders fixedProviders = handler.getDeviceDefinitions();
builtFixedProviders.putAll(fixedProviders.getProviderMap());
builtFixed.putAll(fixedProviders.getFixedMap());
Iterator<Entry<String, List<String>>> iterator =
handler.getProfiles().entrySet().iterator();
while(iterator.hasNext()) {
Entry<String, List<String>> entry = iterator.next();
if(builtProfiles.containsKey(entry.getKey())) {
builtProfiles.get(entry.getKey()).addAll(entry.getValue());
} else{
builtProfiles.put(entry.getKey(), entry.getValue());
}
}
super.addResourceConfigCatalog(new ExtResourceConfigCatalog(handler, defaults));
}catch( ParserConfigurationException | SAXException | IOException e){
mediator.debug("%s does not contains a valid catalog", catalog.toExternalForm());
continue;
}
}
}
super.fixed = Collections.unmodifiableMap(builtFixed);
super.profiles = Collections.unmodifiableMap(builtProfiles);
this.fixedProviders = Collections.unmodifiableMap(builtFixedProviders);
this.mediator.info("ExtModelConfiguration initialized...");
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setDefaultResourceType(java.lang.Class)
*/
@Override
public ExtModelConfiguration<P> setDefaultResourceType(Class<? extends Resource> defaultResourceType) {
super.setDefaultResourceType(defaultResourceType);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setDefaultDataType(java.lang.Class)
*/
@Override
public ExtModelConfiguration<P> setDefaultDataType(Class<?> defaultDataType) {
super.setDefaultDataType(defaultDataType);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setDefaultModifiable(org.eclipse.sensinact.gateway.common.primitive.Modifiable)
*/
@Override
public ExtModelConfiguration<P> setDefaultModifiable(Modifiable defaultModifiable) {
super.setDefaultModifiable(defaultModifiable);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setDefaultUpdatePolicy(org.eclipse.sensinact.gateway.api.core.Resource.UpdatePolicy)
*/
@Override
public ExtModelConfiguration<P> setDefaultUpdatePolicy(UpdatePolicy defaultUpdatePolicy) {
super.setDefaultUpdatePolicy(defaultUpdatePolicy);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setProviderImplementationType(java.lang.Class)
*/
@Override
public ExtModelConfiguration<P> setProviderImplementationType(Class<? extends ServiceProviderImpl> serviceProviderType) {
super.setProviderImplementationType(serviceProviderType);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setServiceImplmentationType(java.lang.Class)
*/
@Override
public ExtModelConfiguration<P> setServiceImplmentationType(Class<? extends ServiceImpl> serviceType) {
super.setServiceImplmentationType(serviceType);
return this;
}
/**
* @inheritDoc
* @see org.eclipse.sensinact.gateway.core.ModelConfiguration#
* setResourceImplementationType(java.lang.Class)
*/
@Override
public ExtModelConfiguration<P> setResourceImplementationType(Class<? extends ResourceImpl> resourceType) {
super.setResourceImplementationType(resourceType);
return this;
}
/**
* @param lockedAtInitializationTime
* @return
*/
public ExtModelConfiguration<P> setLockedAtInitializationTime(boolean lockedAtInitializationTime) {
this.lockedAtInitializationTime = lockedAtInitializationTime;
return this;
}
/**
* @return
*/
public boolean isLockedAtInitializationTime() {
return this.lockedAtInitializationTime;
}
/**
* @param isDesynchronized
*/
public ExtModelConfiguration<P> setDesynchronized(boolean isDesynchronized) {
this.isDesynchronized = isDesynchronized;
return this;
}
/**
* @return
*/
public boolean isDesynchronized() {
return this.isDesynchronized;
}
/**
* Defines the instance of {@link ConnectorCustomizer} to attach to
* the {@link Connector}(s) instantiated by this ExtModelConfiguration
*
* @param customizer the {@link ConnectorCustomizer} to attach to
* the {@link Connector}(s) instantiated by this ExtModelConfiguration
*/
public void setConnectorCustomizer(ConnectorCustomizer<P> customizer) {
this.customizer = customizer;
}
/**
* Defines the {@link Connector} type to be instantiated by this ExtModelConfiguration
*
* @param connectorType
* the {@link Connector} type to be instantiated by this ExtModelConfiguration
*/
public ExtModelConfiguration<P> setConnectorType(Class<? extends Connector<P>> connectorType) {
this.connectorType = connectorType;
return this;
}
/**
* Returns the command bytes array mapped to the
* {@link Task.CommandType} passed as parameter
*
* @param commandType the {@link Task.CommandType}
* @return the command bytes array for the
* specified {@link Task.CommandType}
*/
public byte[] getCommandIdentifier(Task.CommandType commandType) {
return this.commands.getCommand(commandType);
}
/**
* the set of bytes array commands mapped to
* existing {@link Task.CommandType}s
*
* @return the set of bytes array commands mapped to
* existing {@link Task.CommandType}s
*/
public Commands getCommands() {
return this.commands;
}
/**
* Returns the a Map in which keys are the name of pre-defined
* service providers and the values are their profile
*
* @return the mapping between pre-defined service providers
* and their profile
*/
public Map<String, String> getFixedProviders() {
return Collections.unmodifiableMap(this.fixedProviders);
}
/**
* @return
*/
public Class<P> getPacketType() {
return this.packetType;
}
/**
* @param endpoint
* @return
* @throws InvalidProtocolStackException
*/
public Connector<P> connect(ProtocolStackEndpoint<P> endpoint)
throws InvalidProtocolStackException {
Connector<P> connector = null;
try {
connector = this.newConnector(endpoint);
} catch (ClassCastException e) {
throw new InvalidProtocolStackException(e);
}
return connector;
}
/**
* Creates and returns a new {@link Connector} instance
* to connect to the {@link ProtocolStackEndpoint} passed
* as parameter
*
* @param endpoint the {@link ProtocolStackEndpoint} to which the {@link
* Connector} to instantiate will be connected to
* @return a new {@link Connector} instance
*/
protected <N extends Connector<P>> N newConnector(ProtocolStackEndpoint<P> endpoint)
throws InvalidProtocolStackException {
N connector = null;
if(this.connectorType != null) {
if (this.customizer != null) {
connector = (N) ReflectUtils.<N>getTheBestInstance(
(Class<N>)this.connectorType, new Object[] {mediator, endpoint, this, this.customizer});
} else {
connector = (N) ReflectUtils.<N>getTheBestInstance(
(Class<N>)this.connectorType, new Object[] {mediator, endpoint, this});
}
} else {
if (this.customizer != null) {
return (N) new Connector<P>(mediator, endpoint, this, (ConnectorCustomizer<P>) this.customizer);
} else {
connector = (N) new Connector<P>(mediator, endpoint, this);
}
}
return connector;
}
}