All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sputnikdev.bluetooth.manager.impl.BluetoothManagerBuilder Maven / Gradle / Ivy

package org.sputnikdev.bluetooth.manager.impl;

/*-
 * #%L
 * org.sputnikdev:bluetooth-manager
 * %%
 * Copyright (C) 2017 Sputnik Dev
 * %%
 * 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.
 * #L%
 */

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sputnikdev.bluetooth.manager.AdapterDiscoveryListener;
import org.sputnikdev.bluetooth.manager.BluetoothGovernor;
import org.sputnikdev.bluetooth.manager.BluetoothManager;
import org.sputnikdev.bluetooth.manager.DeviceDiscoveryListener;
import org.sputnikdev.bluetooth.manager.DiscoveredAdapter;
import org.sputnikdev.bluetooth.manager.DiscoveredDevice;
import org.sputnikdev.bluetooth.manager.ManagerListener;
import org.sputnikdev.bluetooth.manager.transport.BluetoothObjectFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * Bluetooth Manager instance builder.
 *
 * @author Vlad Kolotov
 */
public class BluetoothManagerBuilder {

    private Logger logger = LoggerFactory.getLogger(BluetoothManagerBuilder.class);

    private int discoveryRate = BluetoothManagerImpl.DISCOVERY_RATE_SEC;
    private boolean rediscover;
    private int refreshRate = BluetoothManagerImpl.REFRESH_RATE_SEC;
    private boolean combinedAdapters;
    private boolean combinedDevices = true;
    private boolean tinybTransport;
    private String bluegigaRegex;
    private boolean started = true;
    private boolean discovering;
    private boolean ignoreTransportInitErrors;

    /**
     * Sets how frequent the discovery process should update its state.
     * Note: discovery rate must be set before calling {@link BluetoothManager#start} method
     * @param seconds discovery rate in seconds
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withDiscoveryRate(int seconds) {
        discoveryRate = seconds;
        return this;
    }

    /**
     * Sets whether the discovery process should repeatedly notify clients
     * ({@link AdapterDiscoveryListener#discovered(DiscoveredAdapter)} and
     * {@link DeviceDiscoveryListener#discovered(DiscoveredDevice)}) about discovered devices every update step.
     * See {@link #withDiscoveryRate(int)} to set discovery rate
     * @param rediscover controls whether clients
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withRediscover(boolean rediscover) {
        this.rediscover = rediscover;
        return this;
    }

    /**
     * Sets the refresh rate which controls how often bluetooth devices are checked/updated.
     * Restart is required if the manager is already started.
     * @param refreshRate refresh rate
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withRefreshRate(int refreshRate) {
        this.refreshRate = refreshRate;
        return this;
    }

    /**
     * If set to true all discovered adapters are combined into a single adapter and therefore can be controlled as
     * a single unit.
     * @param combinedAdapters if true, all discovered adapters are combined into a single adapter
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withCombinedAdapters(boolean combinedAdapters) {
        this.combinedAdapters = combinedAdapters;
        return this;
    }

    /**
     * If set to true, all discovered devices with the same address (but discovered through different adapters)
     * are combined into a single device and therefore can be controlled as a single unit.
     * @param combinedDevices if true, all discovered devices with the same address are combined into a single device
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withCombinedDevices(boolean combinedDevices) {
        this.combinedDevices = combinedDevices;
        return this;
    }

    /**
     * Is set to true, TinyB transport is registered (if found in the classpath).
     * @param tinybTransport register TinyB transport
     * @return the same builder instance
     */
    public BluetoothManagerBuilder withTinyBTransport(boolean tinybTransport) {
        this.tinybTransport = tinybTransport;
        return this;
    }

    /**
     * If the provided argument is not null, then BlueGiga is registered with the provided regular expression
     * for BlueGiga adapters (serial ports) auto discovery.
     * WARNING!: It is very important not to make the regular expression too wide so that ONLY Bluegiga
     * adapters/ serial ports are matched by the regular expression. If the regular expression is too broad,
     * this can lead to hardware malfunction/damage of other devices that are accidentally matched by the
     * regular expression. USE THIS FEATURE AT YOUR OWN RISK.
     * 
Regular expression examples: *
    *
  • Defining some specific serial ports (preferable option): (/dev/ttyACM1)|(/dev/ttyACM2)
  • *
  • Matching all serial ports on Linux: ((/dev/ttyACM)[0-9]{1,3})
  • *
  • Matching all serial ports on OSX: (/dev/tty.(usbmodem).*)
  • *
  • Matching all serial ports on Windows: ((COM)[0-9]{1,3})
  • *
  • Matching all serial ports with some exclusions: (?!/dev/ttyACM0|/dev/ttyACM5)((/dev/ttyACM)[0-9]{1,3})
  • *
  • Default regular expression is to match nothing: (?!)
  • *
* @param bluegigaRegex BlueGiga serial port regular expression * @return the same builder instance */ public BluetoothManagerBuilder withBlueGigaTransport(String bluegigaRegex) { this.bluegigaRegex = bluegigaRegex; return this; } /** * If set to true, bluetooth manager will be started. * @param started if true, bluetooth manager will be started * @return the same builder instance */ public BluetoothManagerBuilder withStarted(boolean started) { this.started = started; return this; } /** * If set to true, the discovery process will be enabled. * @param discovering if true, the discovery process will be enabled * @return the same builder instance */ public BluetoothManagerBuilder withDiscovering(boolean discovering) { this.discovering = discovering; return this; } /** * If set to true, initialization errors for the transport factories are ignored. * @param ignoreTransportInitErrors ignore initialization errors for transports * @return the same builder instance */ public BluetoothManagerBuilder withIgnoreTransportInitErrors(boolean ignoreTransportInitErrors) { this.ignoreTransportInitErrors = ignoreTransportInitErrors; return this; } /** * Builds a new instance of the Bluetooth Manager. * @return a new instance of the Bluetooth Manager */ public BluetoothManager build() { BluetoothManagerImpl manager = new BluetoothManagerImpl(); manager.setDiscoveryRate(discoveryRate); manager.setRediscover(rediscover); manager.setRefreshRate(refreshRate); manager.enableCombinedAdapters(combinedAdapters); manager.enableCombinedDevices(combinedDevices); if (tinybTransport) { loadTinyBTransport(manager); } if (bluegigaRegex != null) { loadBlueGigaTransport(manager); } if (started) { manager.start(discovering); } Runtime.getRuntime().addShutdownHook(new Thread(manager::dispose)); return manager; } private void loadTinyBTransport(BluetoothManager bluetoothManager) { try { Class tinybFactoryClass = Class.forName("org.sputnikdev.bluetooth.manager.transport.tinyb.TinyBFactory"); boolean loaded = (boolean) tinybFactoryClass.getDeclaredMethod("loadNativeLibraries") .invoke(tinybFactoryClass); if (loaded) { BluetoothObjectFactory tinyBFactory = (BluetoothObjectFactory) tinybFactoryClass.newInstance(); bluetoothManager.registerFactory(tinyBFactory); bluetoothManager.addManagerListener(new DisposeListener(tinyBFactory)); } else { if (ignoreTransportInitErrors) { logger.warn("Native libraries for TinyB transport could not be loaded."); } else { throw new IllegalStateException("Native libraries for TinyB transport could not be loaded."); } } } catch (Exception ex) { if (ignoreTransportInitErrors) { logger.warn("Could not initialize TinyB transport: {}", ex.getMessage()); } else { throw new IllegalStateException(ex); } } } private void loadBlueGigaTransport(BluetoothManager bluetoothManager) { try { Class bluegigaFactoryClass = Class.forName("org.sputnikdev.bluetooth.manager.transport.bluegiga.BluegigaFactory"); Constructor constructor = bluegigaFactoryClass.getConstructor(String.class); BluetoothObjectFactory bluegigaFactory = (BluetoothObjectFactory) constructor.newInstance(bluegigaRegex); bluetoothManager.registerFactory((BluetoothObjectFactory) constructor.newInstance(bluegigaRegex)); bluetoothManager.addManagerListener(new DisposeListener(bluegigaFactory)); } catch (Exception ex) { if (ignoreTransportInitErrors) { logger.warn("Could not initialize BlueGiga transport: {}", ex.getMessage()); } else { throw new IllegalStateException(ex); } } } private static class DisposeListener implements ManagerListener { private final BluetoothObjectFactory factory; DisposeListener(BluetoothObjectFactory factory) { this.factory = factory; } @Override public void ready(BluetoothGovernor governor, boolean ready) { } @Override public void disposed() { try { factory.getClass().getMethod("dispose").invoke(factory); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new IllegalStateException("Could not invoke " + factory.getClass().getSimpleName() + ".dispose method", e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy