Rename store methods and fix access to open pubsub nodes

This commit is contained in:
Paul Schaub 2018-07-03 11:29:27 +02:00
parent 6a756c9a44
commit 613c5d869a
10 changed files with 110 additions and 60 deletions

View File

@ -24,7 +24,6 @@ import java.util.logging.Level;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.util.FileUtils; import org.jivesoftware.smack.util.FileUtils;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ox.OXInstantMessagingManager; import org.jivesoftware.smackx.ox.OXInstantMessagingManager;
@ -76,15 +75,6 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint(); final SimpleResultSyncPoint bobReceivedMessage = new SimpleResultSyncPoint();
final String body = "Writing integration tests is an annoying task, but it has to be done, so lets do it!!!"; final String body = "Writing integration tests is an annoying task, but it has to be done, so lets do it!!!";
Roster aliceRoster = Roster.getInstanceFor(aliceConnection);
Roster bobRoster = Roster.getInstanceFor(bobConnection);
aliceRoster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
bobRoster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
aliceRoster.createEntry(bob, "Bob", null);
bobRoster.createEntry(alice, "Alice", null);
FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(aliceStorePath, new UnprotectedKeysProtector()); FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(aliceStorePath, new UnprotectedKeysProtector());
FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobStorePath, new UnprotectedKeysProtector()); FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobStorePath, new UnprotectedKeysProtector());
@ -114,8 +104,8 @@ public class BasicOpenPgpInstantMessagingIntegrationTest extends AbstractOpenPgp
aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice); aliceFingerprint = aliceOpenPgp.generateAndImportKeyPair(alice);
bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob); bobFingerprint = bobOpenPgp.generateAndImportKeyPair(bob);
aliceStore.setPrimaryOpenPgpKeyPairFingerprint(aliceFingerprint); aliceStore.setSigningKeyPairFingerprint(aliceFingerprint);
bobStore.setPrimaryOpenPgpKeyPairFingerprint(bobFingerprint); bobStore.setSigningKeyPairFingerprint(bobFingerprint);
aliceOpenPgp.announceSupportAndPublish(); aliceOpenPgp.announceSupportAndPublish();
bobOpenPgp.announceSupportAndPublish(); bobOpenPgp.announceSupportAndPublish();

View File

@ -101,11 +101,11 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection); OpenPgpManager openPgpManager = OpenPgpManager.getInstanceFor(aliceConnection);
openPgpManager.setOpenPgpProvider(beforeProvider); openPgpManager.setOpenPgpProvider(beforeProvider);
assertNull(beforeStore.getPrimaryOpenPgpKeyPairFingerprint()); assertNull(beforeStore.getSigningKeyPairFingerprint());
OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice); OpenPgpV4Fingerprint keyFingerprint = openPgpManager.generateAndImportKeyPair(alice);
beforeStore.setPrimaryOpenPgpKeyPairFingerprint(keyFingerprint); beforeStore.setSigningKeyPairFingerprint(keyFingerprint);
assertEquals(keyFingerprint, beforeStore.getPrimaryOpenPgpKeyPairFingerprint()); assertEquals(keyFingerprint, beforeStore.getSigningKeyPairFingerprint());
assertTrue(beforeStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint)); assertTrue(beforeStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
@ -125,7 +125,7 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(alice, afterStore); PainlessOpenPgpProvider afterProvider = new PainlessOpenPgpProvider(alice, afterStore);
openPgpManager.setOpenPgpProvider(afterProvider); openPgpManager.setOpenPgpProvider(afterProvider);
assertNull(afterStore.getPrimaryOpenPgpKeyPairFingerprint()); assertNull(afterStore.getSigningKeyPairFingerprint());
assertFalse(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint)); assertFalse(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() { OpenPgpV4Fingerprint fingerprint = openPgpManager.restoreSecretKeyServerBackup(new AskForBackupCodeCallback() {
@ -142,9 +142,9 @@ public class SecretKeyBackupRestoreIntegrationTest extends AbstractOpenPgpIntegr
assertTrue(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint)); assertTrue(afterStore.getAvailableKeyPairFingerprints(alice).contains(keyFingerprint));
afterStore.setPrimaryOpenPgpKeyPairFingerprint(fingerprint); afterStore.setSigningKeyPairFingerprint(fingerprint);
assertEquals(keyFingerprint, afterStore.getPrimaryOpenPgpKeyPairFingerprint()); assertEquals(keyFingerprint, afterStore.getSigningKeyPairFingerprint());
assertTrue(Arrays.equals(beforeStore.getSecretKeyRings(alice).getEncoded(), afterStore.getSecretKeyRings(alice).getEncoded())); assertTrue(Arrays.equals(beforeStore.getSecretKeyRings(alice).getEncoded(), afterStore.getSecretKeyRings(alice).getEncoded()));
} }
} }

View File

@ -39,12 +39,12 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
private final SecretKeyRingProtector secretKeyRingProtector; private final SecretKeyRingProtector secretKeyRingProtector;
@Override @Override
public OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint() { public OpenPgpV4Fingerprint getSigningKeyPairFingerprint() {
return primaryKeyFingerprint; return primaryKeyFingerprint;
} }
@Override @Override
public void setPrimaryOpenPgpKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) { public void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint) {
this.primaryKeyFingerprint = fingerprint; this.primaryKeyFingerprint = fingerprint;
} }

View File

@ -220,7 +220,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
secretKeyRings = getStore().getSecretKeyRings(owner); secretKeyRings = getStore().getSecretKeyRings(owner);
} catch (PGPException | IOException e) { } catch (PGPException | IOException e) {
LOGGER.log(Level.INFO, "Could not get secret keys of user " + owner); LOGGER.log(Level.INFO, "Could not get secret keys of user " + owner);
throw new MissingOpenPgpKeyPairException(owner, getStore().getPrimaryOpenPgpKeyPairFingerprint()); throw new MissingOpenPgpKeyPairException(owner, getStore().getSigningKeyPairFingerprint());
} }
SecretKeyRingProtector protector = getStore().getSecretKeyProtector(); SecretKeyRingProtector protector = getStore().getSecretKeyProtector();

View File

@ -90,8 +90,8 @@ public class DryOxEncryptionTest extends OxTestSuite {
OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romemo, OpenPgpV4Fingerprint romeoFinger = romeoProvider.importSecretKey(romemo,
BCUtil.getDecodedBytes(TestKeys.ROMEO_PRIV.getBytes(UTF8))); BCUtil.getDecodedBytes(TestKeys.ROMEO_PRIV.getBytes(UTF8)));
julietStore.setPrimaryOpenPgpKeyPairFingerprint(julietFinger); julietStore.setSigningKeyPairFingerprint(julietFinger);
romeoStore.setPrimaryOpenPgpKeyPairFingerprint(romeoFinger); romeoStore.setSigningKeyPairFingerprint(romeoFinger);
byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(juliet, julietFinger); byte[] julietPubBytes = julietStore.getPublicKeyRingBytes(juliet, julietFinger);
byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romemo, romeoFinger); byte[] romeoPubBytes = romeoStore.getPublicKeyRingBytes(romemo, romeoFinger);

View File

@ -219,7 +219,7 @@ public final class OpenPgpManager extends Manager {
*/ */
public OpenPgpV4Fingerprint getOurFingerprint() { public OpenPgpV4Fingerprint getOurFingerprint() {
throwIfNoProviderSet(); throwIfNoProviderSet();
return provider.getStore().getPrimaryOpenPgpKeyPairFingerprint(); return provider.getStore().getSigningKeyPairFingerprint();
} }
/** /**
@ -362,12 +362,9 @@ public final class OpenPgpManager extends Manager {
* @throws SmackOpenPgpException * @throws SmackOpenPgpException
* @throws InterruptedException * @throws InterruptedException
* @throws XMPPException.XMPPErrorException * @throws XMPPException.XMPPErrorException
* @throws SmackException.NotConnectedException
* @throws SmackException.NoResponseException
*/ */
private OpenPgpFingerprints determineContactsKeys(BareJid jid) private OpenPgpFingerprints determineContactsKeys(BareJid jid)
throws SmackOpenPgpException, InterruptedException, XMPPException.XMPPErrorException, throws SmackOpenPgpException, InterruptedException, XMPPException.XMPPErrorException {
SmackException.NotConnectedException, SmackException.NoResponseException {
Set<OpenPgpV4Fingerprint> announced = provider.getStore().getAnnouncedKeysFingerprints(jid).keySet(); Set<OpenPgpV4Fingerprint> announced = provider.getStore().getAnnouncedKeysFingerprints(jid).keySet();
Set<OpenPgpV4Fingerprint> available = provider.getStore().getAvailableKeysFingerprints(jid).keySet(); Set<OpenPgpV4Fingerprint> available = provider.getStore().getAvailableKeysFingerprints(jid).keySet();
Map<OpenPgpV4Fingerprint, Throwable> unfetched = new HashMap<>(); Map<OpenPgpV4Fingerprint, Throwable> unfetched = new HashMap<>();
@ -382,7 +379,7 @@ public final class OpenPgpManager extends Manager {
processPublicKey(pubkeyElement, jid); processPublicKey(pubkeyElement, jid);
available.add(f); available.add(f);
} catch (PubSubException.NotAPubSubNodeException | PubSubException.NotALeafNodeException e) { } catch (SmackException e) {
LOGGER.log(Level.WARNING, "Could not fetch public key " + f.toString() + " of user " + jid.toString(), e); LOGGER.log(Level.WARNING, "Could not fetch public key " + f.toString() + " of user " + jid.toString(), e);
unfetched.put(f, e); unfetched.put(f, e);
} catch (MissingUserIdOnKeyException e) { } catch (MissingUserIdOnKeyException e) {
@ -422,9 +419,8 @@ public final class OpenPgpManager extends Manager {
}; };
public void requestMetadataUpdate(BareJid contact) public void requestMetadataUpdate(BareJid contact)
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException, throws InterruptedException, SmackException,
SmackException.NotConnectedException, XMPPException.XMPPErrorException, XMPPException.XMPPErrorException {
PubSubException.NotAPubSubNodeException {
PublicKeysListElement metadata = PubSubDelegate.fetchPubkeysList(connection(), contact); PublicKeysListElement metadata = PubSubDelegate.fetchPubkeysList(connection(), contact);
processPublicKeysListElement(contact, metadata); processPublicKeysListElement(contact, metadata);
} }

View File

@ -64,7 +64,7 @@ public interface OpenPgpProvider {
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, IOException; throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, IOException;
/** /**
* Sign a {@link SignElement} with th users signing key. * Sign a {@link SignElement} with the users signing key.
* The resulting byte array contains the signed byte representation of the {@link SignElement}. * The resulting byte array contains the signed byte representation of the {@link SignElement}.
* *
* @see <a href="https://xmpp.org/extensions/xep-0373.html#exchange">XEP-0373 §3.1</a> * @see <a href="https://xmpp.org/extensions/xep-0373.html#exchange">XEP-0373 §3.1</a>

View File

@ -37,7 +37,7 @@ public interface OpenPgpStore {
* *
* @return fingerprint of the primary OpenPGP key pair. * @return fingerprint of the primary OpenPGP key pair.
*/ */
OpenPgpV4Fingerprint getPrimaryOpenPgpKeyPairFingerprint(); OpenPgpV4Fingerprint getSigningKeyPairFingerprint();
/** /**
* Set the {@link OpenPgpV4Fingerprint} of the primary OpenPGP key pair. * Set the {@link OpenPgpV4Fingerprint} of the primary OpenPGP key pair.
@ -45,7 +45,7 @@ public interface OpenPgpStore {
* *
* @param fingerprint {@link OpenPgpV4Fingerprint} of the new primary key pair. * @param fingerprint {@link OpenPgpV4Fingerprint} of the new primary key pair.
*/ */
void setPrimaryOpenPgpKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint); void setSigningKeyPairFingerprint(OpenPgpV4Fingerprint fingerprint);
/** /**
* Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available * Return a {@link Set} containing the {@link OpenPgpV4Fingerprint}s of the master keys of all available
@ -127,6 +127,8 @@ public interface OpenPgpStore {
* @param owner owner of the key * @param owner owner of the key
* @param fingerprint fingerprint of the key * @param fingerprint fingerprint of the key
* @return byte representation of the public key. * @return byte representation of the public key.
*
* @throws MissingOpenPgpPublicKeyException if the key does not exist.
*/ */
byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) byte[] getPublicKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
throws MissingOpenPgpPublicKeyException; throws MissingOpenPgpPublicKeyException;
@ -137,6 +139,8 @@ public interface OpenPgpStore {
* @param owner owner of the key * @param owner owner of the key
* @param fingerprint fingerprint of the key * @param fingerprint fingerprint of the key
* @return byte representation of the secret key. * @return byte representation of the secret key.
*
* @throws MissingOpenPgpKeyPairException if the secret key doesn't exist.
*/ */
byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint) byte[] getSecretKeyRingBytes(BareJid owner, OpenPgpV4Fingerprint fingerprint)
throws MissingOpenPgpKeyPairException; throws MissingOpenPgpKeyPairException;

View File

@ -57,7 +57,7 @@ public class OpenPgpContact {
OpenPgpFingerprints contactsFingerprints) { OpenPgpFingerprints contactsFingerprints) {
this.cryptoProvider = cryptoProvider; this.cryptoProvider = cryptoProvider;
this.jid = jid; this.jid = jid;
this.singingKey = cryptoProvider.getStore().getPrimaryOpenPgpKeyPairFingerprint(); this.singingKey = cryptoProvider.getStore().getSigningKeyPairFingerprint();
this.ourFingerprints = ourFingerprints; this.ourFingerprints = ourFingerprints;
this.contactsFingerprints = contactsFingerprints; this.contactsFingerprints = contactsFingerprints;
} }

View File

@ -16,8 +16,12 @@
*/ */
package org.jivesoftware.smackx.ox.util; package org.jivesoftware.smackx.ox.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -35,6 +39,7 @@ import org.jivesoftware.smackx.pubsub.AccessModel;
import org.jivesoftware.smackx.pubsub.ConfigureForm; import org.jivesoftware.smackx.pubsub.ConfigureForm;
import org.jivesoftware.smackx.pubsub.Item; import org.jivesoftware.smackx.pubsub.Item;
import org.jivesoftware.smackx.pubsub.LeafNode; import org.jivesoftware.smackx.pubsub.LeafNode;
import org.jivesoftware.smackx.pubsub.Node;
import org.jivesoftware.smackx.pubsub.PayloadItem; import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.PubSubException; import org.jivesoftware.smackx.pubsub.PubSubException;
import org.jivesoftware.smackx.pubsub.PubSubManager; import org.jivesoftware.smackx.pubsub.PubSubManager;
@ -157,19 +162,16 @@ public class PubSubDelegate {
* *
* @return content of our metadata node. * @return content of our metadata node.
* @throws InterruptedException * @throws InterruptedException
* @throws PubSubException.NotALeafNodeException * @throws SmackException
* @throws SmackException.NoResponseException
* @throws SmackException.NotConnectedException
* @throws XMPPException.XMPPErrorException * @throws XMPPException.XMPPErrorException
* @throws PubSubException.NotAPubSubNodeException
*/ */
public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection) public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection)
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException, throws InterruptedException, SmackException,
SmackException.NotConnectedException, XMPPException.XMPPErrorException, XMPPException.XMPPErrorException {
PubSubException.NotAPubSubNodeException {
return fetchPubkeysList(connection, connection.getUser().asBareJid()); return fetchPubkeysList(connection, connection.getUser().asBareJid());
} }
/** /**
* Consult the public key metadata node of {@code contact} to fetch the list of their published OpenPGP public keys. * Consult the public key metadata node of {@code contact} to fetch the list of their published OpenPGP public keys.
* TODO: Add @see which points to the (for now missing) respective example in XEP-0373. * TODO: Add @see which points to the (for now missing) respective example in XEP-0373.
@ -177,19 +179,15 @@ public class PubSubDelegate {
* @param contact {@link BareJid} of the user we want to fetch the list from. * @param contact {@link BareJid} of the user we want to fetch the list from.
* @return content of {@code contact}'s metadata node. * @return content of {@code contact}'s metadata node.
* @throws InterruptedException * @throws InterruptedException
* @throws PubSubException.NotALeafNodeException * @throws SmackException
* @throws SmackException.NoResponseException
* @throws SmackException.NotConnectedException
* @throws XMPPException.XMPPErrorException * @throws XMPPException.XMPPErrorException
* @throws PubSubException.NotAPubSubNodeException
*/ */
public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection, BareJid contact) public static PublicKeysListElement fetchPubkeysList(XMPPConnection connection, BareJid contact)
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException, throws InterruptedException, SmackException,
SmackException.NotConnectedException, XMPPException.XMPPErrorException, XMPPException.XMPPErrorException {
PubSubException.NotAPubSubNodeException {
PubSubManager pm = PubSubManager.getInstance(connection, contact); PubSubManager pm = PubSubManager.getInstance(connection, contact);
LeafNode node = pm.getLeafNode(PEP_NODE_PUBLIC_KEYS); LeafNode node = getOpenLeafNode(pm, PEP_NODE_PUBLIC_KEYS);
List<PayloadItem<PublicKeysListElement>> list = node.getItems(1); List<PayloadItem<PublicKeysListElement>> list = node.getItems(1);
if (list.isEmpty()) { if (list.isEmpty()) {
@ -247,6 +245,7 @@ public class PubSubDelegate {
} }
} }
/** /**
* Fetch the OpenPGP public key of a {@code contact}, identified by its OpenPGP {@code v4_fingerprint}. * Fetch the OpenPGP public key of a {@code contact}, identified by its OpenPGP {@code v4_fingerprint}.
* *
@ -255,20 +254,16 @@ public class PubSubDelegate {
* @param contact {@link BareJid} of the contact we want to fetch a key from. * @param contact {@link BareJid} of the contact we want to fetch a key from.
* @param v4_fingerprint upper case, hex encoded v4 fingerprint of the contacts key. * @param v4_fingerprint upper case, hex encoded v4 fingerprint of the contacts key.
* @return {@link PubkeyElement} containing the requested public key. * @return {@link PubkeyElement} containing the requested public key.
* @throws InterruptedException *
* @throws PubSubException.NotALeafNodeException * @throws InterruptedException if we get interrupted.
* @throws SmackException.NoResponseException * @throws SmackException in case the node cannot be fetched.
* @throws SmackException.NotConnectedException
* @throws XMPPException.XMPPErrorException * @throws XMPPException.XMPPErrorException
* @throws PubSubException.NotAPubSubNodeException
*/ */
public static PubkeyElement fetchPubkey(XMPPConnection connection, BareJid contact, OpenPgpV4Fingerprint v4_fingerprint) public static PubkeyElement fetchPubkey(XMPPConnection connection, BareJid contact, OpenPgpV4Fingerprint v4_fingerprint)
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException, throws InterruptedException, SmackException, XMPPException.XMPPErrorException {
SmackException.NotConnectedException, XMPPException.XMPPErrorException,
PubSubException.NotAPubSubNodeException {
PubSubManager pm = PubSubManager.getInstance(connection, contact); PubSubManager pm = PubSubManager.getInstance(connection, contact);
LeafNode node = pm.getLeafNode(PEP_NODE_PUBLIC_KEY(v4_fingerprint)); LeafNode node = getOpenLeafNode(pm, PEP_NODE_PUBLIC_KEY(v4_fingerprint));
List<PayloadItem<PubkeyElement>> list = node.getItems(1); List<PayloadItem<PubkeyElement>> list = node.getItems(1);
if (list.isEmpty()) { if (list.isEmpty()) {
@ -352,4 +347,69 @@ public class PubSubDelegate {
PubSubManager pm = PubSubManager.getInstance(connection); PubSubManager pm = PubSubManager.getInstance(connection);
pm.deleteNode(PEP_NODE_SECRET_KEY); pm.deleteNode(PEP_NODE_SECRET_KEY);
} }
/**
* Use reflection magic to get a {@link LeafNode} without doing a disco#info query.
* This method is useful for fetching nodes that are configured with the access model 'open', since
* some servers that announce support for that access model do not allow disco#info queries from contacts
* which are not subscribed to the node owner. Therefore this method fetches the node directly and puts it
* into the {@link PubSubManager}s node map.
*
* @see <a href="https://github.com/processone/ejabberd/issues/2483">Ejabberd bug tracker about the issue</a>
*
* @param pubSubManager pubsub manager
* @param nodeName name of the node
* @return leafNode
*
* @throws SmackException if something goes wrong with reflections.
* @throws PubSubException.NotALeafNodeException if the node is already in the nodeMap, but is NOT a LeafNode.
*/
@SuppressWarnings("unchecked")
public static LeafNode getOpenLeafNode(PubSubManager pubSubManager, String nodeName)
throws SmackException, PubSubException.NotALeafNodeException {
try {
// Get access to the PubSubManager's nodeMap
Field field = pubSubManager.getClass().getDeclaredField("nodeMap");
field.setAccessible(true);
// CHECKSTYLE:OFF
Map<String, Node> nodeMap = (Map) field.get(pubSubManager);
// CHECKSTYLE:ON
// Check, if the node already exists
Node existingNode = nodeMap.get(nodeName);
if (existingNode != null) {
if (existingNode instanceof LeafNode) {
// We already know that node
return (LeafNode) existingNode;
} else {
// Throw a new NotALeafNodeException, as the node is not a LeafNode.
// Again use reflections to access the exceptions constructor.
Constructor<PubSubException.NotALeafNodeException> exceptionConstructor =
PubSubException.NotALeafNodeException.class.getDeclaredConstructor(String.class, BareJid.class);
exceptionConstructor.setAccessible(true);
throw exceptionConstructor.newInstance(nodeName, pubSubManager.getServiceJid());
}
}
// Node does not exist. Create the node
Constructor<LeafNode> constructor;
constructor = LeafNode.class.getDeclaredConstructor(PubSubManager.class, String.class);
constructor.setAccessible(true);
LeafNode node = constructor.newInstance(pubSubManager, nodeName);
// Add it to the node map
nodeMap.put(nodeName, node);
// And return
return node;
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException |
NoSuchFieldException e) {
throw new SmackException("Using reflections to create a LeafNode and put it into PubSubManagers nodeMap failed.", e);
}
}
} }