/** * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.waveprotocol.wave.federation.xmpp; import com.google.inject.Inject; import com.google.inject.name.Named; import org.jivesoftware.whack.ExternalComponentManager; import org.waveprotocol.wave.federation.FederationSettings; import org.xmpp.component.Component; import org.xmpp.component.ComponentException; import org.xmpp.component.ComponentManager; import org.xmpp.packet.JID; import org.xmpp.packet.Packet; import java.util.LinkedList; import java.util.Queue; import java.util.logging.Logger; /** * Talks to a XMPP server using the Jabber Component Protocol (XEP-0114). * * Implements {@link OutgoingPacketTransport} allowing users to send packets, * and accepts an {@link IncomingPacketHandler} which can process incoming * packets. * * @author thorogood@google.com (Sam Thorogood) */ public class ComponentPacketTransport implements Component, OutgoingPacketTransport { private static final Logger LOG = Logger.getLogger(ComponentPacketTransport.class.getCanonicalName()); private final IncomingPacketHandler handler; private final String componentName; private final String serverDomain; private final String serverSecret; private final String serverAddress; private final int serverPort; // Contains packets queued but not sent (while offline). private final Queue<Packet> queuedPackets; // Object used to lock around online/offline state changes. private final Object connectionLock = new Object(); private ExternalComponentManager componentManager = null; private boolean connected = false; @Inject public ComponentPacketTransport(IncomingPacketHandler handler, @Named(FederationSettings.XMPP_COMPONENT_NAME) String componentName, @Named(FederationSettings.XMPP_SERVER_HOSTNAME) String serverDomain, @Named(FederationSettings.XMPP_SERVER_SECRET) String serverSecret, @Named(FederationSettings.XMPP_SERVER_IP) String serverAddress, @Named(FederationSettings.XMPP_SERVER_PORT) int serverPort) { this.handler = handler; this.componentName = componentName; this.serverDomain = serverDomain; this.serverSecret = serverSecret; this.serverAddress = serverAddress; this.serverPort = serverPort; queuedPackets = new LinkedList<Packet>(); } /** * Bind the component to the XMPP server. * * @throws ComponentException if the component couldn't talk to the server */ public void run() throws ComponentException { componentManager = new ExternalComponentManager(serverAddress, serverPort); componentManager.setDefaultSecretKey(serverSecret); componentManager.setServerName(serverDomain); // Register this component with the manager. componentManager.addComponent(componentName, this); } @Override public void sendPacket(Packet packet) { synchronized (connectionLock) { if (connected) { componentManager.sendPacket(this, packet); } else { queuedPackets.add(packet); } } } @Override public String getDescription() { return "Wave in a Box Server"; } @Override public String getName() { return componentName; } @Override public void initialize(JID jid, ComponentManager componentManager) { // TODO(thorogood): According to XEP-0114, the only valid JID here is the // same JID we attempt to connect to the XMPP server with. LOG.info("Initializing with JID: " + jid); } /** * {@inheritDoc} * * Pass the incoming on-the-wire packet onto the incoming handler. */ @Override public void processPacket(Packet packet) { handler.receivePacket(packet); } @Override public void shutdown() { synchronized (connectionLock) { LOG.info("Disconnected from XMPP server."); componentManager = null; connected = false; } } @Override public void start() { synchronized (connectionLock) { connected = true; LOG.info("Connected to XMPP server with JID: " + componentName + "." + serverDomain); // Send all queued outgoing packets. while (!queuedPackets.isEmpty()) { componentManager.sendPacket(this, queuedPackets.poll()); } } } }