/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2008-2009 Michael Lifshits
* Copyright (C) 2008-2009 Vlad Skarzhevskyy
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*
* @author vlads
* @version $Id$
*/
package com.intel.bluetooth.emu;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import com.intel.bluetooth.BluetoothConsts;
import com.intel.bluetooth.DebugLog;
import com.intel.bluetooth.RemoteDeviceHelper;
/**
* Defines Emulator configuration properties.
*
* See properties defined in javax.bluetooth.LocalDevice.getProperty();
*/
public class EmulatorConfiguration implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Name of configuration file or resource.
*
* Defaults to "bluecove.emulator.properties". Can be changed using system property "bluecove.emulator.properties"
*
*/
public static final String CONFIG_FILE_NAME = "bluecove.emulator.properties";
/**
* Allow to define device name. <br/>
* Example
*
* <pre>
* 0B1000000000.deviceName=My Device Server
* # Device is Computer
* 0B1000000000.deviceClass=0x0100
*
* 0B1000000001.deviceName=My Device Client
* # Device is Phone
* 0B1000000001.deviceClass=0x0200
*
* <pre>
*/
public static final String deviceName = "deviceName";
/**
* Allow to define device class.
*
* @see deviceName
*/
public static final String deviceClass = "deviceClass";
/**
* Defaults to '0B1000000000'.
*/
protected long firstDeviceAddress = 0x0B1000000000L;
/**
* Defaults to "EmuDevice".
*
*/
protected String deviceNamePrefix = "EmuDevice";
/**
* Created Devices are initially discoverable.
*/
protected boolean deviceDiscoverable = true;
/**
* Discoverable duration in seconds for LIAC. Defaults to <code>3</code>.
*/
protected int durationLIAC = 3;
/**
* deviceInquiryDuration in seconds, Defaults to <code>11</code>.
*/
protected int deviceInquiryDuration = 11;
/**
* Device Inquiry Duration is random. Defaults to <code>false</code>.
*/
protected boolean deviceInquiryRandomDelay = true;
/**
* Defaults to 8K.
*/
protected int connectionBufferSize = 8 * 1024;
/**
* Defaults to <code>true</code>.
*/
protected boolean linkEncryptionSupported = true;
/**
* stream.flush() will Block sender till client reads all data.
*/
protected boolean senderFlushBlock = false;
/**
* Monitor if client device is active.
*
* RMI timeout is up to 10 minutes. This property enables killing application and recovery faster.
*/
protected int keepAliveSeconds = 5;
private Map<String, String> propertiesMap;
public EmulatorConfiguration() {
propertiesMap = new Hashtable<String, String>();
final String TRUE = "true";
final String FALSE = "false";
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX, "7");
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX, "7");
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN, TRUE);
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN, TRUE);
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY, TRUE);
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE, TRUE);
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX, "255");
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_MASTER_SWITCH, FALSE);
propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_L2CAP_RECEIVEMTU_MAX, "2048");
}
public void loadConfigFile() {
String configName = System.getProperty(CONFIG_FILE_NAME, CONFIG_FILE_NAME);
// Try file to find the file first
File file = new File(configName);
if (file.exists()) {
try {
load(new FileInputStream(file));
} catch (IOException e) {
DebugLog.error("Error loading properties from file " + file.getAbsolutePath(), e);
}
} else {
// find the resource in the classPath
if (!configName.startsWith("/")) {
configName = "/" + configName;
}
InputStream input = this.getClass().getResourceAsStream(configName);
if (input != null) {
try {
load(input);
} catch (IOException e) {
DebugLog.error("Error loading properties from resource " + configName, e);
}
}
}
}
private void load(InputStream input) throws IOException {
Properties values = new Properties();
try {
values.load(input);
} finally {
input.close();
}
for (Map.Entry<Object, Object> me : values.entrySet()) {
Object value = me.getValue();
if (value == null) {
continue;
}
String txt = value.toString().trim();
if (txt.length() == 0) {
continue;
}
propertiesMap.put(me.getKey().toString(), txt);
}
copyPertiesToFields();
}
private void copyPertiesToFields() {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
String value = propertiesMap.get(field.getName());
if (value == null) {
continue;
}
Class<?> type = field.getType();
try {
if (String.class.isAssignableFrom(type)) {
field.set(this, value);
} else if (boolean.class.isAssignableFrom(type)) {
field.setBoolean(this, valueToBoolean(value));
} else if (int.class.isAssignableFrom(type)) {
field.setInt(this, valueToInt(value));
} else if (long.class.isAssignableFrom(type)) {
field.setLong(this, valueToLong(value));
}
} catch (Throwable e) {
DebugLog.error("Error setting property " + field.getName(), e);
}
}
}
private boolean valueToBoolean(String value) {
if (value.equalsIgnoreCase("true") || "1".equals(value)) {
return true;
} else {
return false;
}
}
public static int valueToInt(String value) {
if (value.startsWith("0x")) {
return Integer.parseInt(value.substring(2), 16);
} else {
return Integer.parseInt(value);
}
}
public static long valueToLong(String value) {
if (value.startsWith("0x")) {
return Long.parseLong(value.substring(2), 16);
} else {
return Long.parseLong(value);
}
}
public EmulatorConfiguration clone(long localAddress) {
String namePrefix = RemoteDeviceHelper.getBluetoothAddress(localAddress) + ".";
EmulatorConfiguration deviceConfig = new EmulatorConfiguration();
for (Map.Entry<String, String> me : this.propertiesMap.entrySet()) {
String key = me.getKey();
String value = me.getValue();
deviceConfig.propertiesMap.put(key, value);
if (key.startsWith(namePrefix)) {
deviceConfig.propertiesMap.put(key.substring(namePrefix.length()), value);
}
}
deviceConfig.copyPertiesToFields();
return deviceConfig;
}
public int getDurationLIAC() {
return durationLIAC;
}
public int getDeviceInquiryDuration() {
return deviceInquiryDuration;
}
public boolean isDeviceInquiryRandomDelay() {
return deviceInquiryRandomDelay;
}
public long getFirstDeviceAddress() {
return firstDeviceAddress;
}
/**
* Get specific device property.
*
* If specific not found, return global value.
*
* @param address
* device address
* @param property
* @return value or null
*/
public String getProperty(long address, String property) {
String addressString = RemoteDeviceHelper.getBluetoothAddress(address);
String v = getProperty(addressString + "." + property);
if (v != null) {
return v;
} else {
return getProperty(property);
}
}
public String getProperty(String property) {
return (String) propertiesMap.get(property);
}
public int getIntProperty(String property) {
return Integer.valueOf(getProperty(property)).intValue();
}
public String getDeviceNamePrefix() {
return deviceNamePrefix;
}
public boolean isDeviceDiscoverable() {
return this.deviceDiscoverable;
}
public int getConnectionBufferSize() {
return connectionBufferSize;
}
public boolean isLinkEncryptionSupported() {
return this.linkEncryptionSupported;
}
public int getKeepAliveSeconds() {
return keepAliveSeconds;
}
public boolean isSenderFlushBlock() {
return this.senderFlushBlock;
}
}