diff options
author | Artur Dryomov <artur.dryomov@gmail.com> | 2013-06-25 02:38:01 +0300 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2013-07-25 18:01:48 +0100 |
commit | 858072d9b81402baab9447e13a88d44fc5ba0cd3 (patch) | |
tree | 9e8f2f42bcd7b936cead5fe91dca0f8b59131562 /android | |
parent | a4165981dc35d7b75645585753a08e78c5ee476d (diff) |
Refactor servers finders.
* Add a common ServersFinder interface.
* Rename finders to match their responsibility.
Change-Id: Ib414ce2ba8315558695c80ca47d43d98f64298c9
Diffstat (limited to 'android')
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java (renamed from android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java) | 120 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java | 20 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java | 1 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/Server.java | 7 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java | 226 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/ServersFinder.java | 21 | ||||
-rw-r--r-- | android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java | 198 |
7 files changed, 300 insertions, 293 deletions
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java index 4ed99a13aa8f..93a1f8453872 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java @@ -8,8 +8,9 @@ */ package org.libreoffice.impressremote.communication; -import java.util.Collection; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import android.bluetooth.BluetoothAdapter; @@ -23,104 +24,84 @@ import android.support.v4.content.LocalBroadcastManager; import org.libreoffice.impressremote.communication.Server.Protocol; -public class BluetoothFinder extends BroadcastReceiver { - // TODO: add removal of cached items +public class BluetoothServersFinder extends BroadcastReceiver implements ServersFinder, Runnable { + private static final int SEARCH_DELAY_IN_MILLISECONDS = 1000 * 10; + private final Context mContext; private final Map<String, Server> mServers; - public BluetoothFinder(Context aContext) { + public BluetoothServersFinder(Context aContext) { mContext = aContext; mServers = new HashMap<String, Server>(); } + @Override public void startSearch() { if (!isBluetoothAvailable()) { return; } - BluetoothAdapter.getDefaultAdapter().startDiscovery(); + if (BluetoothAdapter.getDefaultAdapter().isDiscovering()) { + return; + } + + setUpSearchResultsReceiver(); - registerSearchResultsReceiver(); + BluetoothAdapter.getDefaultAdapter().startDiscovery(); } private boolean isBluetoothAvailable() { return BluetoothAdapter.getDefaultAdapter() != null; } - private void registerSearchResultsReceiver() { - IntentFilter aIntentFilter = new IntentFilter( + private void setUpSearchResultsReceiver() { + IntentFilter aSearchResultsFilter = new IntentFilter( BluetoothDevice.ACTION_FOUND); - aIntentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); - aIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); - - mContext.registerReceiver(this, aIntentFilter); - } - - public void stopSearch() { - if (!isBluetoothAvailable()) { - return; - } - - BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); - - unregisterSearchResultsReceiver(); - } + aSearchResultsFilter + .addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); - private void unregisterSearchResultsReceiver() { - mContext.unregisterReceiver(this); - } - - public Collection<Server> getServers() { - return mServers.values(); + mContext.registerReceiver(this, aSearchResultsFilter); } @Override public void onReceive(Context aContext, Intent aIntent) { - if (aIntent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { - BluetoothDevice aBluetoothDevice = (BluetoothDevice) aIntent - .getExtras().get(BluetoothDevice.EXTRA_DEVICE); - - if (aBluetoothDevice == null) { - return; - } + if (BluetoothDevice.ACTION_FOUND.equals(aIntent.getAction())) { + BluetoothDevice aBluetoothDevice = aIntent + .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - createServer(aBluetoothDevice); + addServer(buildServer(aBluetoothDevice)); callUpdatingServersList(); return; } - if (aIntent.getAction() - .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { - startDiscoveryDelayed(); + if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED + .equals(aIntent.getAction())) { - return; - } - - if (aIntent.getAction() - .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { startDiscoveryDelayed(); } } - private void createServer(BluetoothDevice aBluetoothDevice) { + private void addServer(Server aServer) { + mServers.put(aServer.getAddress(), aServer); + } + + private Server buildServer(BluetoothDevice aBluetoothDevice) { String aServerAddress = aBluetoothDevice.getAddress(); String aServerName = aBluetoothDevice.getName(); - Server aServer = new Server(Protocol.BLUETOOTH, aServerAddress, - aServerName, System.currentTimeMillis()); - mServers.put(aServerAddress, aServer); + return new Server(Protocol.BLUETOOTH, aServerAddress, aServerName); } private void callUpdatingServersList() { - Intent aServersListChangedIntent = new Intent( + Intent aServersListUpdatedIntent = new Intent( CommunicationService.MSG_SERVERLIST_CHANGED); LocalBroadcastManager.getInstance(mContext) - .sendBroadcast(aServersListChangedIntent); + .sendBroadcast(aServersListUpdatedIntent); } private void startDiscoveryDelayed() { @@ -133,12 +114,37 @@ public class BluetoothFinder extends BroadcastReceiver { } Handler aHandler = new Handler(); - aHandler.postDelayed(new Runnable() { - @Override - public void run() { - // Looping, huh? - } - }, 1000 * 15); + aHandler.postDelayed(this, SEARCH_DELAY_IN_MILLISECONDS); + } + + @Override + public void run() { + BluetoothAdapter.getDefaultAdapter().startDiscovery(); + } + + @Override + public void stopSearch() { + if (!isBluetoothAvailable()) { + return; + } + + tearDownSearchResultsReceiver(); + + BluetoothAdapter.getDefaultAdapter().cancelDiscovery(); + } + + private void tearDownSearchResultsReceiver() { + try { + mContext.unregisterReceiver(this); + } catch (IllegalArgumentException e) { + // Receiver not registered. + // Fixed in Honeycomb: Android’s issue #6191. + } + } + + @Override + public List<Server> getServers() { + return new ArrayList<Server>(mServers.values()); } } diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java index d87ef6ff96c5..273362c11d26 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java @@ -68,8 +68,8 @@ public class CommunicationService extends Service implements Runnable { private final Receiver mReceiver = new Receiver(this); - private final ServerFinder mNetworkFinder = new ServerFinder(this); - private final BluetoothFinder mBluetoothFinder = new BluetoothFinder(this); + private final ServersFinder mTcpServersFinder = new TcpServersFinder(this); + private final ServersFinder mBluetoothServersFinder = new BluetoothServersFinder(this); private Thread mThread = null; @@ -180,19 +180,19 @@ public class CommunicationService extends Service implements Runnable { .getDefaultSharedPreferences(this); boolean bEnableWifi = aPref.getBoolean("option_enablewifi", false); if (bEnableWifi) - mNetworkFinder.startSearch(); + mTcpServersFinder.startSearch(); BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter(); if (aAdapter != null) { mBluetoothPreviouslyEnabled = aAdapter.isEnabled(); if (!mBluetoothPreviouslyEnabled) aAdapter.enable(); - mBluetoothFinder.startSearch(); + mBluetoothServersFinder.startSearch(); } } public void stopSearch() { - mNetworkFinder.stopSearch(); - mBluetoothFinder.stopSearch(); + mTcpServersFinder.stopSearch(); + mBluetoothServersFinder.stopSearch(); BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter(); if (aAdapter != null) { if (!mBluetoothPreviouslyEnabled) { @@ -204,8 +204,8 @@ public class CommunicationService extends Service implements Runnable { public void connectTo(Server aServer) { synchronized (mConnectionVariableMutex) { if (mState == State.SEARCHING) { - mNetworkFinder.stopSearch(); - mBluetoothFinder.stopSearch(); + mTcpServersFinder.stopSearch(); + mBluetoothServersFinder.stopSearch(); mState = State.DISCONNECTED; } mServerDesired = aServer; @@ -261,8 +261,8 @@ public class CommunicationService extends Service implements Runnable { public List<Server> getServers() { List<Server> aServers = new ArrayList<Server>(); - aServers.addAll(mNetworkFinder.getServers()); - aServers.addAll(mBluetoothFinder.getServers()); + aServers.addAll(mTcpServersFinder.getServers()); + aServers.addAll(mBluetoothServersFinder.getServers()); aServers.addAll(mManualServers.values()); return aServers; diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java index 6081669b89c8..6f40e5452f6c 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java @@ -40,6 +40,7 @@ final class Protocol { public static final String PAIRED = "LO_SERVER_SERVER_PAIRED"; public static final String VALIDATING = "LO_SERVER_VALIDATING_PIN"; + public static final String ADVERTISE = "LOREMOTE_ADVERTISE"; public static final String SLIDESHOW_STARTED = "slideshow_started"; public static final String SLIDESHOW_FINISHED = "slideshow_finished"; diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java index dd2bc5be9c7f..7edf63c50af2 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java @@ -36,6 +36,13 @@ public class Server implements Parcelable { this.mTimeDiscovered = aTimeDiscovered; } + protected Server(Protocol aProtocol, String aAddress, String aName) { + this.mProtocol = aProtocol; + this.mAddress = aAddress; + this.mName = aName; + this.mTimeDiscovered = System.currentTimeMillis(); + } + public Protocol getProtocol() { return mProtocol; } diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java deleted file mode 100644 index 9ac70376e1a6..000000000000 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.libreoffice.impressremote.communication; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import android.content.Context; -import android.content.Intent; -import android.support.v4.content.LocalBroadcastManager; - -public class ServerFinder implements Runnable { - private final Context mContext; - - private DatagramSocket mSocket = null; - private Thread mListenerThread; - private boolean mFinishRequested; - - private final Map<String, Server> mServers; - - public ServerFinder(Context aContext) { - mContext = aContext; - - mSocket = null; - mListenerThread = null; - mFinishRequested = false; - - mServers = new HashMap<String, Server>(); - } - - public void startSearch() { - if (mSocket != null) { - return; - } - - mFinishRequested = false; - - if (mListenerThread == null) { - mListenerThread = new Thread(this); - } - - mListenerThread.start(); - } - - @Override - public void run() { - addLocalServerForEmulator(); - - long aStartSearchTime = 0; - - setUpSearchSocket(); - - while (!mFinishRequested) { - if (System - .currentTimeMillis() - aStartSearchTime > 1000 * 15) { - sendSearchCommand(); - - aStartSearchTime = System.currentTimeMillis(); - - removeStaleServers(); - } - - listenForServer(); - } - } - - /** - * Check whether we are on an emulator and add it's host to the list of - * servers if so (although we do not know whether libo is running on - * the host). - */ - private void addLocalServerForEmulator() { - if (!isLocalServerForEmulatorReachable()) { - return; - } - - Server aServer = new Server(Server.Protocol.NETWORK, - Protocol.Addresses.SERVER_LOCAL_FOR_EMULATOR, "Android Emulator", - 0); - - mServers.put(aServer.getAddress(), aServer); - - callUpdatingServersList(); - } - - private boolean isLocalServerForEmulatorReachable() { - try { - InetAddress aLocalServerAddress = InetAddress - .getByName(Protocol.Addresses.SERVER_LOCAL_FOR_EMULATOR); - - return aLocalServerAddress.isReachable(100); - } catch (UnknownHostException e) { - return false; - } catch (IOException e) { - return false; - } - } - - private void callUpdatingServersList() { - Intent aIntent = new Intent( - CommunicationService.MSG_SERVERLIST_CHANGED); - LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent); - } - - private void setUpSearchSocket() { - try { - mSocket = new DatagramSocket(); - mSocket.setSoTimeout(1000 * 10); - } catch (SocketException e) { - throw new RuntimeException("Unable to open search socket."); - } - } - - private void sendSearchCommand() { - try { - mSocket.send(buildSearchPacket()); - } catch (IOException e) { - throw new RuntimeException("Unable to send search packet."); - } - } - - private DatagramPacket buildSearchPacket() { - try { - String aSearchCommand = Protocol.Commands - .prepareCommand(Protocol.Commands.SEARCH_SERVERS); - - DatagramPacket aSearchPacket = new DatagramPacket( - aSearchCommand.getBytes(), aSearchCommand.length()); - aSearchPacket.setAddress( - InetAddress.getByName(Protocol.Addresses.SERVER_SEARCH)); - aSearchPacket.setPort(Protocol.Ports.SERVER_SEARCH); - - return aSearchPacket; - } catch (UnknownHostException e) { - throw new RuntimeException("Unable to find address to search."); - } - } - - private void removeStaleServers() { - for (Server aServer : mServers.values()) { - if (aServer.mNoTimeout) { - continue; - } - - if (System.currentTimeMillis() - - aServer - .getTimeDiscovered() > 60 * 1000) { - mServers - .remove(aServer.getAddress()); - callUpdatingServersList(); - } - } - } - - private void listenForServer() { - byte[] aBuffer = new byte[500]; - DatagramPacket aPacket = new DatagramPacket(aBuffer, aBuffer.length); - - try { - String aCommand = null; - String aName = null; - mSocket.receive(aPacket); - int i; - for (i = 0; i < aBuffer.length; i++) { - if (aPacket.getData()[i] == '\n') { - aCommand = new String(aPacket.getData(), 0, i, - Protocol.CHARSET); - break; - } - } - if (i == aBuffer.length || !"LOREMOTE_ADVERTISE".equals(aCommand)) { - return; - } - for (int j = i + 1; j < aBuffer.length; j++) { - if (aPacket.getData()[j] == '\n') { - aName = new String(aPacket.getData(), i + 1, j - (i + 1), - Protocol.CHARSET); - break; - } - } - if (aName == null) { - return; - } - Server aServer = new Server(Server.Protocol.NETWORK, aPacket - .getAddress().getHostAddress(), aName, - System.currentTimeMillis()); - mServers.put(aServer.getAddress(), aServer); - - callUpdatingServersList(); - } catch (SocketTimeoutException e) { - // Ignore -- we want to timeout to enable checking whether we - // should stop listening periodically - } catch (IOException e) { - } - - } - - public void stopSearch() { - if (mListenerThread == null) { - return; - } - - mFinishRequested = true; - mListenerThread = null; - } - - public Collection<Server> getServers() { - return mServers.values(); - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersFinder.java new file mode 100644 index 000000000000..aba82abbb466 --- /dev/null +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersFinder.java @@ -0,0 +1,21 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.libreoffice.impressremote.communication; + +import java.util.List; + +public interface ServersFinder { + public void startSearch(); + + public void stopSearch(); + + public List<Server> getServers(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java new file mode 100644 index 000000000000..53a14c38d5c2 --- /dev/null +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java @@ -0,0 +1,198 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.libreoffice.impressremote.communication; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; + +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; + +public class TcpServersFinder implements ServersFinder, Runnable { + private static final int SEARCH_DELAY_IN_MILLISECONDS = 1000 * 10; + private static final int BLOCKING_TIMEOUT_IN_MILLISECONDS = 1000 * 10; + + private static final int SEARCH_RESULT_BUFFER_SIZE = 1024; + + private final Context mContext; + + private final Map<String, Server> mServers; + + private DatagramSocket mSearchSocket; + private Thread mSearchResultsListenerThread; + private boolean mSearchStopRequested; + + public TcpServersFinder(Context aContext) { + mContext = aContext; + + mServers = new HashMap<String, Server>(); + } + + @Override + public void startSearch() { + if (mSearchResultsListenerThread != null) { + return; + } + + mSearchStopRequested = false; + + mSearchResultsListenerThread = new Thread(this); + mSearchResultsListenerThread.start(); + } + + @Override + public void run() { + setUpSearchSocket(); + + while (!mSearchStopRequested) { + sendSearchCommand(); + + listenForSearchResults(); + + setUpSearchDelay(); + } + + tearDownSearchSocket(); + } + + private void setUpSearchSocket() { + try { + mSearchSocket = new DatagramSocket(); + mSearchSocket.setSoTimeout(BLOCKING_TIMEOUT_IN_MILLISECONDS); + } catch (SocketException e) { + throw new RuntimeException("Unable to open search socket."); + } + } + + private void sendSearchCommand() { + try { + mSearchSocket.send(buildSearchPacket()); + } catch (IOException e) { + throw new RuntimeException("Unable to send search packet."); + } + } + + private DatagramPacket buildSearchPacket() { + try { + String aSearchCommand = Protocol.Commands + .prepareCommand(Protocol.Commands.SEARCH_SERVERS); + + DatagramPacket aSearchPacket = new DatagramPacket( + aSearchCommand.getBytes(), aSearchCommand.length()); + aSearchPacket.setAddress( + InetAddress.getByName(Protocol.Addresses.SERVER_SEARCH)); + aSearchPacket.setPort(Protocol.Ports.SERVER_SEARCH); + + return aSearchPacket; + } catch (UnknownHostException e) { + throw new RuntimeException("Unable to find address to search."); + } + } + + private void listenForSearchResults() { + DatagramPacket aSearchResultPacket = buildSearchResultPacket(); + + String aSearchResult = receiveSearchResult(aSearchResultPacket); + + if (TextUtils.isEmpty(aSearchResult)) { + return; + } + + Scanner aSearchResultScanner = new Scanner(aSearchResult); + + String aMessage = aSearchResultScanner.nextLine(); + + if (!Protocol.Messages.ADVERTISE.equals(aMessage)) { + return; + } + + String aFoundServerHostname = aSearchResultScanner.nextLine(); + + Server aFoundServer = new Server(Server.Protocol.NETWORK, + aSearchResultPacket.getAddress().getHostAddress(), + aFoundServerHostname); + + addServer(aFoundServer); + + callUpdatingServersList(); + } + + private DatagramPacket buildSearchResultPacket() { + byte[] aSearchResultBuffer = new byte[SEARCH_RESULT_BUFFER_SIZE]; + + return new DatagramPacket( + aSearchResultBuffer, aSearchResultBuffer.length); + } + + private String receiveSearchResult(DatagramPacket aSearchResultPacket) { + try { + mSearchSocket.receive(aSearchResultPacket); + + return new String(aSearchResultPacket.getData(), Protocol.CHARSET); + } catch (SocketTimeoutException e) { + return ""; + } catch (IOException e) { + throw new RuntimeException("Unable to receive search result."); + } + } + + private void addServer(Server aServer) { + mServers.put(aServer.getAddress(), aServer); + } + + private void callUpdatingServersList() { + Intent aServersListUpdatedIntent = new Intent( + CommunicationService.MSG_SERVERLIST_CHANGED); + + LocalBroadcastManager.getInstance(mContext) + .sendBroadcast(aServersListUpdatedIntent); + } + + private void setUpSearchDelay() { + try { + Thread.sleep(SEARCH_DELAY_IN_MILLISECONDS); + } catch (InterruptedException e) { + mSearchStopRequested = true; + } + } + + private void tearDownSearchSocket() { + mSearchSocket.close(); + } + + @Override + public void stopSearch() { + if (mSearchResultsListenerThread == null) { + return; + } + + mSearchStopRequested = true; + + mSearchResultsListenerThread = null; + } + + @Override + public List<Server> getServers() { + return new ArrayList<Server>(mServers.values()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |