Java tutorial
/******************************************************************************* * 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.bluetooth.milling.machine; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.bluetooth.ServiceRecord; import org.apache.commons.collections.IterableMap; import org.apache.commons.collections.MapIterator; 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.ConfigurationService; import org.eclipse.kura.message.KuraRequestPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.eclipse.kura.system.SystemService; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.EventAdmin; import org.osgi.service.io.ConnectorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; import de.tum.in.activity.log.ActivityLogService; import de.tum.in.activity.log.IActivityLogService; /** * Used to consume all the service records provided by all the paired Bluetooth * Enabled Milling Machines * * @author AMIT KUMAR MONDAL * */ @Component(immediate = false, name = "de.tum.in.bluetooth.milling.machine") @Service(value = { BluetoothMillingMachine.class }) public class BluetoothMillingMachine extends Cloudlet { /** * Defines Application Configuration Metatype Id */ private static final String APP_CONF_ID = "de.tum.in.bluetooth.milling.machine"; /** * Application Identifier */ private static final String APP_ID = "MILLING-V1"; /** * Property for Bluetooth Real-time Topic Namespace */ private static final String BLUETOOTH_REALTIME_TOPIC = "bluetooth.realtime.topic"; /** * Logger */ private static final Logger LOGGER = LoggerFactory.getLogger(BluetoothMillingMachine.class); /** * Activity Log Service Dependency */ @Reference(bind = "bindActivityLogService", unbind = "unbindActivityLogService") private volatile IActivityLogService m_activityLogService; /** * Cloud Service Dependency */ @Reference(bind = "bindCloudService", unbind = "unbindCloudService") private volatile CloudService m_cloudService; /** * Configuration Service Dependency */ @Reference(bind = "bindConfigurationService", unbind = "unbindConfigurationService") private volatile ConfigurationService m_configurationService; /** * Connection Service Dependency */ @Reference(bind = "bindConnectorService", unbind = "unbindConnectorService") private volatile ConnectorService m_connectorService; /** * OSGi Event Admin Service Dependency */ @Reference(bind = "bindEventAdmin", unbind = "unbindEventAdmin") private volatile EventAdmin m_eventAdmin; /** * Future Event Handle for Executor */ private Future<?> m_handle; /** * Bluetooth Service Record Dependency for paired bluetooth devices */ @Reference(bind = "bindServiceRecord", unbind = "unbindServiceRecord", policy = ReferencePolicy.DYNAMIC, target = "(service.name=Bluetooth-Milling-Machine-Simulation)", cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE) private volatile ServiceRecord m_serviceRecord; /** * Holds List of Service Record for all the paired devices */ private final List<ServiceRecord> m_serviceRecords = Lists.newCopyOnWriteArrayList(); /** * Eclipse Kura System Service Dependency */ @Reference(bind = "bindSystemService", unbind = "unbindSystemService") private volatile SystemService m_systemService; /** * Bluetooth Connector Worker Thread */ private final ExecutorService m_worker; /* Constructor */ public BluetoothMillingMachine() { super(APP_ID); this.m_worker = Executors.newSingleThreadExecutor(); } /** * Callback used when this service component is activating */ @Activate protected synchronized void activate(final ComponentContext componentContext, final Map<String, Object> properties) { LOGGER.info("Activating Bluetooth Milling Machine Component..."); super.setCloudService(this.m_cloudService); super.activate(componentContext); LOGGER.info("Activating Bluetooth Milling Machine 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 ConnectorService} is registering */ public synchronized void bindConnectorService(final ConnectorService connectorService) { if (this.m_connectorService == null) { this.m_connectorService = connectorService; } } /** * Callback to be used while {@link EventAdmin} is registering */ public synchronized void bindEventAdmin(final EventAdmin eventAdmin) { if (this.m_eventAdmin == null) { this.m_eventAdmin = eventAdmin; } } /** * Callback to be used while {@link ServiceRecord} is registering */ public synchronized void bindServiceRecord(final ServiceRecord serviceRecord) { if (!this.m_serviceRecords.contains(serviceRecord)) { this.m_serviceRecords.add(serviceRecord); } } /** * Callback to be used while {@link SystemService} is registering */ public synchronized void bindSystemService(final SystemService systemService) { if (this.m_systemService == null) { this.m_systemService = systemService; } } /** * Callback used when this service component is deactivating */ @Override @Deactivate protected void deactivate(final ComponentContext context) { LOGGER.debug("Deactivating Bluetooth Milling Machine Component..."); super.deactivate(context); this.m_serviceRecords.clear(); this.m_worker.shutdown(); LOGGER.debug("Deactivating Bluetooth Milling Machine Component... Done."); } /** {@inheritDoc} */ @Override protected void doExec(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload, final KuraResponsePayload respPayload) throws KuraException { if ("start".equals(reqTopic.getResources()[0])) { LOGGER.info("Bluetooth Milling Machine Communication Started..."); this.m_serviceRecords.stream().forEach(serviceRecord -> this.doPublish(serviceRecord)); this.m_activityLogService.saveLog("Bluetooth Milling Machine Communication Started"); LOGGER.info("Bluetooth Milling Machine Communication Done"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK); } if ("stop".equals(reqTopic.getResources()[0])) { LOGGER.info("Bluetooth Milling Machine Communication Stopped..."); this.m_worker.shutdownNow(); LOGGER.info("Bluetooth Milling Machine Communication Done"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK); } } /** {@inheritDoc} */ @Override protected void doGet(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload, final KuraResponsePayload respPayload) throws KuraException { LOGGER.info("Bluetooth Milling Machine Component GET handler"); // Retrieve the configurations if ("configurations".equals(reqTopic.getResources()[0])) { LOGGER.info("Bluetooth Milling Machine Configuration Retrieval Started..."); final ComponentConfiguration configuration = this.m_configurationService .getComponentConfiguration(APP_CONF_ID); final IterableMap map = (IterableMap) 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("Bluetooth Milling Machine Configuration Retrieved"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK); LOGGER.info("Bluetooth Milling Machine Configuration Retrieval Finished"); } } /** * Used to publish real-time data retrieved from all the milling machines * and cache it */ private void doPublish(final ServiceRecord serviceRecord) { // cancel a current worker handle if one if active if (this.m_handle != null) { this.m_handle.cancel(true); } LOGGER.debug("Publishing Real-time Data Started....."); final String remoteDeviceAddress = serviceRecord.getHostDevice().getBluetoothAddress(); LOGGER.info("Active Bluetooth Data Transfer for " + remoteDeviceAddress); final String bluetoothRealtimeTopic = this.m_systemService.getProperties() .getProperty(BLUETOOTH_REALTIME_TOPIC); final BluetoothConnector bluetoothConnector = new BluetoothConnector.Builder() .setConnectorService(this.m_connectorService).setTopic(bluetoothRealtimeTopic) .setServiceRecord(serviceRecord).setEventAdmin(this.m_eventAdmin) .setCloudClient(this.getCloudApplicationClient()).build(); this.m_handle = this.m_worker.submit(bluetoothConnector); } /** {@inheritDoc} */ @Override protected void doPut(final CloudletTopic reqTopic, final KuraRequestPayload reqPayload, final KuraResponsePayload respPayload) throws KuraException { LOGGER.info("Bluetooth Milling Machine Configuration Updating..."); // Update the configurations if ("configurations".equals(reqTopic.getResources()[0])) { this.m_configurationService.updateConfiguration(APP_CONF_ID, reqPayload.metrics()); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_OK); } this.m_activityLogService.saveLog("Bluetooth Milling Machine Configuration Updated"); LOGGER.info("Bluetooth Milling Machine Configuration Updated"); } /** * 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 ConnectorService} is deregistering */ public synchronized void unbindConnectorService(final ConnectorService connectorService) { if (this.m_connectorService != null) { this.m_connectorService = null; } } /** * Callback to be used while {@link EventAdmin} is deregistering */ public synchronized void unbindEventAdmin(final EventAdmin eventAdmin) { if (this.m_cloudService == eventAdmin) { this.m_eventAdmin = null; } } /** * Callback to be used while {@link ServiceRecord} is deregistering */ public synchronized void unbindServiceRecord(final ServiceRecord serviceRecord) { if ((this.m_serviceRecords.size() > 0) && this.m_serviceRecords.contains(serviceRecord)) { this.m_serviceRecords.remove(serviceRecord); } } /** * Callback to be used while {@link SystemService} is deregistering */ public synchronized void unbindSystemService(final SystemService systemService) { if (this.m_systemService == systemService) { this.m_systemService = null; } } /** * Used to be called when configurations will get updated */ public void updated(final Map<String, Object> properties) { LOGGER.info("Updating Bluetooth Milling Machine Component..."); properties.keySet().forEach(s -> LOGGER.info("Update - " + s + ": " + properties.get(s))); LOGGER.info("Updating Bluetooth Milling Machine Component... Done."); } }