org.eclipse.leshan.server.californium.impl.LeshanServer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.leshan.server.californium.impl.LeshanServer.java

Source

/*******************************************************************************
 * Copyright (c) 2013-2015 Sierra Wireless and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * 
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *    http://www.eclipse.org/org/documents/edl-v10.html.
 * 
 * Contributors:
 *     Sierra Wireless - initial API and implementation
 *******************************************************************************/
package org.eclipse.leshan.server.californium.impl;

import java.net.InetSocketAddress;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

import org.bson.Document;
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.Endpoint;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder;
import org.eclipse.leshan.core.node.codec.LwM2mNodeDecoder;
import org.eclipse.leshan.core.node.codec.LwM2mNodeEncoder;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.DownlinkRequest;
import org.eclipse.leshan.core.request.ObserveRequest;
import org.eclipse.leshan.core.response.ErrorCallback;
import org.eclipse.leshan.core.response.LwM2mResponse;
import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.core.response.ResponseCallback;
import org.eclipse.leshan.server.Destroyable;
import org.eclipse.leshan.server.LwM2mServer;
import org.eclipse.leshan.server.Startable;
import org.eclipse.leshan.server.Stoppable;
import org.eclipse.leshan.server.californium.CaliforniumObservationRegistry;
import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.client.Client;
import org.eclipse.leshan.server.client.ClientRegistry;
import org.eclipse.leshan.server.client.ClientRegistryListener;
import org.eclipse.leshan.server.client.ClientUpdate;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.observation.ObservationRegistry;
import org.eclipse.leshan.server.observation.ObservationRegistryListener;
import org.eclipse.leshan.server.registration.RegistrationHandler;
import org.eclipse.leshan.server.request.LwM2mRequestSender;
import org.eclipse.leshan.server.response.ResponseListener;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityRegistry;
import org.eclipse.leshan.util.Validate;
import org.leshan.server.configuration.DataBaseConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

/**
 * A Lightweight M2M server.
 * <p>
 * This implementation starts a Californium {@link CoapServer} with a non-secure and secure endpoint. This CoAP server
 * defines a <i>/rd</i> resource as described in the CoRE RD specification.
 * </p>
 * <p>
 * This class is the entry point to send synchronous and asynchronous requests to registered clients.
 * </p>
 * <p>
 * The {@link LeshanServerBuilder} should be the preferred way to build an instance of {@link LeshanServer}.
 * </p>
 */
public class LeshanServer implements LwM2mServer {

    private final CoapServer coapServer;

    private static final Logger LOG = LoggerFactory.getLogger(LeshanServer.class);

    private final LwM2mRequestSender requestSender;

    private final ClientRegistry clientRegistry;

    private final CaliforniumObservationRegistry observationRegistry;

    private final SecurityRegistry securityRegistry;

    private final LwM2mModelProvider modelProvider;

    private final CoapEndpoint nonSecureEndpoint;

    private final CoapEndpoint secureEndpoint;

    private final LwM2mNodeEncoder encoder;

    private final LwM2mNodeDecoder decoder;
    // private KeyedMessage < Integer, String > document;
    // ****************************************************
    private String json;

    private static Producer<Integer, String> producer;

    private static final String topic = "panelEvents";

    protected static final int KeyedMessage = 0;

    protected static final int Integer = 0;

    protected static final int String = 0;

    private final String mongoDBAdd = DataBaseConfiguration.getInstance().getPropertyString("MONGODB_ADD");

    private int mongoDBPort = DataBaseConfiguration.getInstance().getPropertyInt("MONGODB_PORT");

    private final String kafkaBroker1Add = DataBaseConfiguration.getInstance()
            .getPropertyString("KAFKA_BROKER1_ADD");

    private final int kafkaBroker1Port = DataBaseConfiguration.getInstance().getPropertyInt("KAFKA_BROKER1_PORT");
    // ****************************************************

    /**
     * Initialize a server which will bind to the specified address and port.
     *
     * @param localAddress the address to bind the CoAP server.
     * @param localSecureAddress the address to bind the CoAP server for DTLS connection.
     * @param clientRegistry the registered {@link Client} registry.
     * @param securityRegistry the {@link SecurityInfo} registry.
     * @param observationRegistry the {@link Observation} registry.
     * @param modelProvider provides the objects description for each client.
     * @param decoder
     * @param encoder
     */
    public LeshanServer(InetSocketAddress localAddress, InetSocketAddress localSecureAddress,
            final ClientRegistry clientRegistry, final SecurityRegistry securityRegistry,
            final CaliforniumObservationRegistry observationRegistry, final LwM2mModelProvider modelProvider,
            LwM2mNodeEncoder encoder, LwM2mNodeDecoder decoder) {
        Validate.notNull(localAddress, "IP address cannot be null");
        Validate.notNull(localSecureAddress, "Secure IP address cannot be null");
        Validate.notNull(clientRegistry, "clientRegistry cannot be null");
        Validate.notNull(securityRegistry, "securityRegistry cannot be null");
        Validate.notNull(observationRegistry, "observationRegistry cannot be null");
        Validate.notNull(modelProvider, "modelProvider cannot be null");
        Validate.notNull(encoder, "encoder cannot be null");
        Validate.notNull(decoder, "decoder cannot be null");

        // Init registries
        this.clientRegistry = clientRegistry;
        this.securityRegistry = securityRegistry;
        this.observationRegistry = observationRegistry;
        this.modelProvider = modelProvider;
        this.encoder = encoder;
        this.decoder = decoder;

        // Cancel observations on client unregistering
        this.clientRegistry.addListener(new ClientRegistryListener() {

            @Override
            public void updated(final ClientUpdate update, final Client clientUpdated) {
                if (!clientUpdated.getFirstUpdate()) {
                    observeResource(clientUpdated);
                    clientUpdated.setFirstUpdate(true);
                }
            }

            @Override
            public void unregistered(final Client client) {
                LeshanServer.this.observationRegistry.cancelObservations(client);
                requestSender.cancelPendingRequests(client);
            }

            @Override
            public void registered(final Client client) {
            }
        });

        // default endpoint
        coapServer = new CoapServer() {
            @Override
            protected Resource createRoot() {
                return new RootResource();
            }
        };
        nonSecureEndpoint = new CoapEndpoint(localAddress, NetworkConfig.getStandard(),
                this.observationRegistry.getObservationStore());
        nonSecureEndpoint.addNotificationListener(observationRegistry);
        observationRegistry.setNonSecureEndpoint(nonSecureEndpoint);
        coapServer.addEndpoint(nonSecureEndpoint);

        // secure endpoint
        Builder builder = new DtlsConnectorConfig.Builder(localSecureAddress);
        builder.setPskStore(new LwM2mPskStore(this.securityRegistry, this.clientRegistry));
        PrivateKey privateKey = this.securityRegistry.getServerPrivateKey();
        PublicKey publicKey = this.securityRegistry.getServerPublicKey();
        X509Certificate[] X509CertChain = this.securityRegistry.getServerX509CertChain();

        // if in raw key mode and not in X.509 set the raw keys
        if (X509CertChain == null && privateKey != null && publicKey != null) {
            builder.setIdentity(privateKey, publicKey);
        }
        // if in X.509 mode set the private key, certificate chain, public key is extracted from the certificate
        if (privateKey != null && X509CertChain != null && X509CertChain.length > 0) {
            builder.setIdentity(privateKey, X509CertChain, false);
        }

        Certificate[] trustedCertificates = securityRegistry.getTrustedCertificates();
        if (trustedCertificates != null && trustedCertificates.length > 0) {
            builder.setTrustStore(trustedCertificates);
        }

        secureEndpoint = new CoapEndpoint(new DTLSConnector(builder.build()), NetworkConfig.getStandard(),
                this.observationRegistry.getObservationStore());
        secureEndpoint.addNotificationListener(observationRegistry);
        observationRegistry.setSecureEndpoint(secureEndpoint);
        coapServer.addEndpoint(secureEndpoint);

        // define /rd resource
        final RegisterResource rdResource = new RegisterResource(
                new RegistrationHandler(this.clientRegistry, this.securityRegistry));
        coapServer.add(rdResource);

        // create sender
        final Set<Endpoint> endpoints = new HashSet<>();
        endpoints.add(nonSecureEndpoint);
        endpoints.add(secureEndpoint);
        requestSender = new CaliforniumLwM2mRequestSender(endpoints, this.observationRegistry, modelProvider,
                encoder, decoder);
    }

    @Override
    public void start() {

        // Start registries
        if (clientRegistry instanceof Startable) {
            ((Startable) clientRegistry).start();
        }
        if (securityRegistry instanceof Startable) {
            ((Startable) securityRegistry).start();
        }
        if (observationRegistry instanceof Startable) {
            ((Startable) observationRegistry).start();
        }

        // Start server
        coapServer.start();

        LOG.info("LWM2M server started at coap://{}, coaps://{}.", getNonSecureAddress(), getSecureAddress());
    }

    @Override
    public void stop() {
        // Stop server
        coapServer.stop();

        // Start registries
        if (clientRegistry instanceof Stoppable) {
            ((Stoppable) clientRegistry).stop();
        }
        if (securityRegistry instanceof Stoppable) {
            ((Stoppable) securityRegistry).stop();
        }
        if (observationRegistry instanceof Stoppable) {
            ((Stoppable) observationRegistry).stop();
        }

        LOG.info("LWM2M server stopped.");
    }

    public void destroy() {
        // Destroy server
        coapServer.destroy();

        // Destroy registries
        if (clientRegistry instanceof Destroyable) {
            ((Destroyable) clientRegistry).destroy();
        }
        if (securityRegistry instanceof Destroyable) {
            ((Destroyable) securityRegistry).destroy();
        }
        if (observationRegistry instanceof Destroyable) {
            ((Destroyable) observationRegistry).destroy();
        }

        LOG.info("LWM2M server destroyed.");
    }

    @Override
    public ClientRegistry getClientRegistry() {
        return this.clientRegistry;
    }

    @Override
    public ObservationRegistry getObservationRegistry() {
        return this.observationRegistry;
    }

    @Override
    public SecurityRegistry getSecurityRegistry() {
        return this.securityRegistry;
    }

    @Override
    public LwM2mModelProvider getModelProvider() {
        return this.modelProvider;
    }

    @Override
    public <T extends LwM2mResponse> T send(final Client destination, final DownlinkRequest<T> request)
            throws InterruptedException {
        return requestSender.send(destination, request, null);
    }

    @Override
    public <T extends LwM2mResponse> T send(final Client destination, final DownlinkRequest<T> request,
            long timeout) throws InterruptedException {
        return requestSender.send(destination, request, timeout);
    }

    @Override
    public <T extends LwM2mResponse> void send(final Client destination, final DownlinkRequest<T> request,
            final ResponseCallback<T> responseCallback, final ErrorCallback errorCallback) {
        requestSender.send(destination, request, responseCallback, errorCallback);
    }

    @Override
    public <T extends LwM2mResponse> void send(Client destination, String requestTicket,
            DownlinkRequest<T> request) {
        requestSender.send(destination, requestTicket, request);
    }

    @Override
    public void addResponseListener(ResponseListener listener) {
        requestSender.addResponseListener(listener);
    }

    @Override
    public void removeResponseListener(ResponseListener listener) {
        requestSender.removeResponseListener(listener);
    }

    /**
     * @return the underlying {@link CoapServer}
     */
    public CoapServer getCoapServer() {
        return coapServer;
    }

    public InetSocketAddress getNonSecureAddress() {
        return nonSecureEndpoint.getAddress();
    }

    public InetSocketAddress getSecureAddress() {
        return secureEndpoint.getAddress();
    }

    /**
     * The Leshan Root Resource.
     */
    private class RootResource extends CoapResource {

        public RootResource() {
            super("");
        }

        @Override
        public void handleGET(CoapExchange exchange) {
            exchange.respond(ResponseCode.NOT_FOUND);
        }

        public List<Endpoint> getEndpoints() {
            return coapServer.getEndpoints();
        }
    }

    // added observeResource for observing resource after ragistering to server.
    private void observeResource(final Client client) {
        // ObserveRequest request = new ObserveRequest("2050/0/0");
        String contentFormatParam = "TLV";
        ContentFormat contentFormat = contentFormatParam != null
                ? ContentFormat.fromName(contentFormatParam.toUpperCase())
                : null;
        ObserveRequest request = new ObserveRequest(contentFormat, "/3/0/13");
        // ObserveRequest request = new ObserveRequest(contentFormat, "/2050/0/0");
        ObserveResponse cResponse = null;
        try {

            long i = 50000L;
            cResponse = this.send(client, request, i);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        LOG.debug("cResponse : " + cResponse);

        Observation observation = cResponse.getObservation();

        observationRegistry.addListener(new ObservationRegistryListener() {

            @Override
            public void newObservation(Observation observation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void cancelled(Observation observation) {
                LOG.debug("Observation Cancelled ....");

            }

            @Override
            public void newValue(Observation observation, ObserveResponse response) {
                // writeToFile(observation, mostRecentValue,timestampedValues );
                // TODO Auto-generated method stub
                if (client.getRegistrationId().equals(observation.getRegistrationId())) {

                    // initialize("document");

                    /*
                     * try { publishMesssage(); } catch (Exception e1) { // TODO Auto-generated catch block
                     * e1.printStackTrace(); }
                     */

                    // ********Saving into database**************************
                    Gson gson = new Gson();
                    // List<TimestampedLwM2mNode> obresp = response.getTimestampedLwM2mNode();
                    JsonObject jsonObject = new JsonParser().parse(gson.toJson(response.getContent()))
                            .getAsJsonObject();

                    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    java.util.Date date = new java.util.Date();
                    String timestamp = dateFormat.format(date);

                    try {

                        MongoClient mongoClient = new MongoClient(mongoDBAdd, mongoDBPort);
                        MongoDatabase database = mongoClient.getDatabase("qolsys");
                        MongoCollection<Document> collection = database.getCollection("events");
                        String event = jsonObject.get("value").getAsString().trim();
                        Document document = new Document();
                        document.put("client_ep", client.getEndpoint());
                        document.put("event", event);
                        document.put("timestamp", timestamp);
                        collection.insertOne(document);
                        json = document.toJson();
                        sendToBroker(topic, json);
                        mongoClient.close();
                        producer.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.err.println(e.getClass().getName() + ": " + e.getMessage());
                        System.exit(0);
                    }

                    // ******************************************************

                    LOG.debug("recent observation ...." + observation);
                }
            }

            // *************************************************************

            /*
             * private static Producer<Integer, String> producer; private static final String topic = "mytopic";
             */

            @SuppressWarnings("deprecation")
            public void sendToBroker(String topic, String msg) {

                Properties producerProps = new Properties();
                producerProps.put("metadata.broker.list", kafkaBroker1Add + ":" + kafkaBroker1Port);
                producerProps.put("serializer.class", "kafka.serializer.StringEncoder");
                producerProps.put("request.required.acks", "1");
                ProducerConfig producerConfig = new ProducerConfig(producerProps);
                producer = new Producer<Integer, String>(producerConfig);
                KeyedMessage<Integer, String> keyedMsg = new KeyedMessage<Integer, String>(topic, msg);
                producer.send(keyedMsg);

            }

        });

    }
}