001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) FIRST 2017-2018. All Rights Reserved. */ 003/* Open Source Software - may be modified and shared by FRC teams. The code */ 004/* must be accompanied by the FIRST BSD license file in the root directory of */ 005/* the project. */ 006/*----------------------------------------------------------------------------*/ 007 008package edu.wpi.first.wpilibj.networktables; 009 010import edu.wpi.first.networktables.ConnectionInfo; 011import edu.wpi.first.networktables.ConnectionNotification; 012import edu.wpi.first.networktables.EntryInfo; 013import edu.wpi.first.networktables.EntryNotification; 014import edu.wpi.first.networktables.NetworkTableEntry; 015import edu.wpi.first.networktables.NetworkTableInstance; 016import edu.wpi.first.networktables.NetworkTableType; 017import edu.wpi.first.networktables.NetworkTableValue; 018import edu.wpi.first.networktables.NetworkTablesJNI; 019import edu.wpi.first.networktables.PersistentException; 020import edu.wpi.first.wpilibj.tables.IRemote; 021import edu.wpi.first.wpilibj.tables.IRemoteConnectionListener; 022import edu.wpi.first.wpilibj.tables.ITable; 023import edu.wpi.first.wpilibj.tables.ITableListener; 024import java.nio.ByteBuffer; 025import java.util.ArrayList; 026import java.util.HashMap; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Objects; 030import java.util.Set; 031import java.util.concurrent.ConcurrentHashMap; 032import java.util.concurrent.ConcurrentMap; 033import java.util.function.Consumer; 034 035/** 036 * A network table that knows its subtable path. 037 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable} instead. 038 */ 039@Deprecated 040public class NetworkTable implements ITable, IRemote { 041 /** 042 * The path separator for sub-tables and keys 043 * 044 */ 045 public static final char PATH_SEPARATOR = '/'; 046 /** 047 * The default port that network tables operates on 048 */ 049 public static final int DEFAULT_PORT = 1735; 050 051 private static boolean client = false; 052 private static boolean enableDS = true; 053 private static boolean running = false; 054 private static int port = DEFAULT_PORT; 055 private static String persistentFilename = "networktables.ini"; 056 057 private synchronized static void checkInit() { 058 if (running) 059 throw new IllegalStateException( 060 "Network tables has already been initialized"); 061 } 062 063 /** 064 * initializes network tables 065 * @deprecated Use {@link NetworkTableInstance#startServer()} or 066 * {@link NetworkTableInstance#startClient()} instead. 067 */ 068 @Deprecated 069 public synchronized static void initialize() { 070 if (running) 071 shutdown(); 072 NetworkTableInstance inst = NetworkTableInstance.getDefault(); 073 if (client) { 074 inst.startClient(); 075 if (enableDS) 076 inst.startDSClient(port); 077 } else 078 inst.startServer(persistentFilename, "", port); 079 running = true; 080 } 081 082 /** 083 * shuts down network tables 084 * @deprecated Use {@link NetworkTableInstance#stopServer()} or 085 * {@link NetworkTableInstance#stopClient()} instead. 086 */ 087 @Deprecated 088 public synchronized static void shutdown() { 089 if (!running) 090 return; 091 NetworkTableInstance inst = NetworkTableInstance.getDefault(); 092 if (client) { 093 inst.stopDSClient(); 094 inst.stopClient(); 095 } else 096 inst.stopServer(); 097 running = false; 098 } 099 100 /** 101 * set that network tables should be a server 102 * This must be called before initialize or getTable 103 * @deprecated Use {@link NetworkTableInstance#startServer()} instead. 104 */ 105 @Deprecated 106 public synchronized static void setServerMode() { 107 if (!client) 108 return; 109 checkInit(); 110 client = false; 111 } 112 113 /** 114 * set that network tables should be a client 115 * This must be called before initialize or getTable 116 * @deprecated Use {@link NetworkTableInstance#startClient()} instead. 117 */ 118 @Deprecated 119 public synchronized static void setClientMode() { 120 if (client) 121 return; 122 checkInit(); 123 client = true; 124 } 125 126 /** 127 * set the team the robot is configured for (this will set the mdns address that 128 * network tables will connect to in client mode) 129 * This must be called before initialize or getTable 130 * @param team the team number 131 * @deprecated Use {@link NetworkTableInstance#setServerTeam(int)} or 132 * {@link NetworkTableInstance#startClientTeam(int)} instead. 133 */ 134 @Deprecated 135 public synchronized static void setTeam(int team) { 136 NetworkTableInstance inst = NetworkTableInstance.getDefault(); 137 inst.setServerTeam(team, port); 138 if (enableDS) 139 inst.startDSClient(port); 140 } 141 142 /** 143 * @param address the address that network tables will connect to in client 144 * mode 145 * @deprecated Use {@link NetworkTableInstance#setServer(String)} or 146 * {@link NetworkTableInstance#startClient(String)} instead. 147 */ 148 @Deprecated 149 public synchronized static void setIPAddress(final String address) { 150 String[] addresses = new String[1]; 151 addresses[0] = address; 152 setIPAddress(addresses); 153 } 154 155 /** 156 * @param addresses the adresses that network tables will connect to in 157 * client mode (in round robin order) 158 * @deprecated Use {@link NetworkTableInstance#setServer(String[])} or 159 * {@link NetworkTableInstance#startClient(String[])} instead. 160 */ 161 @Deprecated 162 public synchronized static void setIPAddress(final String[] addresses) { 163 NetworkTableInstance inst = NetworkTableInstance.getDefault(); 164 inst.setServer(addresses, port); 165 166 // Stop the DS client if we're explicitly connecting to localhost 167 if (addresses.length > 0 && 168 (addresses[0].equals("localhost") || addresses[0].equals("127.0.0.1"))) 169 inst.stopDSClient(); 170 else if (enableDS) 171 inst.startDSClient(port); 172 } 173 174 /** 175 * Set the port number that network tables will connect to in client 176 * mode or listen to in server mode. 177 * @param aport the port number 178 * @deprecated Use the appropriate parameters to 179 * {@link NetworkTableInstance#setServer(String, int)}, 180 * {@link NetworkTableInstance#startClient(String, int)}, 181 * {@link NetworkTableInstance#startServer(String, String, int)}, and 182 * {@link NetworkTableInstance#startDSClient(int)} instead. 183 */ 184 @Deprecated 185 public synchronized static void setPort(int aport) { 186 if (port == aport) 187 return; 188 checkInit(); 189 port = aport; 190 } 191 192 /** 193 * Enable requesting the server address from the Driver Station. 194 * @param enabled whether to enable the connection to the local DS 195 * @deprecated Use {@link NetworkTableInstance#startDSClient()} and 196 * {@link NetworkTableInstance#stopDSClient()} instead. 197 */ 198 @Deprecated 199 public synchronized static void setDSClientEnabled(boolean enabled) { 200 NetworkTableInstance inst = NetworkTableInstance.getDefault(); 201 enableDS = enabled; 202 if (enableDS) 203 inst.startDSClient(port); 204 else 205 inst.stopDSClient(); 206 } 207 208 /** 209 * Sets the persistent filename. 210 * @param filename the filename that the network tables server uses for 211 * automatic loading and saving of persistent values 212 * @deprecated Use the appropriate parameter to 213 * {@link NetworkTableInstance#startServer()} instead. 214 */ 215 @Deprecated 216 public synchronized static void setPersistentFilename(final String filename) { 217 if (persistentFilename.equals(filename)) 218 return; 219 checkInit(); 220 persistentFilename = filename; 221 } 222 223 /** 224 * Sets the network identity. 225 * This is provided in the connection info on the remote end. 226 * @param name identity 227 * @deprecated Use {@link NetworkTableInstance#setNetworkIdentity(String)} 228 * instead. 229 */ 230 @Deprecated 231 public static void setNetworkIdentity(String name) { 232 NetworkTableInstance.getDefault().setNetworkIdentity(name); 233 } 234 235 public static boolean[] toNative(Boolean[] arr) { 236 boolean[] out = new boolean[arr.length]; 237 for (int i = 0; i < arr.length; i++) 238 out[i] = arr[i]; 239 return out; 240 } 241 242 public static double[] toNative(Number[] arr) { 243 double[] out = new double[arr.length]; 244 for (int i = 0; i < arr.length; i++) 245 out[i] = arr[i].doubleValue(); 246 return out; 247 } 248 249 public static Boolean[] fromNative(boolean[] arr) { 250 Boolean[] out = new Boolean[arr.length]; 251 for (int i = 0; i < arr.length; i++) 252 out[i] = arr[i]; 253 return out; 254 } 255 256 public static Double[] fromNative(double[] arr) { 257 Double[] out = new Double[arr.length]; 258 for (int i = 0; i < arr.length; i++) 259 out[i] = arr[i]; 260 return out; 261 } 262 263 /** 264 * Gets the table with the specified key. If the table does not exist, a new 265 * table will be created.<br> 266 * This will automatically initialize network tables if it has not been 267 * already 268 * 269 * @deprecated Use {@link NetworkTableInstance#getTable(String)} instead. 270 * 271 * @param key the key name 272 * @return the network table requested 273 */ 274 @Deprecated 275 public synchronized static NetworkTable getTable(String key) { 276 if (!running) 277 initialize(); 278 String theKey; 279 if (key.isEmpty() || key.equals("/")) { 280 theKey = ""; 281 } else if (key.charAt(0) == NetworkTable.PATH_SEPARATOR) { 282 theKey = key; 283 } else { 284 theKey = NetworkTable.PATH_SEPARATOR + key; 285 } 286 return new NetworkTable(NetworkTableInstance.getDefault(), theKey); 287 } 288 289 private final String path; 290 private final String pathWithSep; 291 private final NetworkTableInstance inst; 292 293 NetworkTable(NetworkTableInstance inst, String path) { 294 this.path = path; 295 this.pathWithSep = path + PATH_SEPARATOR; 296 this.inst = inst; 297 } 298 299 public String toString() { return "NetworkTable: " + path; } 300 301 private final ConcurrentMap<String, NetworkTableEntry> entries = new ConcurrentHashMap<String, NetworkTableEntry>(); 302 303 /** 304 * Gets the entry for a subkey. 305 * @param key the key name 306 * @return Network table entry. 307 */ 308 private NetworkTableEntry getEntry(String key) { 309 NetworkTableEntry entry = entries.get(key); 310 if (entry == null) { 311 entry = inst.getEntry(pathWithSep + key); 312 entries.putIfAbsent(key, entry); 313 } 314 return entry; 315 } 316 317 /** 318 * Gets the current network connections. 319 * @return An array of connection information. 320 * @deprecated Use {@link NetworkTableInstance#getConnections()} instead. 321 */ 322 @Deprecated 323 public static ConnectionInfo[] connections() { 324 return NetworkTableInstance.getDefault().getConnections(); 325 } 326 327 /** 328 * Determine whether or not a network connection is active. 329 * @return True if connected, false if not connected. 330 * @deprecated Use {@link NetworkTableInstance#isConnected()} instead. 331 */ 332 @Deprecated 333 public boolean isConnected() { 334 return inst.isConnected(); 335 } 336 337 /** 338 * Determine whether NetworkTables is operating as a server or as a client. 339 * @return True if operating as a server, false otherwise. 340 * @deprecated Use {@link NetworkTableInstance#getNetworkMode()} instead. 341 */ 342 @Deprecated 343 public boolean isServer() { 344 return (inst.getNetworkMode() & NetworkTableInstance.kNetModeServer) != 0; 345 } 346 347 /* Backwards compatibility shims for IRemoteConnectionListener */ 348 private static class ConnectionListenerAdapter implements Consumer<ConnectionNotification> { 349 public int uid; 350 private final IRemote targetSource; 351 private final IRemoteConnectionListener targetListener; 352 353 public ConnectionListenerAdapter(IRemote targetSource, IRemoteConnectionListener targetListener) { 354 this.targetSource = targetSource; 355 this.targetListener = targetListener; 356 } 357 358 @Override 359 public void accept(ConnectionNotification event) { 360 if (event.connected) 361 targetListener.connectedEx(targetSource, event.conn); 362 else 363 targetListener.disconnectedEx(targetSource, event.conn); 364 } 365 } 366 367 private static final HashMap<IRemoteConnectionListener,ConnectionListenerAdapter> globalConnectionListenerMap = new HashMap<IRemoteConnectionListener,ConnectionListenerAdapter>(); 368 369 private static IRemote staticRemote = new IRemote() { 370 public void addConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify) { 371 NetworkTable.addGlobalConnectionListener(listener, immediateNotify); 372 } 373 public void removeConnectionListener(IRemoteConnectionListener listener) { 374 NetworkTable.removeGlobalConnectionListener(listener); 375 } 376 public boolean isConnected() { 377 ConnectionInfo[] conns = NetworkTableInstance.getDefault().getConnections(); 378 return conns.length > 0; 379 } 380 public boolean isServer() { 381 return (NetworkTableInstance.getDefault().getNetworkMode() & NetworkTableInstance.kNetModeServer) != 0; 382 } 383 }; 384 385 private final HashMap<IRemoteConnectionListener,ConnectionListenerAdapter> connectionListenerMap = new HashMap<IRemoteConnectionListener,ConnectionListenerAdapter>(); 386 387 /** 388 * Add a connection listener. 389 * @param listener connection listener 390 * @param immediateNotify call listener immediately for all existing connections 391 * @deprecated Use {@link NetworkTableInstance#addConnectionListener(Consumer, boolean)} instead. 392 */ 393 @Deprecated 394 public static synchronized void addGlobalConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify) { 395 ConnectionListenerAdapter adapter = new ConnectionListenerAdapter(staticRemote, listener); 396 if (globalConnectionListenerMap.putIfAbsent(listener, adapter) != null) { 397 throw new IllegalStateException("Cannot add the same listener twice"); 398 } 399 adapter.uid = NetworkTableInstance.getDefault().addConnectionListener(adapter, immediateNotify); 400 } 401 402 /** 403 * Remove a connection listener. 404 * @param listener connection listener 405 * @deprecated Use {@link NetworkTableInstance#removeConnectionListener(int)} instead. 406 */ 407 @Deprecated 408 public static synchronized void removeGlobalConnectionListener(IRemoteConnectionListener listener) { 409 ConnectionListenerAdapter adapter = globalConnectionListenerMap.remove(listener); 410 if (adapter != null) { 411 NetworkTableInstance.getDefault().removeConnectionListener(adapter.uid); 412 } 413 } 414 415 /** 416 * Add a connection listener. 417 * @param listener connection listener 418 * @param immediateNotify call listener immediately for all existing connections 419 * @deprecated Use {@link NetworkTableInstance#addConnectionListener(Consumer, boolean)} instead. 420 */ 421 @Deprecated 422 public synchronized void addConnectionListener(IRemoteConnectionListener listener, 423 boolean immediateNotify) { 424 ConnectionListenerAdapter adapter = new ConnectionListenerAdapter(this, listener); 425 if (connectionListenerMap.putIfAbsent(listener, adapter) != null) { 426 throw new IllegalStateException("Cannot add the same listener twice"); 427 } 428 adapter.uid = inst.addConnectionListener(adapter, immediateNotify); 429 } 430 431 /** 432 * Remove a connection listener. 433 * @param listener connection listener 434 * @deprecated Use {@link NetworkTableInstance#removeConnectionListener(int)} instead. 435 */ 436 @Deprecated 437 public synchronized void removeConnectionListener(IRemoteConnectionListener listener) { 438 ConnectionListenerAdapter adapter = connectionListenerMap.get(listener); 439 if (adapter != null && connectionListenerMap.remove(listener, adapter)) { 440 inst.removeConnectionListener(adapter.uid); 441 } 442 } 443 444 /** 445 * {@inheritDoc} 446 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addEntryListener(TableEntryListener, int)} instead 447 * (with flags value of NOTIFY_NEW | NOTIFY_UPDATE). 448 */ 449 @Override 450 @Deprecated 451 public void addTableListener(ITableListener listener) { 452 addTableListenerEx(listener, NOTIFY_NEW | NOTIFY_UPDATE); 453 } 454 455 /** 456 * {@inheritDoc} 457 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addEntryListener(TableEntryListener, int)} instead 458 * (with flags value of NOTIFY_NEW | NOTIFY_UPDATE | NOTIFY_IMMEDIATE). 459 */ 460 @Override 461 @Deprecated 462 public void addTableListener(ITableListener listener, 463 boolean immediateNotify) { 464 int flags = NOTIFY_NEW | NOTIFY_UPDATE; 465 if (immediateNotify) 466 flags |= NOTIFY_IMMEDIATE; 467 addTableListenerEx(listener, flags); 468 } 469 470 /* Base class for listeners; stores uid to implement remove functions */ 471 private static class ListenerBase { 472 public int uid; 473 } 474 475 private class OldTableListenerAdapter extends ListenerBase implements Consumer<EntryNotification> { 476 private final int prefixLen; 477 private final ITable targetSource; 478 private final ITableListener targetListener; 479 480 public OldTableListenerAdapter(int prefixLen, ITable targetSource, ITableListener targetListener) { 481 this.prefixLen = prefixLen; 482 this.targetSource = targetSource; 483 this.targetListener = targetListener; 484 } 485 486 @Override 487 public void accept(EntryNotification event) { 488 String relativeKey = event.name.substring(prefixLen); 489 if (relativeKey.indexOf(PATH_SEPARATOR) != -1) 490 return; 491 targetListener.valueChangedEx(targetSource, relativeKey, event.value.getValue(), event.flags); 492 } 493 } 494 495 private final HashMap<ITableListener,List<ListenerBase>> oldListenerMap = new HashMap<ITableListener,List<ListenerBase>>(); 496 497 /** 498 * {@inheritDoc} 499 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addEntryListener(TableEntryListener, int)} instead. 500 */ 501 @Override 502 @Deprecated 503 public synchronized void addTableListenerEx(ITableListener listener, 504 int flags) { 505 List<ListenerBase> adapters = oldListenerMap.get(listener); 506 if (adapters == null) { 507 adapters = new ArrayList<ListenerBase>(); 508 oldListenerMap.put(listener, adapters); 509 } 510 OldTableListenerAdapter adapter = 511 new OldTableListenerAdapter(path.length() + 1, this, listener); 512 adapter.uid = inst.addEntryListener(pathWithSep, adapter, flags); 513 adapters.add(adapter); 514 } 515 516 /** 517 * {@inheritDoc} 518 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addEntryListener(String, TableEntryListener, int)} 519 * or {@link NetworkTableEntry#addListener(Consumer, int)} instead. 520 */ 521 @Override 522 @Deprecated 523 public void addTableListener(String key, ITableListener listener, 524 boolean immediateNotify) { 525 int flags = NOTIFY_NEW | NOTIFY_UPDATE; 526 if (immediateNotify) 527 flags |= NOTIFY_IMMEDIATE; 528 addTableListenerEx(key, listener, flags); 529 } 530 531 private class OldKeyListenerAdapter extends ListenerBase implements Consumer<EntryNotification> { 532 private final String relativeKey; 533 private final ITable targetSource; 534 private final ITableListener targetListener; 535 536 public OldKeyListenerAdapter(String relativeKey, ITable targetSource, ITableListener targetListener) { 537 this.relativeKey = relativeKey; 538 this.targetSource = targetSource; 539 this.targetListener = targetListener; 540 } 541 542 @Override 543 public void accept(EntryNotification event) { 544 targetListener.valueChangedEx(targetSource, relativeKey, event.value.getValue(), event.flags); 545 } 546 } 547 548 /** 549 * {@inheritDoc} 550 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addEntryListener(String, TableEntryListener, int)} 551 * or {@link NetworkTableEntry#addListener(Consumer, int)} instead. 552 */ 553 @Override 554 @Deprecated 555 public synchronized void addTableListenerEx(String key, 556 ITableListener listener, 557 int flags) { 558 List<ListenerBase> adapters = oldListenerMap.get(listener); 559 if (adapters == null) { 560 adapters = new ArrayList<ListenerBase>(); 561 oldListenerMap.put(listener, adapters); 562 } 563 OldKeyListenerAdapter adapter = new OldKeyListenerAdapter(key, this, listener); 564 adapter.uid = inst.addEntryListener(getEntry(key), adapter, flags); 565 adapters.add(adapter); 566 } 567 568 /** 569 * {@inheritDoc} 570 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addSubTableListener(TableListener, boolean)} 571 * instead. 572 */ 573 @Override 574 @Deprecated 575 public void addSubTableListener(final ITableListener listener) { 576 addSubTableListener(listener, false); 577 } 578 579 private class OldSubListenerAdapter extends ListenerBase implements Consumer<EntryNotification> { 580 private final int prefixLen; 581 private final ITable targetSource; 582 private final ITableListener targetListener; 583 private final Set<String> notifiedTables = new HashSet<String>(); 584 585 public OldSubListenerAdapter(int prefixLen, ITable targetSource, ITableListener targetListener) { 586 this.prefixLen = prefixLen; 587 this.targetSource = targetSource; 588 this.targetListener = targetListener; 589 } 590 591 @Override 592 public void accept(EntryNotification event) { 593 String relativeKey = event.name.substring(prefixLen); 594 int endSubTable = relativeKey.indexOf(PATH_SEPARATOR); 595 if (endSubTable == -1) 596 return; 597 String subTableKey = relativeKey.substring(0, endSubTable); 598 if (notifiedTables.contains(subTableKey)) 599 return; 600 notifiedTables.add(subTableKey); 601 targetListener.valueChangedEx(targetSource, subTableKey, targetSource.getSubTable(subTableKey), event.flags); 602 } 603 } 604 605 /** 606 * {@inheritDoc} 607 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#addSubTableListener(TableListener, boolean)} 608 * instead. 609 */ 610 @Override 611 @Deprecated 612 public synchronized void addSubTableListener(final ITableListener listener, 613 boolean localNotify) { 614 List<ListenerBase> adapters = oldListenerMap.get(listener); 615 if (adapters == null) { 616 adapters = new ArrayList<ListenerBase>(); 617 oldListenerMap.put(listener, adapters); 618 } 619 OldSubListenerAdapter adapter = 620 new OldSubListenerAdapter(path.length() + 1, this, listener); 621 int flags = NOTIFY_NEW | NOTIFY_IMMEDIATE; 622 if (localNotify) 623 flags |= NOTIFY_LOCAL; 624 adapter.uid = inst.addEntryListener(pathWithSep, adapter, flags); 625 adapters.add(adapter); 626 } 627 628 /** 629 * {@inheritDoc} 630 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTable#removeTableListener(int)} instead. 631 */ 632 @Override 633 @Deprecated 634 public synchronized void removeTableListener(ITableListener listener) { 635 List<ListenerBase> adapters = oldListenerMap.remove(listener); 636 if (adapters != null) { 637 for (ListenerBase adapter : adapters) 638 inst.removeEntryListener(adapter.uid); 639 } 640 } 641 642 /** 643 * {@inheritDoc} 644 */ 645 @Override 646 public ITable getSubTable(String key) { 647 return new NetworkTable(inst, pathWithSep + key); 648 } 649 650 /** 651 * {@inheritDoc} 652 */ 653 @Override 654 public boolean containsKey(String key) { 655 return getEntry(key).exists(); 656 } 657 658 public boolean containsSubTable(String key) { 659 int[] handles = NetworkTablesJNI.getEntries(inst.getHandle(), pathWithSep + key + PATH_SEPARATOR, 0); 660 return handles.length != 0; 661 } 662 663 /** 664 * @param types bitmask of types; 0 is treated as a "don't care". 665 * @return keys currently in the table 666 */ 667 public Set<String> getKeys(int types) { 668 Set<String> keys = new HashSet<String>(); 669 int prefixLen = path.length() + 1; 670 for (EntryInfo info : inst.getEntryInfo(pathWithSep, types)) { 671 String relativeKey = info.name.substring(prefixLen); 672 if (relativeKey.indexOf(PATH_SEPARATOR) != -1) 673 continue; 674 keys.add(relativeKey); 675 // populate entries as we go 676 if (entries.get(relativeKey) == null) { 677 entries.putIfAbsent(relativeKey, new NetworkTableEntry(inst, info.entry)); 678 } 679 } 680 return keys; 681 } 682 683 /** 684 * {@inheritDoc} 685 */ 686 @Override 687 public Set<String> getKeys() { 688 return getKeys(0); 689 } 690 691 /** 692 * {@inheritDoc} 693 */ 694 @Override 695 public Set<String> getSubTables() { 696 Set<String> keys = new HashSet<String>(); 697 int prefixLen = path.length() + 1; 698 for (EntryInfo info : inst.getEntryInfo(pathWithSep, 0)) { 699 String relativeKey = info.name.substring(prefixLen); 700 int endSubTable = relativeKey.indexOf(PATH_SEPARATOR); 701 if (endSubTable == -1) 702 continue; 703 keys.add(relativeKey.substring(0, endSubTable)); 704 } 705 return keys; 706 } 707 708 /** 709 * {@inheritDoc} 710 */ 711 @Override 712 public boolean putNumber(String key, double value) { 713 return getEntry(key).setNumber(value); 714 } 715 716 /** 717 * {@inheritDoc} 718 */ 719 public boolean setDefaultNumber(String key, double defaultValue) { 720 return getEntry(key).setDefaultDouble(defaultValue); 721 } 722 723 /** 724 * {@inheritDoc} 725 */ 726 @Override 727 public double getNumber(String key, double defaultValue) { 728 return getEntry(key).getDouble(defaultValue); 729 } 730 731 /** 732 * {@inheritDoc} 733 */ 734 @Override 735 public boolean putString(String key, String value) { 736 return getEntry(key).setString(value); 737 } 738 739 /** 740 * {@inheritDoc} 741 */ 742 public boolean setDefaultString(String key, String defaultValue) { 743 return getEntry(key).setDefaultString(defaultValue); 744 } 745 746 /** 747 * {@inheritDoc} 748 */ 749 @Override 750 public String getString(String key, String defaultValue) { 751 return getEntry(key).getString(defaultValue); 752 } 753 754 /** 755 * {@inheritDoc} 756 */ 757 @Override 758 public boolean putBoolean(String key, boolean value) { 759 return getEntry(key).setBoolean(value); 760 } 761 762 /** 763 * {@inheritDoc} 764 */ 765 public boolean setDefaultBoolean(String key, boolean defaultValue) { 766 return getEntry(key).setDefaultBoolean(defaultValue); 767 } 768 769 /** 770 * {@inheritDoc} 771 */ 772 @Override 773 public boolean getBoolean(String key, boolean defaultValue) { 774 return getEntry(key).getBoolean(defaultValue); 775 } 776 777 /** 778 * {@inheritDoc} 779 */ 780 @Override 781 public boolean putBooleanArray(String key, boolean[] value) { 782 return getEntry(key).setBooleanArray(value); 783 } 784 785 /** 786 * {@inheritDoc} 787 */ 788 @Override 789 public boolean putBooleanArray(String key, Boolean[] value) { 790 return getEntry(key).setBooleanArray(value); 791 } 792 793 /** 794 * {@inheritDoc} 795 */ 796 public boolean setDefaultBooleanArray(String key, boolean[] defaultValue) { 797 return getEntry(key).setDefaultBooleanArray(defaultValue); 798 } 799 800 /** 801 * {@inheritDoc} 802 */ 803 public boolean setDefaultBooleanArray(String key, Boolean[] defaultValue) { 804 return getEntry(key).setDefaultBooleanArray(defaultValue); 805 } 806 807 /** 808 * {@inheritDoc} 809 */ 810 @Override 811 public boolean[] getBooleanArray(String key, boolean[] defaultValue) { 812 return getEntry(key).getBooleanArray(defaultValue); 813 } 814 815 /** 816 * {@inheritDoc} 817 */ 818 @Override 819 public Boolean[] getBooleanArray(String key, Boolean[] defaultValue) { 820 return getEntry(key).getBooleanArray(defaultValue); 821 } 822 823 /** 824 * {@inheritDoc} 825 */ 826 @Override 827 public boolean putNumberArray(String key, double[] value) { 828 return getEntry(key).setDoubleArray(value); 829 } 830 831 /** 832 * {@inheritDoc} 833 */ 834 @Override 835 public boolean putNumberArray(String key, Double[] value) { 836 return getEntry(key).setNumberArray(value); 837 } 838 839 /** 840 * {@inheritDoc} 841 */ 842 public boolean setDefaultNumberArray(String key, double[] defaultValue) { 843 return getEntry(key).setDefaultDoubleArray(defaultValue); 844 } 845 846 /** 847 * {@inheritDoc} 848 */ 849 public boolean setDefaultNumberArray(String key, Double[] defaultValue) { 850 return getEntry(key).setDefaultNumberArray(defaultValue); 851 } 852 853 /** 854 * {@inheritDoc} 855 */ 856 @Override 857 public double[] getNumberArray(String key, double[] defaultValue) { 858 return getEntry(key).getDoubleArray(defaultValue); 859 } 860 861 /** 862 * {@inheritDoc} 863 */ 864 @Override 865 public Double[] getNumberArray(String key, Double[] defaultValue) { 866 return getEntry(key).getDoubleArray(defaultValue); 867 } 868 869 /** 870 * {@inheritDoc} 871 */ 872 @Override 873 public boolean putStringArray(String key, String[] value) { 874 return getEntry(key).setStringArray(value); 875 } 876 877 /** 878 * {@inheritDoc} 879 */ 880 public boolean setDefaultStringArray(String key, String[] defaultValue) { 881 return getEntry(key).setDefaultStringArray(defaultValue); 882 } 883 884 /** 885 * {@inheritDoc} 886 */ 887 @Override 888 public String[] getStringArray(String key, String[] defaultValue) { 889 return getEntry(key).getStringArray(defaultValue); 890 } 891 892 /** 893 * {@inheritDoc} 894 */ 895 @Override 896 public boolean putRaw(String key, byte[] value) { 897 return getEntry(key).setRaw(value); 898 } 899 900 /** 901 * {@inheritDoc} 902 */ 903 public boolean setDefaultRaw(String key, byte[] defaultValue) { 904 return getEntry(key).setDefaultRaw(defaultValue); 905 } 906 907 /** 908 * {@inheritDoc} 909 */ 910 @Override 911 public boolean putRaw(String key, ByteBuffer value, int len) { 912 return getEntry(key).setRaw(value, len); 913 } 914 915 /** 916 * {@inheritDoc} 917 */ 918 @Override 919 public byte[] getRaw(String key, byte[] defaultValue) { 920 return getEntry(key).getRaw(defaultValue); 921 } 922 923 /** 924 * Put a value in the table 925 * @param key the key to be assigned to 926 * @param value the value that will be assigned 927 * @return False if the table key already exists with a different type 928 */ 929 public boolean putValue(String key, NetworkTableValue value) { 930 return getEntry(key).setValue(value); 931 } 932 933 /** 934 * Sets the current value in the table if it does not exist. 935 * @param key the key 936 * @param defaultValue the default value to set if key doens't exist. 937 * @return False if the table key exists with a different type 938 */ 939 public boolean setDefaultValue(String key, NetworkTableValue defaultValue) { 940 return getEntry(key).setDefaultValue(defaultValue); 941 } 942 943 /** 944 * Gets the value associated with a key as a NetworkTableValue object. 945 * @param key the key of the value to look up 946 * @return the value associated with the given key 947 */ 948 public NetworkTableValue getValue(String key) { 949 return getEntry(key).getValue(); 950 } 951 952 /** 953 * {@inheritDoc} 954 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTableEntry#setValue(Object)} 955 * instead, e.g. `NetworkTable.getEntry(key).setValue(NetworkTableEntry.makeBoolean(false));` 956 * or `NetworkTable.getEntry(key).setValue(new Boolean(false));` 957 */ 958 @Deprecated 959 public boolean putValue(String key, Object value) throws IllegalArgumentException { 960 if (value instanceof Boolean) 961 return putBoolean(key, ((Boolean)value).booleanValue()); 962 else if (value instanceof Number) 963 return putDouble(key, ((Number)value).doubleValue()); 964 else if (value instanceof String) 965 return putString(key, (String)value); 966 else if (value instanceof byte[]) 967 return putRaw(key, (byte[])value); 968 else if (value instanceof boolean[]) 969 return putBooleanArray(key, (boolean[])value); 970 else if (value instanceof double[]) 971 return putNumberArray(key, (double[])value); 972 else if (value instanceof Boolean[]) 973 return putBooleanArray(key, toNative((Boolean[])value)); 974 else if (value instanceof Number[]) 975 return putNumberArray(key, toNative((Number[])value)); 976 else if (value instanceof String[]) 977 return putStringArray(key, (String[])value); 978 else if (value instanceof NetworkTableValue) 979 return getEntry(key).setValue((NetworkTableValue)value); 980 else 981 throw new IllegalArgumentException("Value of type " + value.getClass().getName() + " cannot be put into a table"); 982 } 983 984 /** 985 * {@inheritDoc} 986 * @deprecated Use {@link edu.wpi.first.networktables.NetworkTableEntry#getValue()} 987 * instead, e.g. `NetworkTable.getEntry(key).getValue();` 988 */ 989 @Override 990 @Deprecated 991 public Object getValue(String key, Object defaultValue) { 992 NetworkTableValue value = getValue(key); 993 if (value.getType() == NetworkTableType.kUnassigned) { 994 return defaultValue; 995 } 996 return value.getValue(); 997 } 998 999 /** The persistent flag value. */ 1000 public static final int PERSISTENT = 1; 1001 1002 /** 1003 * {@inheritDoc} 1004 */ 1005 @Override 1006 public void setPersistent(String key) { 1007 getEntry(key).setPersistent(); 1008 } 1009 1010 /** 1011 * {@inheritDoc} 1012 */ 1013 @Override 1014 public void clearPersistent(String key) { 1015 getEntry(key).clearPersistent(); 1016 } 1017 1018 /** 1019 * {@inheritDoc} 1020 */ 1021 @Override 1022 public boolean isPersistent(String key) { 1023 return getEntry(key).isPersistent(); 1024 } 1025 1026 /** 1027 * {@inheritDoc} 1028 */ 1029 @Override 1030 public void setFlags(String key, int flags) { 1031 getEntry(key).setFlags(flags); 1032 } 1033 1034 /** 1035 * {@inheritDoc} 1036 */ 1037 @Override 1038 public void clearFlags(String key, int flags) { 1039 getEntry(key).clearFlags(flags); 1040 } 1041 1042 /** 1043 * {@inheritDoc} 1044 */ 1045 @Override 1046 public int getFlags(String key) { 1047 return getEntry(key).getFlags(); 1048 } 1049 1050 /** 1051 * {@inheritDoc} 1052 */ 1053 @Override 1054 public void delete(String key) { 1055 getEntry(key).delete(); 1056 } 1057 1058 /** 1059 * Deletes ALL keys in ALL subtables. Use with caution! 1060 * @deprecated Use {@link NetworkTableInstance#deleteAllEntries()} instead. 1061 */ 1062 @Deprecated 1063 public static void globalDeleteAll() { 1064 NetworkTableInstance.getDefault().deleteAllEntries(); 1065 } 1066 1067 /** 1068 * Flushes all updated values immediately to the network. 1069 * Note: This is rate-limited to protect the network from flooding. 1070 * This is primarily useful for synchronizing network updates with 1071 * user code. 1072 * @deprecated Use {@link NetworkTableInstance#flush()} instead. 1073 */ 1074 @Deprecated 1075 public static void flush() { 1076 NetworkTableInstance.getDefault().flush(); 1077 } 1078 1079 /** 1080 * Set the periodic update rate. 1081 * 1082 * @param interval update interval in seconds (range 0.01 to 1.0) 1083 * @deprecated Use {@link NetworkTableInstance#setUpdateRate(double)} 1084 * instead. 1085 */ 1086 @Deprecated 1087 public static void setUpdateRate(double interval) { 1088 NetworkTableInstance.getDefault().setUpdateRate(interval); 1089 } 1090 1091 /** 1092 * Saves persistent keys to a file. The server does this automatically. 1093 * 1094 * @param filename file name 1095 * @throws PersistentException if error saving file 1096 * @deprecated Use {@link NetworkTableInstance#savePersistent(String)} 1097 * instead. 1098 */ 1099 @Deprecated 1100 public static void savePersistent(String filename) throws PersistentException { 1101 NetworkTableInstance.getDefault().savePersistent(filename); 1102 } 1103 1104 /** 1105 * Loads persistent keys from a file. The server does this automatically. 1106 * 1107 * @param filename file name 1108 * @return List of warnings (errors result in an exception instead) 1109 * @throws PersistentException if error reading file 1110 * @deprecated Use {@link NetworkTableInstance#loadPersistent(String)} 1111 * instead. 1112 */ 1113 @Deprecated 1114 public static String[] loadPersistent(String filename) throws PersistentException { 1115 return NetworkTableInstance.getDefault().loadPersistent(filename); 1116 } 1117 1118 /* 1119 * Deprecated Methods 1120 */ 1121 1122 /** 1123 * {@inheritDoc} 1124 * @deprecated Use {@link #putNumber(String, double)} instead. 1125 */ 1126 @Override 1127 @Deprecated 1128 public boolean putDouble(String key, double value) { 1129 return putNumber(key, value); 1130 } 1131 1132 /** 1133 * {@inheritDoc} 1134 * @deprecated Use {@link #getNumber(String, double)} instead. 1135 */ 1136 @Override 1137 @Deprecated 1138 public double getDouble(String key, double defaultValue) { 1139 return getNumber(key, defaultValue); 1140 } 1141 1142 /** 1143 * {@inheritDoc} 1144 */ 1145 @Override 1146 public String getPath() { 1147 return path; 1148 } 1149 1150 @Override 1151 public boolean equals(Object o) { 1152 if (o == this) { 1153 return true; 1154 } 1155 if (!(o instanceof NetworkTable)) { 1156 return false; 1157 } 1158 NetworkTable other = (NetworkTable) o; 1159 return inst.equals(other.inst) && path.equals(other.path); 1160 } 1161 1162 @Override 1163 public int hashCode() { 1164 return Objects.hash(inst, path); 1165 } 1166}