/** * Checks if the given {@linkplain JID} supports the requested feature. The JID may be non * resource qualified in which case all presences belonging to that JID are checked. * * <p>This method does <b>not</b> perform any I/O operation and will return immediately. * * <p><b>Please note the return value: <code>if(isFeatureSupported(foo, bar)) ... </code> is * likely to produce a {@link NullPointerException NPE}.</b> * * @param jid {@link JID} to query support for * @param namespace the namespace of the feature * @return <code>true</code> if the given feature is supported, <code>false</code> if it is not * supported or <b><code>null</code> </b> if no information is available * @see #queryFeatureSupport(JID, String, boolean) */ public Boolean isFeatureSupported(final JID jid, final String namespace) { checkJID(jid); Boolean supported = null; final List<JID> jidsToQuery = new ArrayList<JID>(); if (jid.isBareJID()) jidsToQuery.addAll(rosterTracker.getAvailablePresences(jid)); else jidsToQuery.add(jid); for (JID rqJID : jidsToQuery) { DiscoverInfoWrapper info = cache.get(rqJID.toString()); if (info == null) continue; DiscoverInfo disco = info.item; if (disco == null) continue; supported = disco.containsFeature(namespace); if (supported) break; } return supported; }
/** Adds the {@link EnterXMPPAccountWizardPage}'s account data to the {@link XMPPAccountStore}. */ private void addXMPPAccount() { if (!enterXMPPAccountWizardPage.isXMPPAccountCreated()) { JID jid = enterXMPPAccountWizardPage.getJID(); String username = jid.getName(); String password = enterXMPPAccountWizardPage.getPassword(); String domain = jid.getDomain().toLowerCase(); String server = enterXMPPAccountWizardPage.getServer(); int port; if (enterXMPPAccountWizardPage.getPort().length() != 0) port = Integer.valueOf(enterXMPPAccountWizardPage.getPort()); else port = 0; boolean useTLS = enterXMPPAccountWizardPage.isUsingTLS(); boolean useSASL = enterXMPPAccountWizardPage.isUsingSASL(); accountStore.createAccount(username, password, domain, server, port, useTLS, useSASL); } if (accountStore.getAllAccounts().size() == 1 && store.getBoolean(PreferenceConstants.AUTO_CONNECT)) ThreadUtils.runSafeAsync( "dpp-connect-demand", LOG, new Runnable() { @Override public void run() { connectionHandler.connect(accountStore.getActiveAccount(), false); } }); }
/** * Perform a service discovery and check if the given feature is among the features supported by * the given recipient. All registered listeners will be notified about the result. * * @param jid A RQ-JID (user@host/resource) of the user to query support for or a non RQ-JID to * query all presences for this JID. * @blocking This method blocks until the ServiceDiscovery returns. * @reentrant This method can be called concurrently. * @caching If results are available in the cache, they are used instead of querying the server. */ private Boolean queryFeatureSupport(JID jid, String namespace) { Boolean supported = null; checkJID(jid); DiscoverInfoWrapper wrapper; final List<JID> jidsToQuery = new ArrayList<JID>(); if (jid.isBareJID()) jidsToQuery.addAll(rosterTracker.getAvailablePresences(jid)); else jidsToQuery.add(jid); for (JID rqJID : jidsToQuery) { // add dummy synchronized (cache) { wrapper = cache.get(rqJID.toString()); if (wrapper == null) { wrapper = new DiscoverInfoWrapper(); cache.put(rqJID.toString(), wrapper); } } DiscoverInfo disco = null; // wait if there is already a discovery for the JID in progress synchronized (wrapper) { if (wrapper.isAvailable()) disco = wrapper.item; else { disco = wrapper.item = performServiceDiscovery(rqJID); if (disco != null) LOG.debug("Inserted DiscoveryInfo into Cache for: " + rqJID); } } // Null means that the discovery failed if (disco == null) { // and so we do not know if the feature is supported // notifyFeatureSupportUpdated(jid, namespace, false); continue; } notifyFeatureSupportUpdated(rqJID, namespace, disco.containsFeature(namespace)); /* * loop through all presence regardless if we already know that the * feature is supported to notify the listener for every current * presence */ if (supported != null) supported |= disco.containsFeature(namespace); else supported = disco.containsFeature(namespace); } return supported; }
/** * Perform a ServiceDiscovery [1] and check if the given resource is among the features supported * by the given recipient. * * <p>[1] XEP-0030 http://xmpp.org/extensions/xep-0030.html * * @param jid The JID must have a resource identifier (user@host/resource), otherwise you get a * blame StackTrace in your logs. * @return DiscoverInfo from recipient or null if an XMPPException was thrown. * @blocking This method blocks until the ServiceDiscovery returns. * @reentrant This method can be called concurrently. * @nonCaching This method does not use a cache, but queries the server directly. */ private DiscoverInfo performServiceDiscovery(final JID jid) { if (jid.isBareJID()) { LOG.warn( "cannot perform service discovery on a non resource qualified jid: " + jid.toString(), new StackTrace()); return null; } final Connection connection = connectionService.getConnection(); if (connection == null) { LOG.warn("cannot not perform a service discovery because not connected to a XMPP server"); return null; } ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); try { return sdm.discoverInfo(jid.toString()); } catch (XMPPException e) { LOG.warn( "Service Discovery failed on recipient " + jid.toString() + " server: " + connection.getHost(), e); /* * FIXME handle timeouts and error conditions differently ! see * http://xmpp.org/extensions/xep-0030.html#errors */ return null; } }
/** * Returns the RQ-JID of given plain JID supporting the feature of the given name-space if * available, otherwise null. * * <p>If not in the cache then a blocking cache update is performed. * * @param jid The JID of the user to find a supporting presence for. The JID can be resource * qualified in which case the resource is stripped, before performing the look-up. * @blocking This method blocks until the ServiceDiscovery returns. * @reentrant This method can be called concurrently. * @caching If results are available in the cache, they are used instead of querying the server. */ public JID getSupportingPresence(final JID jid, final String namespace) { checkJID(jid); for (Presence presence : rosterTracker.getPresences(jid.getBareJID())) { if (!presence.isAvailable()) continue; String rjid = presence.getFrom(); if (rjid == null) { LOG.error("presence.getFrom() is null"); continue; } JID jidToCheck = new JID(rjid); Boolean supported = queryFeatureSupport(jidToCheck, namespace); if (supported != null && supported) return jidToCheck; } return null; }
protected void updatePageCompletion() { JID ownJid = connectionService.getJID(); JID foreignJid = getContact(); if (foreignJid.isValid() && !foreignJid.equals(ownJid) && !foreignJid.isResourceQualifiedJID()) { /* * Page is complete */ wasJIDValid = true; Roster roster = connectionService.getRoster(); if (roster != null && roster.contains(foreignJid.getBase())) { setMessage( Messages.roster_alreadyadded_errorMessage + "\n" + Messages.wizard_finish_noeffect, // $NON-NLS-1$ IMessageProvider.INFORMATION); isContactAlreadyAdded = true; } else { setMessage(DESCRIPTION); isContactAlreadyAdded = false; } setErrorMessage(null); setPageComplete(true); } else { /* * Page is incomplete */ if (foreignJid.equals(ownJid)) { setErrorMessage(Messages.roster_addself_errorMessage); } else if (wasJIDValid) { setErrorMessage(Messages.jid_format_errorMessage); } setPageComplete(false); } }
private void checkJID(JID jid) { if (jid == null) throw new NullPointerException("jid is null"); if (!jid.isValid()) throw new IllegalArgumentException("jid is not valid: " + jid); }
private static String toConnectionIDToken(String connectionIdentifier, String mode, JID jid) { if (connectionIdentifier == null) connectionIdentifier = DEFAULT_CONNECTION_ID; return connectionIdentifier + ":" + mode + ":" + jid.toString(); }
private IByteStreamConnection connectInternal(String connectionID, JID peer) throws IOException { IByteStreamConnection connection = null; final String connectionIDToken = toConnectionIDToken(connectionID, OUT, peer); synchronized (currentOutgoingConnectionEstablishments) { if (!currentOutgoingConnectionEstablishments.contains(connectionIDToken)) { connection = getCurrentConnection(connectionID, peer); if (connection == null) currentOutgoingConnectionEstablishments.add(connectionIDToken); } if (connection != null) return connection; } connectLock.lock(); try { connection = getCurrentConnection(connectionID, peer); if (connection != null) return connection; JID connectionJID = currentLocalJID; if (connectionJID == null) throw new IOException("not connected to a XMPP server"); ArrayList<ITransport> transportModesToUse = new ArrayList<ITransport>(availableTransports); LOG.debug( "currently used IP addresses for Socks5Proxy: " + Arrays.toString(Socks5Proxy.getSocks5Proxy().getLocalAddresses().toArray())); for (ITransport transport : transportModesToUse) { LOG.info( "establishing connection to " + peer.getBase() + " from " + connectionJID + " using " + transport); try { connection = transport.connect(connectionID, peer); break; } catch (IOException e) { LOG.error(peer + " failed to connect using " + transport + ": " + e.getMessage(), e); } catch (InterruptedException e) { IOException io = new InterruptedIOException("connecting cancelled: " + e.getMessage()); io.initCause(e); throw io; } catch (Exception e) { LOG.error( peer + " failed to connect using " + transport + " because of an unknown error: " + e.getMessage(), e); } } if (connection != null) { byteStreamConnectionListener.connectionChanged(connectionID, peer, connection, false); return connection; } throw new IOException("could not connect to: " + peer); } finally { synchronized (currentOutgoingConnectionEstablishments) { currentOutgoingConnectionEstablishments.remove(connectionIDToken); } connectLock.unlock(); } }