at.ac.tuwien.infosys.DeviceManager.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.tuwien.infosys.DeviceManager.java

Source

/*
 * Copyright (c) 2014 Technische Universitaet Wien (TUW), Distributed SystemsGroup E184.
 * 
 * This work was partially supported by the Pacific Controls under the Pacific Controls 
 * Cloud Computing Lab (pc3l.infosys.tuwien.ac.at)
 *
 * 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.
 * 
 * Written by Michael Voegler
 */
package at.ac.tuwien.infosys;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Logger;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.AsyncRestTemplate;

import at.ac.tuwien.infosys.model.Device;
import at.ac.tuwien.infosys.model.Profile;
import at.ac.tuwien.infosys.store.IDeviceStore;
import at.ac.tuwien.infosys.store.Image;
import at.ac.tuwien.infosys.store.model.DeviceDTO;
import at.ac.tuwien.infosys.store.model.DevicesDTO;

@RestController
@RequestMapping("/device-manager")
public class DeviceManager {

    public static Logger logger = Logger.getLogger(DeviceManager.class.getName());

    @Autowired
    private IDeviceStore deviceStore;

    @Autowired
    private AsyncRestTemplate asyncRestTemplate;

    /**
     * This method is used by SD gateway to report its current profile to the
     * Manager. It is used to simulate POST with GET to support the device.
     * 
     * @param msg
     * @return
     */
    @RequestMapping(value = "/profile-test/{msg}", method = RequestMethod.GET)
    public ResponseEntity<String> ping(@PathVariable String msg) {
        logger.info("Device profile is : " + msg);

        return new ResponseEntity<String>("Received: " + msg, HttpStatus.OK);
    }

    /**
     * Adds a profile for the given device.
     * 
     * @param id
     * @param profile
     * @return
     */
    @RequestMapping(value = "/profile/{id}", method = RequestMethod.POST)
    public ResponseEntity<String> addProfile(@PathVariable String id, @RequestBody String profile) {

        logger.info("Received profile for device: " + id + " : " + profile);

        if (!deviceStore.hasDevice(id)) {
            logger.info("Device for given id " + id + " not known!");

            deviceStore.addDevice(id);

            logger.info("Device for given id " + id + " stored!");
        }

        deviceStore.addProfile(id, profile);

        return new ResponseEntity<String>("Profile added for: " + id, HttpStatus.OK);
    }

    /**
     * Adds a ipAddress for the given device.
     * 
     * @param id
     * @param ipAddress
     * @return
     */
    @RequestMapping(value = "/registerIP/{id}", method = RequestMethod.POST)
    public ResponseEntity<String> addIpAddress(@PathVariable String id, @RequestBody String ipAddress) {

        logger.info("Received ipAddress for device: " + id + " : " + ipAddress);

        if (!deviceStore.hasDevice(id)) {
            logger.info("Device for given id " + id + " not known!");

            deviceStore.addDevice(id);

            logger.info("Device for given id " + id + " stored!");
        }

        deviceStore.addIpAddress(id, ipAddress);

        return new ResponseEntity<String>("IpAddress added for: " + id, HttpStatus.OK);
    }

    @RequestMapping(value = "/registerMeta/{id}/{metaInfo}", method = RequestMethod.GET)
    public ResponseEntity<String> addMetaInfo(@PathVariable String id, @PathVariable String metaInfo) {
        logger.info("Received meta information for device: " + id + " : " + metaInfo);
        if (!deviceStore.hasDevice(id)) {
            deviceStore.addDevice(id);
        }
        deviceStore.addDeviceMetaInfo(id, metaInfo);
        return new ResponseEntity<String>("Meta Info added for: " + id, HttpStatus.OK);
    }

    @RequestMapping(value = "/profile/{id}", method = RequestMethod.GET)
    public ResponseEntity<Profile> getProfile(@PathVariable String id) {
        logger.info("Get profile for device: " + id);

        if (!deviceStore.hasDevice(id)) {
            logger.info("Device for given id " + id + " not known!");
            return new ResponseEntity<Profile>(HttpStatus.BAD_REQUEST);
        }

        Profile ret = deviceStore.getProfile(id);
        return new ResponseEntity<Profile>(ret, HttpStatus.OK);
    }

    // Gateway sends profile as part of (file- or url-parameter) update request!
    /**
     * When invoked by a device, e.g., gateway, provides the new sd-image, if
     * available.
     */
    @RequestMapping(value = "/update/{id}", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getUpdate(@PathVariable String id) {

        if (!deviceStore.hasDevice(id)) {
            logger.info("Device for given id " + id + " not known!");

            deviceStore.addDevice(id);

            logger.info("Device for given id " + id + " stored!");
            return new ResponseEntity<byte[]>("Nothing to update!".getBytes(), HttpStatus.OK);
        }

        return new ResponseEntity<byte[]>("Nothing to update!".getBytes(), HttpStatus.OK);
        //FIXME Disable updates for local installation
        //      try {
        //         InputStream updateImage = deviceStore.getUpdate(id);
        //
        //         if (updateImage == null) {
        //            logger.info("No update available for device!");
        //            return new ResponseEntity<byte[]>(
        //                  "Nothing to update!".getBytes(), HttpStatus.OK);
        //         }
        //
        //         logger.info("Update available for device!");
        //
        //         return new ResponseEntity<byte[]>(IOUtils.toByteArray(updateImage),
        //               HttpStatus.OK);
        //
        //      } catch (IOException e) {
        //         logger.info("No update available for device!");
        //         return new ResponseEntity<byte[]>("Nothing to update!".getBytes(),
        //               HttpStatus.OK);
        //      }
    }

    /**
     * Invoked by a device after a successful update, to notify the manager to
     * remove the update from the queue.
     */
    @RequestMapping(value = "/update-successful/{deviceId}/{imageId}", method = RequestMethod.GET)
    public ResponseEntity<String> updateSuccessful(@PathVariable String deviceId, @PathVariable String imageId) {

        if (!deviceStore.hasDevice(deviceId)) {
            logger.info("Device for given id " + deviceId + " not known!");
            return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
        }

        deviceStore.removeUpdate(deviceId, imageId);

        logger.info("Device successfully finished the update!");

        return new ResponseEntity<String>("Update removed from Manager's queue!", HttpStatus.OK);
    }

    /**
     * Invoked by the ArtifactBuilder to notify the Manager that a new device
     * update is available.
     * 
     * @param deviceId
     * @param imageId
     * @param attachment
     * @return
     */
    // TODO get rid of deviceId since Image contains id or set of ids already!
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public ResponseEntity<String> update(@RequestBody Image image) {

        logger.info("Received request to update device(s): " + image.getDeviceIds() + " with image: " + image);

        deviceStore.addUpdate(image);

        //      if (force){
        //invoke API manager
        for (String deviceId : image.getDeviceIds()) {
            ListenableFuture<ResponseEntity<String>> result = asyncRestTemplate
                    .getForEntity("http://localhost:8080/APIManager/invokeAgent/" + deviceId, String.class);

            result.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
                @Override
                public void onSuccess(ResponseEntity<String> result) {
                    //                  LOGGER.info("Received result from node: "
                    //                        + result.getBody());
                    //                  // Add to a queue
                    //                  endTS = System.currentTimeMillis();
                    //                  LOGGER.info("Invocation time was: " + startTime + ","
                    //                        + endTS);
                }

                @Override
                public void onFailure(Throwable t) {
                    //                  LOGGER.info("Error contacting device: "
                    //                        + t.getMessage());
                }
            });

        }

        //      }
        return new ResponseEntity<String>("Successfully stored image!", HttpStatus.OK);
    }

    @RequestMapping(value = "/devices", method = RequestMethod.GET)
    public ResponseEntity<DevicesDTO> getAllDevices() {

        List<Device> devices = deviceStore.getAllDevices();
        // List<DeviceDTO> dtos = new ArrayList<DeviceDTO>();
        DevicesDTO dtos = new DevicesDTO();

        for (Device device : devices) {
            // location=gh1&type=FM5300
            DeviceDTO dto = new DeviceDTO(device.getId(), device.getName(), device.getMetaInfo());
            String[] meta = device.getMetaInfo().split("&");
            for (String datum : meta) {
                String[] split = datum.split("=");
                dto.addMetaData(split[0], split[1]);
            }
            dtos.addDTO(dto);
        }
        return new ResponseEntity<DevicesDTO>(dtos, HttpStatus.OK);
    }

    @RequestMapping(value = "/clean", method = RequestMethod.GET)
    public ResponseEntity<String> clean() {
        try {
            deviceStore.clean();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ResponseEntity<String>(HttpStatus.OK);
    }

    @RequestMapping(value = "/unregister/{deviceId}", method = RequestMethod.DELETE)
    public ResponseEntity<String> unregisterDevice(@PathVariable String deviceId) {
        deviceStore.removeDevice(deviceId);
        return new ResponseEntity<String>(HttpStatus.OK);
    }

    @Configuration
    public static class AsyncRestTemplateFactory {
        @Bean
        public AsyncRestTemplate createAsyncRestTemplate() {
            AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
            return asyncRestTemplate;
        }
    }
}