Java tutorial
/******************************************************************************* * 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); } }); } }