/src/main/java/com/atlassian/confluence/extra/impresence2/reporter/JabberPresenceReporter.java
Java | 314 lines | 234 code | 44 blank | 36 comment | 30 complexity | cac00dde6228b360d599005437c76b26 MD5 | raw file
- /*
- * Copyright (c) 2006, Atlassian Software Systems Pty Ltd All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
- * following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
- * disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
- * the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the
- * name of "Atlassian" nor the names of its contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package com.atlassian.confluence.extra.impresence2.reporter;
- import com.atlassian.bandana.BandanaManager;
- import com.atlassian.confluence.setup.bandana.ConfluenceBandanaContext;
- import com.atlassian.renderer.v2.RenderUtils;
- import com.atlassian.renderer.v2.macro.ResourceAware;
- import org.apache.commons.lang.StringUtils;
- import org.jivesoftware.smack.ConnectionConfiguration;
- import org.jivesoftware.smack.Roster;
- import org.jivesoftware.smack.RosterEntry;
- import org.jivesoftware.smack.XMPPConnection;
- import org.jivesoftware.smack.XMPPException;
- import org.jivesoftware.smack.packet.Presence;
- import org.jivesoftware.smack.packet.RosterPacket;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.io.IOException;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * This class interfaces with Jabber (XMPP) IM services.
- */
- public class JabberPresenceReporter extends LoginPresenceReporter implements ResourceAware
- {
- private static final String DOMAIN_PREFIX = "extra.im.domain.";
- private static final String PORT_PREFIX = "extra.im.port.";
- private static final Logger logger = LoggerFactory.getLogger(JabberPresenceReporter.class);
- private static final Map<Presence.Mode, String> STATUS_MAP = Collections.unmodifiableMap(
- new HashMap<Presence.Mode, String>()
- {
- {
- put(Presence.Mode.available, "im_available");
- put(Presence.Mode.away, "im_away");
- put(Presence.Mode.available, "im_free_chat");
- put(Presence.Mode.dnd, "im_dnd");
- put(Presence.Mode.xa, "im_away");
- }
- }
- );
- public static final String KEY = "jabber";
- public static final String DEFAULT_JABBER_DOMAIN = "chat.example.com";
- public static final int DEFAULT_JABBER_PORT = 5222;
- private String resourcePath;
- private XMPPConnection xmppConnection;
- private BandanaManager bandanaManager;
- public void setBandanaManager(BandanaManager bandanaManager)
- {
- super.setBandanaManager(bandanaManager);
- this.bandanaManager = bandanaManager;
- }
- public String getKey()
- {
- return KEY;
- }
- public String getName()
- {
- return getText("presencereporter." + getKey() + ".name");
- }
- public String getServiceHomepage()
- {
- return getText("presencereporter." + getKey() + ".servicehomepage");
- }
- public String getPresenceXHTML(String id, boolean outputId) throws IOException, PresenceException
- {
- final XMPPConnection xmppConnection = checkCreateConnection();
- if (xmppConnection.isAuthenticated())
- {
- /* roster won't be null, because we've got an authentication check above */
- final Roster roster = xmppConnection.getRoster();
- if (!roster.contains(id))
- {
- try
- {
- roster.createEntry(id, id, null);
- return RenderUtils.error(getText("presencereporter." + getKey() + ".message.waitinbuddyaccept",
- new Object[]
- { id }));
- }
- catch (XMPPException e)
- {
- logger.error("Unable to add " + id + " to contact list of " + getId(), e);
- throw new PresenceException(getText("presencereporter." + getKey() + ".error.addbuddy",
- new Object[]
- { id, getId() }), e);
- }
- }
- else
- {
- final RosterEntry entry = roster.getEntry(id);
- if (RosterPacket.ItemStatus.SUBSCRIPTION_PENDING.equals(entry.getStatus()))
- {
- return getPresenceLink(id, "im_invisible", getText("presence.link.waitingunblock"), outputId);
- }
- else
- {
- final Presence presence = getPresence(id, roster);
- if (null != presence)
- {
- Presence.Mode presenceMode = presence.getMode();
- // Sometimes, available is sent with a null mode but available type.
- if (null == presenceMode && presence.getType().equals(Presence.Type.available))
- {
- presenceMode = Presence.Mode.available;
- }
- return getPresenceLink(id, getStatusImage(presenceMode), String.valueOf(presenceMode), outputId);
- }
- else
- {
- return getPresenceLink(id, "im_invisible", getText("presence.link.intermediate"), outputId);
- }
- }
- }
- }
- else
- {
- if (xmppConnection.isConnected())
- {
- xmppConnection.disconnect(); /* Since we failed to authenticate, we'll close the connection */
- }
- return RenderUtils.error(getText("presencereporter." + getKey() + ".error.login"));
- }
- }
- protected XMPPConnection checkCreateConnection()
- {
- if (null == xmppConnection || !xmppConnection.isConnected())
- {
- /* Close of the stale connction */
- if (null != xmppConnection)
- {
- xmppConnection.disconnect();
- }
- try
- {
- if (logger.isDebugEnabled())
- {
- logger.debug("Creating a new XMPPConnection for: " + getKey());
- }
- String trimmedId = getTrimmedId(getId());
- String password = getPassword();
- int lastIndexOfAlias = getId().lastIndexOf("@");
- String userDomainName;
- // If there's an '@' in the trimmed ID and it is not the last character, then we should use
- // that as the domain name. Otherwise, just use the jabber domain.
- if (-1 != lastIndexOfAlias && lastIndexOfAlias < getId().length() - 1)
- {
- userDomainName = getId().substring(lastIndexOfAlias + 1);
- }
- else
- {
- userDomainName = getDomain();
- }
- xmppConnection = createXmppConnection(userDomainName);
- xmppConnection.connect();
- xmppConnection.login(trimmedId, password);
- }
- catch (XMPPException xmppe)
- {
- logger.error("Unable to establish connection to " + getKey(), xmppe);
- }
- }
- return xmppConnection;
- }
- XMPPConnection createXmppConnection(String usernameDomain)
- {
- return new XMPPConnection(new ConnectionConfiguration(getDomain(), getPort(), usernameDomain));
- }
- private String getStatusImage(Presence.Mode mode)
- {
- final String img;
- if (null != mode && STATUS_MAP.containsKey(mode))
- {
- img = STATUS_MAP.get(mode);
- }
- else
- {
- img = "im_invisible";
- }
- if (null == img)
- {
- logger.info("Unrecognised " + getKey() + " status: " + mode);
- }
- return img;
- }
- /**
- * Removes the domain suffix from the specified ID.
- *
- * @param id
- * The ID to trim.
- * @return The ID with the domain suffix removed, if any. Otherwise, the return value would be the
- * same as the one specified to this method.
- */
- private String getTrimmedId(String id)
- {
- if (id.contains("@"))
- {
- id = id.substring(0, id.indexOf("@"));
- }
- return id;
- }
- private Presence getPresence(final String targetAddress, Roster roster)
- {
- if (logger.isDebugEnabled())
- {
- logger.debug("Roster for " + getId() + " is: " + roster);
- }
- if (null != roster)
- {
- return roster.getPresence(targetAddress);
- }
- else
- {
- return null;
- }
- }
- public String getResourcePath()
- {
- return resourcePath;
- }
- public void setResourcePath(String resourcePath)
- {
- this.resourcePath = resourcePath;
- }
- protected String getPresenceURL(String id)
- {
- return "jabber:" + id;
- }
- public String getDomain()
- {
- return StringUtils.defaultIfEmpty(
- (String) bandanaManager.getValue(ConfluenceBandanaContext.GLOBAL_CONTEXT, DOMAIN_PREFIX + getKey()),
- DEFAULT_JABBER_DOMAIN
- );
- }
- public void setDomain(String domain)
- {
- bandanaManager.setValue(ConfluenceBandanaContext.GLOBAL_CONTEXT, DOMAIN_PREFIX + getKey(), StringUtils.defaultString(StringUtils.trim(domain)));
- }
- public Integer getPort()
- {
- Object portObj = bandanaManager.getValue(ConfluenceBandanaContext.GLOBAL_CONTEXT, PORT_PREFIX + getKey());
- return null == portObj ? DEFAULT_JABBER_PORT : new Integer(portObj.toString());
- }
- public void setPort(Integer port)
- {
- if (null == port)
- bandanaManager.removeValue(ConfluenceBandanaContext.GLOBAL_CONTEXT, PORT_PREFIX + getKey());
- else
- bandanaManager.setValue(ConfluenceBandanaContext.GLOBAL_CONTEXT, PORT_PREFIX + getKey(), port.toString());
- }
- }