Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

FixedXmppConnection.java 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright (c) 2006-2015 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.parser.xmpp;
  23. import java.lang.reflect.Field;
  24. import java.util.HashSet;
  25. import java.util.Set;
  26. import org.jivesoftware.smack.Connection;
  27. import org.jivesoftware.smack.ConnectionConfiguration;
  28. import org.jivesoftware.smack.ConnectionCreationListener;
  29. import org.jivesoftware.smack.XMPPConnection;
  30. import org.jivesoftware.smack.XMPPException;
  31. import org.jivesoftware.smackx.ServiceDiscoveryManager;
  32. /**
  33. * An extension of XMPPConnection that hacks around the problems caused by Smack's ridiculous use of
  34. * static initialisers (and the dependencies between them). See
  35. * http://issues.igniterealtime.org/browse/SMACK-315 for info.
  36. */
  37. public class FixedXmppConnection extends XMPPConnection
  38. implements ConnectionCreationListener {
  39. /** A set of listeners that were registered with the XMPP Parser. */
  40. private final Set<ConnectionCreationListener> oldListeners = new HashSet<>();
  41. /**
  42. * Creates a new fixed XMPP connection with the specified config.
  43. *
  44. * @param config The config to pass on to the underlying connection
  45. *
  46. * @see XMPPConnection#XMPPConnection(org.jivesoftware.smack.ConnectionConfiguration)
  47. */
  48. public FixedXmppConnection(final ConnectionConfiguration config) {
  49. super(config);
  50. }
  51. @Override
  52. public void connect() throws XMPPException {
  53. // We're fiddling with a static array
  54. synchronized (FixedXmppConnection.class) {
  55. final Set<ConnectionCreationListener> rawListeners = getListeners();
  56. // Copy them so we can clear and restore later
  57. oldListeners.addAll(rawListeners);
  58. // Get rid of everything and add ourselves.
  59. rawListeners.clear();
  60. rawListeners.add(this);
  61. try {
  62. super.connect();
  63. } finally {
  64. // Restore to the previous state
  65. rawListeners.remove(this);
  66. rawListeners.addAll(oldListeners);
  67. oldListeners.clear();
  68. }
  69. }
  70. }
  71. @Override
  72. @SuppressWarnings("ResultOfObjectAllocationIgnored")
  73. public void connectionCreated(final Connection xmppc) {
  74. // Creating this shoves itself into a static map. Other listeners
  75. // depend on this entry existing in the map before they're called.
  76. new ServiceDiscoveryManager(xmppc);
  77. // Now execute our real listeners
  78. // We've already created a discovery manager, don't make another...
  79. oldListeners.stream()
  80. .filter(listener -> !ServiceDiscoveryManager.class
  81. .equals(listener.getClass().getEnclosingClass()))
  82. .forEach(listener -> listener.connectionCreated(xmppc));
  83. }
  84. /**
  85. * Retrieves the set of listeners that have been registered statically with the XMPPConnection
  86. * class.
  87. *
  88. * @return The raw listener set.
  89. */
  90. @SuppressWarnings("unchecked")
  91. private Set<ConnectionCreationListener> getListeners() {
  92. try {
  93. final Field field = XMPPConnection.class.getDeclaredField(
  94. "connectionEstablishedListeners");
  95. field.setAccessible(true);
  96. return (Set<ConnectionCreationListener>) field.get(null);
  97. } catch (ReflectiveOperationException ex) {
  98. // Throws a bunch of exceptions... Try to carry on anyway, the
  99. // horrible concurrency bugs might not bite.
  100. return new HashSet<>();
  101. }
  102. }
  103. }