View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2008 Michael Lifshits
4    *  Copyright (C) 2008 Vlad Skarzhevskyy
5    *
6    *  Licensed to the Apache Software Foundation (ASF) under one
7    *  or more contributor license agreements.  See the NOTICE file
8    *  distributed with this work for additional information
9    *  regarding copyright ownership.  The ASF licenses this file
10   *  to you under the Apache License, Version 2.0 (the
11   *  "License"); you may not use this file except in compliance
12   *  with the License.  You may obtain a copy of the License at
13   *
14   *    http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing,
17   *  software distributed under the License is distributed on an
18   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   *  KIND, either express or implied.  See the License for the
20   *  specific language governing permissions and limitations
21   *  under the License.
22   *
23   *  @author vlads
24   *  @version $Id: EmulatorConfiguration.java 2642 2008-12-23 00:21:23Z skarzhevskyy $
25   */
26  package com.intel.bluetooth.emu;
27  
28  import java.io.File;
29  import java.io.FileInputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.Serializable;
33  import java.lang.reflect.Field;
34  import java.lang.reflect.Modifier;
35  import java.util.Hashtable;
36  import java.util.Map;
37  import java.util.Properties;
38  
39  import com.intel.bluetooth.BluetoothConsts;
40  import com.intel.bluetooth.DebugLog;
41  import com.intel.bluetooth.RemoteDeviceHelper;
42  
43  /**
44   * Defines Emulator configuration properties.
45   * 
46   * See properties defined in javax.bluetooth.LocalDevice.getProperty();
47   */
48  public class EmulatorConfiguration implements Serializable {
49  
50  	private static final long serialVersionUID = 1L;
51  
52  	/**
53  	 * Name of configuration file or resource.
54  	 * 
55  	 * Defaults to "bluecove.emulator.properties". Can be changed using system property "bluecove.emulator.properties"
56  	 * 
57  	 */
58  	public static final String CONFIG_FILE_NAME = "bluecove.emulator.properties";
59  
60  	/**
61  	 * Allow to define device name. <br/>
62  	 * Example
63  	 * 
64  	 * <pre>
65  	 * 0B1000000000.deviceName=My Device Server
66  	 * # Device is Computer
67  	 * 0B1000000000.deviceClass=0x0100
68  	 * 
69  	 * 0B1000000001.deviceName=My Device Client
70  	 * # Device is Phone
71  	 * 0B1000000001.deviceClass=0x0200
72  	 * 
73  	 * <pre>
74  	 */
75  	public static final String deviceName = "deviceName";
76  
77  	/**
78  	 * Allow to define device class.
79  	 * 
80  	 * @see deviceName
81  	 */
82  	public static final String deviceClass = "deviceClass";
83  
84  	/**
85  	 * Defaults to '0B1000000000'.
86  	 */
87  	protected long firstDeviceAddress = 0x0B1000000000L;
88  
89  	/**
90  	 * Defaults to "EmuDevice".
91  	 * 
92  	 */
93  	protected String deviceNamePrefix = "EmuDevice";
94  
95  	/**
96  	 * Created Devices are initially discoverable.
97  	 */
98  	protected boolean deviceDiscoverable = true;
99  
100 	/**
101 	 * Discoverable duration in seconds for LIAC. Defaults to <code>3</code>.
102 	 */
103 	protected int durationLIAC = 3;
104 
105 	/**
106 	 * deviceInquiryDuration in seconds, Defaults to <code>11</code>.
107 	 */
108 	protected int deviceInquiryDuration = 11;
109 
110 	/**
111 	 * Device Inquiry Duration is random. Defaults to <code>false</code>.
112 	 */
113 	protected boolean deviceInquiryRandomDelay = true;
114 
115 	/**
116 	 * Defaults to 8K.
117 	 */
118 	protected int connectionBufferSize = 8 * 1024;
119 
120 	/**
121 	 * Defaults to <code>true</code>.
122 	 */
123 	protected boolean linkEncryptionSupported = true;
124 
125 	/**
126 	 * stream.flush() will Block sender till client reads all data.
127 	 */
128 	protected boolean senderFlushBlock = false;
129 
130 	/**
131 	 * Monitor if client device is active.
132 	 * 
133 	 * RMI timeout is up to 10 minutes. This property enables killing application and recovery faster.
134 	 */
135 	protected int keepAliveSeconds = 5;
136 
137 	private Map<String, String> propertiesMap;
138 
139 	public EmulatorConfiguration() {
140 		propertiesMap = new Hashtable<String, String>();
141 		final String TRUE = "true";
142 		final String FALSE = "false";
143 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX, "7");
144 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX, "7");
145 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN, TRUE);
146 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN, TRUE);
147 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY, TRUE);
148 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE, TRUE);
149 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX, "255");
150 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_MASTER_SWITCH, FALSE);
151 		propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_L2CAP_RECEIVEMTU_MAX, "2048");
152 	}
153 
154 	public void loadConfigFile() {
155 		String configName = System.getProperty(CONFIG_FILE_NAME, CONFIG_FILE_NAME);
156 		// Try file to find the file first
157 		File file = new File(configName);
158 		if (file.exists()) {
159 			try {
160 				load(new FileInputStream(file));
161 			} catch (IOException e) {
162 				DebugLog.error("Error loading properties from file " + file.getAbsolutePath(), e);
163 			}
164 		} else {
165 			// find the resource in the classPath
166 			if (!configName.startsWith("/")) {
167 				configName = "/" + configName;
168 			}
169 			InputStream input = this.getClass().getResourceAsStream(configName);
170 			if (input != null) {
171 				try {
172 					load(input);
173 				} catch (IOException e) {
174 					DebugLog.error("Error loading properties from resource " + configName, e);
175 				}
176 			}
177 		}
178 	}
179 
180 	private void load(InputStream input) throws IOException {
181 		Properties values = new Properties();
182 		try {
183 			values.load(input);
184 		} finally {
185 			input.close();
186 		}
187 		for (Map.Entry<Object, Object> me : values.entrySet()) {
188 			Object value = me.getValue();
189 			if (value == null) {
190 				continue;
191 			}
192 			String txt = value.toString().trim();
193 			if (txt.length() == 0) {
194 				continue;
195 			}
196 			propertiesMap.put(me.getKey().toString(), txt);
197 		}
198 		copyPertiesToFields();
199 	}
200 
201 	private void copyPertiesToFields() {
202 		Field[] fields = this.getClass().getDeclaredFields();
203 		for (Field field : fields) {
204 			if (Modifier.isStatic(field.getModifiers())) {
205 				continue;
206 			}
207 			String value = propertiesMap.get(field.getName());
208 			if (value == null) {
209 				continue;
210 			}
211 			Class<?> type = field.getType();
212 			try {
213 				if (String.class.isAssignableFrom(type)) {
214 					field.set(this, value);
215 				} else if (boolean.class.isAssignableFrom(type)) {
216 					field.setBoolean(this, valueToBoolean(value));
217 				} else if (int.class.isAssignableFrom(type)) {
218 					field.setInt(this, valueToInt(value));
219 				} else if (long.class.isAssignableFrom(type)) {
220 					field.setLong(this, valueToLong(value));
221 				}
222 			} catch (Throwable e) {
223 				DebugLog.error("Error setting property " + field.getName(), e);
224 			}
225 		}
226 	}
227 
228 	private boolean valueToBoolean(String value) {
229 		if (value.equalsIgnoreCase("true") || "1".equals(value)) {
230 			return true;
231 		} else {
232 			return false;
233 		}
234 	}
235 
236 	public static int valueToInt(String value) {
237 		if (value.startsWith("0x")) {
238 			return Integer.parseInt(value.substring(2), 16);
239 		} else {
240 			return Integer.parseInt(value);
241 		}
242 	}
243 
244 	public static long valueToLong(String value) {
245 		if (value.startsWith("0x")) {
246 			return Long.parseLong(value.substring(2), 16);
247 		} else {
248 			return Long.parseLong(value);
249 		}
250 	}
251 
252 	public EmulatorConfiguration clone(long localAddress) {
253 		String namePrefix = RemoteDeviceHelper.getBluetoothAddress(localAddress) + ".";
254 		EmulatorConfiguration deviceConfig = new EmulatorConfiguration();
255 		for (Map.Entry<String, String> me : this.propertiesMap.entrySet()) {
256 			String key = me.getKey();
257 			String value = me.getValue();
258 			deviceConfig.propertiesMap.put(key, value);
259 			if (key.startsWith(namePrefix)) {
260 				deviceConfig.propertiesMap.put(key.substring(namePrefix.length()), value);
261 			}
262 		}
263 		deviceConfig.copyPertiesToFields();
264 		return deviceConfig;
265 	}
266 
267 	public int getDurationLIAC() {
268 		return durationLIAC;
269 	}
270 
271 	public int getDeviceInquiryDuration() {
272 		return deviceInquiryDuration;
273 	}
274 
275 	public boolean isDeviceInquiryRandomDelay() {
276 		return deviceInquiryRandomDelay;
277 	}
278 
279 	public long getFirstDeviceAddress() {
280 		return firstDeviceAddress;
281 	}
282 
283 	/**
284 	 * Get specific device property.
285 	 * 
286 	 * If specific not found, return global value.
287 	 * 
288 	 * @param address
289 	 *            device address
290 	 * @param property
291 	 * @return value or null
292 	 */
293 	public String getProperty(long address, String property) {
294 		String addressString = RemoteDeviceHelper.getBluetoothAddress(address);
295 		String v = getProperty(addressString + "." + property);
296 		if (v != null) {
297 			return v;
298 		} else {
299 			return getProperty(property);
300 		}
301 	}
302 
303 	public String getProperty(String property) {
304 		return (String) propertiesMap.get(property);
305 	}
306 
307 	public int getIntProperty(String property) {
308 		return Integer.valueOf(getProperty(property)).intValue();
309 	}
310 
311 	public String getDeviceNamePrefix() {
312 		return deviceNamePrefix;
313 	}
314 
315 	public boolean isDeviceDiscoverable() {
316 		return this.deviceDiscoverable;
317 	}
318 
319 	public int getConnectionBufferSize() {
320 		return connectionBufferSize;
321 	}
322 
323 	public boolean isLinkEncryptionSupported() {
324 		return this.linkEncryptionSupported;
325 	}
326 
327 	public int getKeepAliveSeconds() {
328 		return keepAliveSeconds;
329 	}
330 
331 	public boolean isSenderFlushBlock() {
332 		return this.senderFlushBlock;
333 	}
334 }