예제 #1
0
		/**
	 * Processes IQ request stanzas (IQ stanzas of type <tt>get</tt> or
	 * <tt>set</tt>. This method will, in order:
	 * <p/>
	 * <ol>
	 * <li>check if the stanza is a valid request stanza. If not, an IQ stanza
	 * of type <tt>error</tt>, condition 'bad-request' is returned;</li>
	 * <li>process Service Discovery requests by calling
	 * {@link #handleDiscoInfo(IQ)} and {@link #handleDiscoItems(IQ)} where
	 * appropriate;</li>
	 * <li>call the abstract methods {@link #handleIQGet()} or
	 * {@link #handleIQSet()} if the above actions did not apply to the request.
	 * </li>
	 * </ol>
	 * <p/>
	 * Note that if this method returns <tt>null</tt>, an IQ stanza of type
	 * <tt>error</tt>, condition <tt>feature-not-implemented</tt> will be
	 * returned to the sender of the original request. This behavior can be
	 * disabled by setting the <tt>enforceIQResult</tt> argument in the
	 * constructor to <tt>false</tt>.
	 * <p/>
	 * Note that if this method throws an Exception, an IQ stanza of type
	 * <tt>error</tt>, condition 'internal-server-error' will be returned to the
	 * sender of the original request.
	 * <p/>
	 * Note that if you want to add or adjust functionality, you should
	 * <strong>not</strong> override this method. Instead, you probably want to
	 * override any of these methods: {@link #handleIQGet()},
	 * {@link #handleIQSet()}, {@link #handleDiscoInfo(IQ)} and/or
	 * {@link #handleDiscoItems(IQ)}
	 * 
	 * @param iq
	 *            The IQ request stanza.
	 * @return Response to the request, or null to indicate a
	 *         'feature-not-implemented' error.
	 */
		private sealed IQ processIQRequest(IQ iq)
		{
			log.Debug("(serving component '{}') Processing IQ "
			      + "request (packetId {}).", getName(), iq.getID());

			// IQ get (and set) stanza's MUST be replied to.
			XElement childElement = iq.getChildElement();
			string @namespace = null;
			if (childElement != null) {
				@namespace = childElement.getNamespaceURI();
			}
			if (@namespace == null) {
				log.Debug("(serving component '{}') Invalid XMPP "
				      + "- no child element or namespace in IQ "
				      + "request (packetId {})", getName(), iq.getID());
				// this isn't valid XMPP.
				IQ response = IQ.createResultIQ(iq);
				response.setError(Condition.bad_request);
				return response;
			}
			// check if this is a component for local users only.
			if (servesLocalUsersOnly() && !sentByLocalEntity(iq)) {
				log.Info("(serving component '{}') Returning "
				     + "'not-authorized' IQ error to a user from "
				     + "another domain: {}", getName(), iq.getFrom());
				log.Debug("(serving component '{}') Returning "
				      + "'not-authorized' IQ error to a user from "
				      + "another domain: {}", getName(), iq.toXML());
				IQ error = IQ.createResultIQ(iq);
				error.setError(Condition.not_authorized);
				return error;
			}
			Type type = iq.getType();
			if (type == Type.get) {
				if (NAMESPACE_DISCO_INFO.equals(@namespace)) {
					log.Trace("(serving component '{}') "
					      + "Calling #handleDiscoInfo() (packetId {}).",
					      getName(), iq.getID());
					return handleDiscoInfo(iq);
				} else if (NAMESPACE_DISCO_ITEMS.equals(@namespace)) {
					log.Trace("(serving component '{}') "
					      + "Calling #handleDiscoItems() (packetId {}).",
					      getName(), iq.getID());
					return handleDiscoItems(iq);
				} else if (NAMESPACE_XMPP_PING.equals(@namespace)) {
					log.Trace("(serving component '{}') "
					      + "Calling #handlePing() (packetId {}).", getName(), iq
					      .getID());
					return handlePing(iq);
				} else if (NAMESPACE_LAST_ACTIVITY.equals(@namespace)) {
					log.Trace("(serving component '{}') "
					      + "Calling #handleLastActivity() (packetId {}).", getName(), iq
					      .getID());
					return handleLastActivity(iq);
				} else if (NAMESPACE_ENTITY_TIME.equals(@namespace)) {
					log.Trace("(serving component '{}') "
					      + "Calling #handleEntityTime() (packetId {}).", getName(), iq
					      .getID());
					return handleEntityTime(iq);
				} else {
					return handleIQGet(iq);
				}
			}
			if (type == Type.set) {
				return handleIQSet(iq);
			}
			// If by now we didn't do anything to the packet, we don't know what to
			// do with this. Return error (as it is a SET or GET stanza, which MUST
			// be replied to).
			return null;
		}
예제 #2
0
		/**
	 * This method applies default processing to received IQ stanzas. This
	 * method:
	 * <p/>
	 * <ul>
	 * <li>calls methods to process IQ requests (type <tt>get</tt> and
	 * <tt>set</tt>). If no response to these request are returned, this method
	 * will respond to the request with an IQ stanza of type <tt>error</tt>,
	 * containing an error condition <tt>feature-not-implemented</tt> (this
	 * behavior can be disabled by setting the <tt>enforceIQResult</tt> argument
	 * in the constructor to <tt>false</tt>);</li>
	 * <li>calls methods to process IQ results (type <tt>result</tt> and
	 * <tt>error</tt>). No response to these stanzas are expected;</li>
	 * <li>returns an IQ stanza of type error, condition 'internal-server-error'
	 * if the processing of an IQ request (type <tt>get</tt> or <tt>set</tt>)
	 * resulted in an Exception being thrown.</li>
	 * </ul>
	 * <p/>
	 * Note that if you want to add or adjust functionality, you should
	 * <strong>not</strong> override this method. Instead, you probably want to
	 * override any of these methods: {@link #handleIQGet()},
	 * {@link #handleIQSet()}, {@link #handleIQResult(IQ)},
	 * {@link #handleIQError(IQ)} {@link #handleDiscoInfo(IQ)} and/or
	 * {@link #handleDiscoItems(IQ)}
	 * 
	 * @param iq
	 *            The IQ stanza that was received by this component.
	 */
		private sealed void processIQ(IQ iq)
		{
			log.Debug("(serving component '{}') Processing IQ (packetId {}): {}",
			      new Object[] {getName(), iq.getID(), iq.toXML() });

			IQ response = null;
			Type type = iq.getType();
			try {
				switch (type) {

					case get: // intended fall-through
					case set:
						// cache the id, to prevent the extending implementation from
						// modifying it.
						String requestID = iq.getID();
						response = processIQRequest(iq);
						// validate the response IQ stanza.
						if (response == null) {
							// A request (IQ type 'get' or 'set') MUST be responded to.
							// If no response was generated, create an 'error' type
							// response.
							if (enforceIQResult) {
								response = IQ.createResultIQ(iq);
								response.setError(Condition.feature_not_implemented);
							}
						} else {
							// responses MUST be of type 'result' or 'error'. Everything
							// else is invalid.
							if (!response.isResponse()) {
								throw new IllegalStateException("Responses to IQ "
								                        + "of type <tt>get</tt> or <tt>set</tt> can "
								                        + "only be IQ stanza's of type <tt>error</tt> "
								                        + "or <tt>result</tt>. The response to this "
								                        + "packet was incorrect: " + iq.toXML()
								                        + ". The response was: " + response.toXML());
							}
							// responses must have the same packet ID as the request
							if (!requestID.equals(response.getID())) {
								throw new IllegalStateException("The response to "
								                        + "an request IQ must have the same packet "
								                        + "ID. If this was done intentionally, "
								                        + "#send(Packet) should have been used "
								                        + "instead. The response to this packet "
								                        + "was incorrect: " + iq.toXML()
								                        + ". The response was: " + response.toXML());
							}
							log.debug("(serving component '{}') Responding to IQ (packetId {}) with: {}", new Object[] { getName(), iq.getID(), response.toXML() }); 
						}
						break;

					case result:
						if (servesLocalUsersOnly() && !sentByLocalEntity(iq)) {
							log.info("(serving component '{}') Dropping IQ "
							 + "stanza sent by a user from another domain: {}",
							 getName(), iq.getFrom());
							log.debug("(serving component '{}') Dropping IQ "
							  + "stanza sent by a user from another domain: {}",
							  getName(), iq.toXML());
							return;
						}
						handleIQResult(iq);
						break;

					case error:
						if (servesLocalUsersOnly() && !sentByLocalEntity(iq)) {
							log.info("(serving component '{}') Dropping IQ "
							 + "stanza sent by a user from another domain: {}",
							 getName(), iq.getFrom());
							log.debug("(serving component '{}') Dropping IQ "
							  + "stanza sent by a user from another domain: {}",
							  getName(), iq.toXML());
							return;
						}
						handleIQError(iq);
						break;
				}
			} catch (Exception ex) {
				log.warn("(serving component '" + getName()
				     + "') Unexpected exception while processing IQ stanza: "
				     + iq.toXML(), ex);
				if (iq.isRequest()) {
					// if the received IQ stanza was a 'get' or 'set' request,
					// return an error, as some kind of response MUST be sent back
					// to those stanzas.
					response = IQ.createResultIQ(iq);
					response.setError(Condition.internal_server_error);
				}
			}
			// send the response, if there's any.
			if (response != null) {
				send(response);
			}
		}