de.tum.in.opcua.client.OpcUaClient.java Source code

Java tutorial

Introduction

Here is the source code for de.tum.in.opcua.client.OpcUaClient.java

Source

/*******************************************************************************
 * Copyright (C) 2015 - Amit Kumar Mondal <admin@amitinside.com>
 *
 * 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 de.tum.in.opcua.client;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.List;
import java.util.Map;

import org.apache.commons.collections.IterableMap;
import org.apache.commons.collections.MapIterator;
import org.apache.commons.collections.map.HashedMap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.Service;
import org.eclipse.kura.KuraException;
import org.eclipse.kura.cloud.CloudService;
import org.eclipse.kura.cloud.Cloudlet;
import org.eclipse.kura.cloud.CloudletTopic;
import org.eclipse.kura.configuration.ComponentConfiguration;
import org.eclipse.kura.configuration.ConfigurableComponent;
import org.eclipse.kura.configuration.ConfigurationService;
import org.eclipse.kura.message.KuraPayload;
import org.eclipse.kura.message.KuraRequestPayload;
import org.eclipse.kura.message.KuraResponsePayload;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.digitalpetri.opcua.stack.core.security.SecurityPolicy;
import com.google.common.collect.Lists;

import de.tum.in.activity.log.ActivityLogService;
import de.tum.in.activity.log.IActivityLogService;

/**
 * This bundle is responsible for communicating with the OPC-UA Server
 *
 * @author AMIT KUMAR MONDAL
 *
 */
@Component(immediate = true, name = "de.tum.in.opcua.client")
@Service(value = { OpcUaClient.class })
public class OpcUaClient extends Cloudlet implements ConfigurableComponent {

    /**
     * Application Identifier
     */
    private static final String APP_ID = "OPCUA-V1";

    /**
     * Configurable property to set client alias for the keystore
     */
    private static final String KEYSTORE_CLIENT_ALIAS = "keystore.client.alias";

    /**
     * Configurable Property to set keystore password
     */
    private static final String KEYSTORE_PASSWORD = "keystore.password";

    /**
     * Configurable Property to set server alias for the keystore
     */
    private static final String KEYSTORE_SERVER_ALIAS = "keystore.server.alias";

    /**
     * Configurable Property to set keystore type
     */
    private static final String KEYSTORE_TYPE = "keystore.type";

    /**
     * Logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(OpcUaClient.class);

    /**
     * Configurable Property to set OPC-UA application certificate
     */
    private static final String OPCUA_APPLICATION_CERTIFICATE = "opcua.certificate.location";

    /**
     * Configurable Property to set OPC-UA application name
     */
    private static final String OPCUA_APPLICATION_NAME = "opcua.application.name";

    /**
     * Configurable Property to set OPC-UA application uri
     */
    private static final String OPCUA_APPLICATION_URI = "opcua.application.uri";

    /**
     * Configurable Property to OPC-UA server password
     */
    private static final String OPCUA_PASSWORD = "opcua.password";

    /**
     * Configurable property specifying the request timeout
     */
    private static final String OPCUA_REQUEST_TIMEOUT = "opcua.request.timeout";

    /**
     * Configurable property specifying the Security Policy
     */
    private static final String OPCUA_SECURITY_POLICY = "opcua.security.policy";

    /**
     * Configurable Property to set OPC-UA server username
     */
    private static final String OPCUA_USERNAME = "opcua.password";

    /**
     * Activity Log Service Dependency
     */
    @Reference(bind = "bindActivityLogService", unbind = "unbindActivityLogService")
    private volatile IActivityLogService m_activityLogService;

    /**
     * Eclipse Kura Cloud Service Dependency
     */
    @Reference(bind = "bindCloudService", unbind = "unbindCloudService")
    private volatile CloudService m_cloudService;

    /**
     * Eclipse Kura Configuration Service Dependency
     */
    @Reference(bind = "bindConfigurationService", unbind = "unbindConfigurationService")
    private volatile ConfigurationService m_configurationService;

    /**
     * Placeholder for keystore client alias
     */
    private String m_keystoreClientAlias;

    /**
     * Placeholder for keystore password
     */
    private String m_keystorePassword;

    /**
     * Placeholder for keystore server alias
     */
    private String m_keystoreServerAlias;

    /**
     * Placeholder for keystore type
     */
    private String m_keystoreType;

    /**
     * Placeholder for OPC-UA certificate location
     */
    private String m_opcuaApplicationCert;

    /**
     * Placeholder for OPC-UA application name
     */
    private String m_opcuaApplicationName;

    /**
     * Placeholder for OPC-UA application uri
     */
    private String m_opcuaApplicationUri;

    /**
     * OPC-UA Client Service Injection
     */
    @Reference(bind = "bindOpcUa", unbind = "unbindOpcUa", policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
    private volatile OpcUaClientAction m_opcuaClientAction;

    /**
     * Holds List of {@link OpcUaClientAction}
     */
    private final List<OpcUaClientAction> m_opcuaClientActions = Lists.newCopyOnWriteArrayList();

    /**
     * Placeholder for OPC-UA password
     */
    private String m_opcuaPassword;

    /**
     * Placeholder for security policy
     */
    private SecurityPolicy m_opcuaSecurityPolicy;

    /**
     * Placeholder for OPC-UA username
     */
    private String m_opcuaUsername;

    /**
     * Map to store list of configurations
     */
    private Map<String, Object> m_properties;

    /**
     * Placeholder for request timeout
     */
    private int m_requestTimeout;

    /**
     * Placeholder for security policy
     */
    private int m_securityPolicy;

    /* Constructor */
    public OpcUaClient() {
        super(APP_ID);
    }

    /**
     * Callback used when this service component is activating
     */
    @Activate
    protected synchronized void activate(final ComponentContext componentContext,
            final Map<String, Object> properties) {
        LOGGER.info("Activating OPC-UA Component...");

        super.setCloudService(this.m_cloudService);
        super.activate(componentContext);
        this.reinitializeConfiguration(properties);

        LOGGER.info("Activating OPC-UA Component... Done.");

    }

    /**
     * Callback to be used while {@link ActivityLogService} is registering
     */
    public synchronized void bindActivityLogService(final IActivityLogService activityLogService) {
        if (this.m_activityLogService == null) {
            this.m_activityLogService = activityLogService;
        }
    }

    /**
     * Callback to be used while {@link CloudService} is registering
     */
    public synchronized void bindCloudService(final CloudService cloudService) {
        if (this.m_cloudService == null) {
            super.setCloudService(this.m_cloudService = cloudService);
        }
    }

    /**
     * Callback to be used while {@link ConfigurationService} is registering
     */
    public synchronized void bindConfigurationService(final ConfigurationService configurationService) {
        if (this.m_configurationService == null) {
            this.m_configurationService = configurationService;
        }
    }

    /**
     * Callback to be used while {@link OpcUaClientAction} is registering
     */
    public synchronized void bindOpcUa(final OpcUaClientAction opcuaClientAction) {
        if (!this.m_opcuaClientActions.contains(opcuaClientAction)) {
            this.m_opcuaClientActions.add(opcuaClientAction);
        }
    }

    /**
     * Retrieves Proper Security Policy required for the client actions
     */
    private void configureSecurityPolicy() {
        switch (this.m_securityPolicy) {
        case 0:
            this.m_opcuaSecurityPolicy = SecurityPolicy.None;
            break;
        case 1:
            this.m_opcuaSecurityPolicy = SecurityPolicy.Basic128Rsa15;
            break;
        case 2:
            this.m_opcuaSecurityPolicy = SecurityPolicy.Basic256;
            break;
        case 3:
            this.m_opcuaSecurityPolicy = SecurityPolicy.Basic256Sha256;
            break;
        }
    }

    /**
     * Callback used when this service component is deactivating
     */
    @Override
    @Deactivate
    protected void deactivate(final ComponentContext context) {
        LOGGER.debug("Deactivating OPC-UA Component...");
        LOGGER.debug("Deactivating OPC-UA Component... Done.");
    }

    /** {@inheritDoc}} */
    @Override
    protected void doExec(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload,
            final KuraResponsePayload respPayload) throws KuraException {
        LOGGER.info("OPC-UA Client Action Started...");
        final String clientName = (String) reqPayload.getMetric("opcClientName");
        checkNotNull(clientName);

        this.m_opcuaClientActions.stream().filter(opcClientName -> clientName.equals(opcClientName))
                .forEach(opcuaClientAction -> {
                    final OpcUaClientActionRunner clientActionRunner = new OpcUaClientActionRunner.Builder()
                            .setApplicationName(this.m_opcuaApplicationName)
                            .setApplicationUri(this.m_opcuaApplicationUri)
                            .setApplicationCertificate(this.m_opcuaApplicationCert)
                            .setRequestTimeout(this.m_requestTimeout)
                            .setKeyStoreClientAlias(this.m_keystoreClientAlias)
                            .setKeyStorePassword(this.m_keystorePassword)
                            .setKeyStoreServerAlias(this.m_keystoreServerAlias).setKeystoreType(this.m_keystoreType)
                            .setEndpointUrl(opcuaClientAction.endpointUrl())
                            .setSecurityPolicy(this.m_opcuaSecurityPolicy).setOpcUaUsername(this.m_opcuaUsername)
                            .setOpcUaPassword(this.m_opcuaPassword).build();
                    clientActionRunner.run();
                });

        this.m_activityLogService.saveLog("OPC-UA Client Action Executed");

        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK);

        LOGGER.info("OPC-UA Client Action Communication Done");
    }

    /** {@inheritDoc}} */
    @Override
    protected void doGet(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload,
            final KuraResponsePayload respPayload) throws KuraException {
        LOGGER.info("OPC-UA Configuration Retrieving...");
        // Retrieve the configurations
        if ("configurations".equals(reqTopic.getResources()[0])) {
            final ComponentConfiguration configuration = this.m_configurationService
                    .getComponentConfiguration(APP_ID);

            final IterableMap map = new HashedMap(configuration.getConfigurationProperties());
            final MapIterator it = map.mapIterator();

            while (it.hasNext()) {
                final Object key = it.next();
                final Object value = it.getValue();

                respPayload.addMetric((String) key, value);
            }
            this.m_activityLogService.saveLog("OPC-UA Configuration Retrieved");

            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK);
        }

        if ("list".equals(reqTopic.getResources()[0])) {
            final KuraPayload payload = new KuraPayload();
            this.m_opcuaClientActions.stream().map(opcClientAction -> opcClientAction.name())
                    .forEach(opcClientActionName -> payload.addMetric("action", opcClientActionName));
        }

        LOGGER.info("OPC-UA Configuration Retrieved");
    }

    /** {@inheritDoc}} */
    @Override
    protected void doPut(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload,
            final KuraResponsePayload respPayload) throws KuraException {
        LOGGER.info("OPC-UA Configuration Updating...");

        // Update the configurations
        if ("configurations".equals(reqTopic.getResources()[0])) {
            this.m_configurationService.updateConfiguration(APP_ID, reqPayload.metrics());

            this.m_activityLogService.saveLog("OPC-UA Configuration Updated");
            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK);
        }

        LOGGER.info("OPC-UA Configuration Updated");
    }

    /**
     * Used to extract configuration for populating placeholders with respective
     * values
     */
    private void extractConfiguration() {
        this.m_keystoreClientAlias = (String) this.m_properties.get(KEYSTORE_CLIENT_ALIAS);
        this.m_keystoreServerAlias = (String) this.m_properties.get(KEYSTORE_SERVER_ALIAS);
        this.m_keystorePassword = (String) this.m_properties.get(KEYSTORE_PASSWORD);
        this.m_opcuaApplicationName = (String) this.m_properties.get(OPCUA_APPLICATION_NAME);
        this.m_opcuaApplicationUri = (String) this.m_properties.get(OPCUA_APPLICATION_URI);
        this.m_opcuaApplicationCert = (String) this.m_properties.get(OPCUA_APPLICATION_CERTIFICATE);
        this.m_securityPolicy = (int) this.m_properties.get(OPCUA_SECURITY_POLICY);
        this.m_requestTimeout = (int) this.m_properties.get(OPCUA_REQUEST_TIMEOUT);
        this.m_keystoreType = (String) this.m_properties.get(KEYSTORE_TYPE);
        this.m_opcuaPassword = (String) this.m_properties.get(OPCUA_PASSWORD);
        this.m_opcuaUsername = (String) this.m_properties.get(OPCUA_USERNAME);
    }

    /**
     * Reinitialize Configurations as it gets updated
     */
    private void reinitializeConfiguration(final Map<String, Object> properties) {
        this.m_properties = properties;
        this.extractConfiguration();
        this.configureSecurityPolicy();
    }

    /**
     * Callback to be used while {@link ActivityLogService} is deregistering
     */
    public synchronized void unbindActivityLogService(final IActivityLogService activityLogService) {
        if (this.m_activityLogService == activityLogService) {
            this.m_activityLogService = null;
        }
    }

    /**
     * Callback to be used while {@link CloudService} is deregistering
     */
    public synchronized void unbindCloudService(final CloudService cloudService) {
        if (this.m_cloudService == cloudService) {
            super.setCloudService(this.m_cloudService = null);
        }
    }

    /**
     * Callback to be used while {@link ConfigurationService} is deregistering
     */
    public synchronized void unbindConfigurationService(final ConfigurationService configurationService) {
        if (this.m_configurationService == configurationService) {
            this.m_configurationService = null;
        }
    }

    /**
     * Callback to be used while {@link OpcUaClientAction} is deregistering
     */
    public synchronized void unbindOpcUa(final OpcUaClientAction opcuaClientAction) {
        if ((this.m_opcuaClientActions.size() > 0) && this.m_opcuaClientActions.contains(opcuaClientAction)) {
            this.m_opcuaClientActions.remove(opcuaClientAction);
        }
    }

    /**
     * Used to be called when configurations get updated
     */
    public void updated(final Map<String, Object> properties) {
        LOGGER.info("Updating OPC-UA Component...");

        this.reinitializeConfiguration(properties);

        properties.keySet().forEach(s -> LOGGER.info("Update - " + s + ": " + properties.get(s)));

        LOGGER.info("Updating OPC-UA Component... Done.");
    }

}