Commit e62ea2df authored by Derek DeMoro's avatar Derek DeMoro Committed by derek

Refactoring work.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@581 b35dd754-fafc-0310-a699-88a17e54d16e
parent 44c82d5d
......@@ -84,8 +84,13 @@ public class Channel<T extends Packet> {
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
try {
packet.getOriginatingSession().getConnection().close();
try {
Session session = SessionManager.getInstance().getSession(packet.getFrom());
session.getConnection().close();
}
catch (SessionNotFoundException e1) {
e1.printStackTrace();
}
}
catch (UnauthorizedException e1) {
// do nothing
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
/**
* Central manager for JMX MBeans.
*
* @author Iain Shigeoka
*/
public class MBeanManager {
// private static MBeanServer server;
static {
// server = MBeanServerFactory.createMBeanServer();
// For now, we'll run an HTMLAdaptor server so that we easily interact with
// the MBean server.
// int portNumber = 8090;
// HtmlAdaptorServer html = new HtmlAdaptorServer(portNumber);
// ObjectName html_name = null;
// try {
// html_name = new ObjectName("Adaptor:name=html,port=" + portNumber);
// server.registerMBean(html, html_name);
// }
// catch (Exception e) {
// Log.error(LocaleUtils.getLocalizedString("admin.error"),e);
// }
// html.start();
}
/**
* Register an MBean with the MBeanServer.
*
* @param object the MBean to register.
* @param objectName a valid MBean object name.
*/
public static void registerMBean(Object object, String objectName) {
try {
// server.registerMBean(object, new ObjectName(objectName));
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
private MBeanManager() {
}
}
......@@ -12,80 +12,147 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.util.Log;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.PacketError;
/**
* <p>Configures and controls the server's offline message storage strategy.</p>
* <p>There are several ways to handle messages sent to offline users. The offline strategy
* centralizes these options and their configuration. In addition, internal components can
* use the strategy without knowing or caring about the actual behavior specified.</p>
* <p>The valid strategies currently supported include:</p>
* <ul>
* <li>Type.bounce - bounce all messages back to the sender. This is one of two ways
* to support offline messages without actually storing them. This is the tactic
* used by AOL.
* </li>
* <li>Type.drop - drop all messages sent to offline users. This is the second of two
* ways to support offline messages without actually storing them. It's much less
* user friendly, but provides better privacy (bounced messages can be used to probe
* the offline/online presence of another user without subscribing to their presence).
* </li>
* <li>Type.store - unconditionally store all messages for later delivery. Ideal for small
* deployments or where you are sure people won't abuse offline message storage.
* </li>
* <li>Type.store_and_bounce - Stores offline messages for later delivery until the quota
* is reached. When the quota is exceeded, all subsequent messages are bounced (see BOUNCE).
* </li>
* <li>Type.store_and_drop - Stores offline messages for later delivery until the quota
* is reached. When the quota is exceeded, all subsequent messages are silently dropped
* (see DROP).
* </li>
* </ul>
* <p>Implements the strategy as a basic server module.</p>
*
* @author Iain Shigeoka
*/
public interface OfflineMessageStrategy {
public class OfflineMessageStrategy extends BasicModule {
/**
* Returns the storage quota for offline messages in bytes per user. The quota
* limit only has significance if the strategy type is {@link Type#store_and_bounce}
* or {@link Type#store_and_drop}.
*
* @return the quota in bytes per user for offline message storage.
*/
int getQuota();
private static int quota = -1;
private static Type type = Type.store;
private SessionManager sessionManager;
/**
* Sets the storage quota for offline messages in bytes per user. The quota
* limit only has significance if the strategy type is {@link Type#store_and_bounce}
* or {@link Type#store_and_drop}.
*
* @param quota the quota in bytes per user for offline message storage.
*/
void setQuota(int quota);
/**
* Returns the storage strategy type.
*
* @return the strategy type in use.
*/
Type getType();
public PacketFactory packetFactory;
public XMPPServer xmppServer;
public PacketDeliverer deliverer;
public OfflineMessageStore messageStore;
/**
* Sets the storage strategy type.
*
* @param type the strategy type to use.
*/
void setType(Type type);
public OfflineMessageStrategy() {
super("Offline Message Strategy");
/**
* Store the given message for an offline user. The strategy will
* take the appropriate action based on it's type.
*
* @param message the message to handle.
*/
void storeOffline(Message message) throws UnauthorizedException, UserNotFoundException;
sessionManager = SessionManager.getInstance();
}
public int getQuota() {
return quota;
}
public void setQuota(int quota) {
OfflineMessageStrategy.quota = quota;
JiveGlobals.setProperty("xmpp.offline.quota", Integer.toString(quota));
}
public OfflineMessageStrategy.Type getType() {
return type;
}
public void setType(OfflineMessageStrategy.Type type) {
if (type == null) {
throw new IllegalArgumentException();
}
OfflineMessageStrategy.type = type;
JiveGlobals.setProperty("xmpp.offline.type", type.toString());
}
public void storeOffline(Message message) throws UnauthorizedException, UserNotFoundException {
if (message != null) {
Session senderSession = null;
try {
senderSession = sessionManager.getSession(message.getFrom());
}
catch (SessionNotFoundException e) {
Log.error(e);
}
JID sender = senderSession.getAddress();
// server messages and anonymous messages can be silently dropped
if (sender == null || sender.getNode() == null || senderSession == null) {
// silently drop the server message
}
else {
if (type == Type.bounce) {
bounce(message);
}
else if (type == Type.store) {
store(message);
}
else if (type == Type.store_and_bounce) {
if (underQuota(message)) {
store(message);
}
else {
bounce(message);
}
}
else if (type == Type.store_and_drop) {
if (underQuota(message)) {
store(message);
}
}
}
}
}
private boolean underQuota(Message message) {
return quota > messageStore.getSize(message.getTo().getNode()) + message.toXML().length();
}
private void store(Message message) {
messageStore.addMessage(message);
}
public void initialize(Container container) {
super.initialize(container);
String quota = JiveGlobals.getProperty("xmpp.offline.quota");
if (quota != null && quota.length() > 0) {
OfflineMessageStrategy.quota = Integer.parseInt(quota);
}
String type = JiveGlobals.getProperty("xmpp.offline.type");
if (type != null && type.length() > 0) {
OfflineMessageStrategy.type = Type.valueOf(type);
}
}
private void bounce(Message message) {
// Generate a rejection response to the sender
try {
Message response = packetFactory.getMessage();
response.setTo(message.getFrom());
response.setFrom(xmppServer.createJID(null, null));
response.setBody("Message could not be delivered to " + message.getTo() + ". User is offline or unreachable.");
Session session = sessionManager.getSession(message.getFrom());
session.getConnection().deliver(response);
Message errorResponse = message.createCopy();
errorResponse.setError(new PacketError(PacketError.Type.continue_processing, PacketError.Condition.item_not_found));
session.getConnection().deliver(errorResponse);
}
catch (Exception e) {
Log.error(e);
}
}
public TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(XMPPServer.class, "xmppServer");
trackInfo.getTrackerClasses().put(PacketFactory.class, "packetFactory");
trackInfo.getTrackerClasses().put(OfflineMessageStore.class, "messageStore");
return trackInfo;
}
/**
* Strategy types.
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.spi.AbstractFragment;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Element;
public class PayloadFragment extends AbstractFragment {
public PayloadFragment(String namespace, String name) {
this.namespace = namespace;
this.name = name;
}
public void send(XMLStreamWriter xmlSerializer, int version) throws XMLStreamException {
xmlSerializer.writeStartElement(name);
xmlSerializer.writeDefaultNamespace(namespace);
Iterator frags = getFragments();
while (frags != null && frags.hasNext()) {
((XMPPFragment)frags.next()).send(xmlSerializer, version);
}
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
PayloadFragment payload = new PayloadFragment(namespace, name);
Iterator frags = getFragments();
while (frags != null && frags.hasNext()) {
payload.addFragment((XMPPFragment)frags.next());
}
return payload;
}
/**
* <p>Converts the given fragment into a payload fragment.</p>
* <p>All sub-elements of the original fragment are broken out into separate
* MetaDataFragments. Currently only supports XMPPDOMFragment objects and their descendents.
* During conversion attributes of the root element is lost.</p>
*
* @param frag The fragment to convert (must be XMPPDOMFragment or descendent)
* @return The converted fragment with all sub-fragments broken up into separate fragments.
* @throws IllegalArgumentException If the given fragment does not implement XMPPDOMFragment
*/
public static PayloadFragment convertToPayload(XMPPFragment frag) throws IllegalArgumentException {
PayloadFragment payload = null;
if (frag instanceof XMPPDOMFragment) {
XMPPDOMFragment dom = (XMPPDOMFragment)frag;
payload = new PayloadFragment(dom.getNamespace(), dom.getName());
Iterator frags = dom.getRootElement().elementIterator();
while (frags.hasNext()) {
payload.addFragment(new MetaDataFragment((Element)frags.next()));
}
}
else {
throw new IllegalArgumentException();
}
return payload;
}
}
......@@ -11,6 +11,8 @@
package org.jivesoftware.messenger;
import org.xmpp.packet.Presence;
/**
* <p>Route presence packets throughout the server.</p>
* <p>Routing is based on the recipient and sender addresses. The typical
......
......@@ -65,6 +65,8 @@ public class SessionManager implements ConnectionCloseListener {
private static SessionManager singleton;
private static final Object LOCK = new Object();
private Map packetSessionMap = new HashMap();
/**
* Returns the singleton instance of <CODE>SessionManagerImpl</CODE>,
* <p/>
......@@ -147,7 +149,7 @@ public class SessionManager implements ConnectionCloseListener {
* and priority).
*/
private class SessionMap {
private HashMap resources = new HashMap();
private Map resources = new HashMap();
private LinkedList priorityList = new LinkedList();
/**
......@@ -461,13 +463,20 @@ public class SessionManager implements ConnectionCloseListener {
return hasRoute;
}
public Session getSession(JID address) throws UnauthorizedException, SessionNotFoundException {
/**
* Returns the session responsible for this JID.
* @param from the sender of the packet.
* @return the <code>Session</code> associated with the JID.
* @throws UnauthorizedException
* @throws SessionNotFoundException
*/
public Session getSession(JID from) throws UnauthorizedException, SessionNotFoundException {
Session session = null;
String resource = address.getResource();
String resource = from.getResource();
if (resource == null) {
throw new SessionNotFoundException();
}
String username = address.getNode();
String username = from.getNode();
if (username == null || "".equals(username)) {
anonymousSessionLock.readLock().lock();
try {
......@@ -496,6 +505,7 @@ public class SessionManager implements ConnectionCloseListener {
return session;
}
public Collection<Session> getSessions() {
List<Session> allSessions = new ArrayList<Session>();
copyUserSessions(allSessions);
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* <p>Manages transports to foreign systems.</p>
* <p>Some transports may represent local systems that act as a foreign server
* such as groupchat servers.</p>
*
* @author Iain Shigeoka
*/
public interface TransportManager {
}
......@@ -20,6 +20,7 @@ import org.jivesoftware.messenger.handler.*;
import org.jivesoftware.messenger.spi.*;
import org.jivesoftware.messenger.transport.TransportHandler;
import org.jivesoftware.messenger.user.spi.*;
import org.jivesoftware.messenger.user.OfflineMessageStrategy;
/**
* A bootstrap container to launch the Messenger XMPP server. This
......@@ -58,8 +59,7 @@ public class XMPPBootContainer extends BootstrapContainer {
PacketTransporterImpl.class.getName(),
PacketDelivererImpl.class.getName(),
TransportHandler.class.getName(),
OfflineMessageStrategyImpl.class.getName(),
DbOfflineMessageStore.class.getName()};
OfflineMessageStrategy.class.getName()};
}
protected String[] getStandardModuleNames() {
......
......@@ -29,7 +29,7 @@ import org.xmpp.packet.JID;
*
* @author Iain Shigeoka
*/
public interface XMPPServer extends XMPPServerMBean, Module {
public interface XMPPServer extends Module {
/**
* Obtain a snapshot of the server's status.
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger;
/**
* JMX MBean wrapper for the XMPP server.
*
* @author Iain Shigeoka
*/
public interface XMPPServerMBean {
}
......@@ -17,6 +17,10 @@ import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.AuditEvent;
import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.audit.Auditor;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Message;
import org.xmpp.packet.Presence;
import org.xmpp.packet.IQ;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
......@@ -57,7 +61,7 @@ public class AuditorImpl implements Auditor {
auditManager = manager;
}
public void audit(XMPPPacket packet) {
public void audit(Packet packet) {
if (auditManager.isEnabled()) {
if (packet instanceof Message) {
if (auditManager.isAuditMessage()) {
......@@ -108,10 +112,10 @@ public class AuditorImpl implements Auditor {
}
}
private void writePacket(XMPPPacket packet, boolean dropped) {
private void writePacket(Packet packet, boolean dropped) {
if (!closed) {
// Add to the logging queue this new entry that will be saved later
logQueue.add(new AuditPacket((XMPPPacket) packet.createDeepCopy(), dropped));
logQueue.add(new AuditPacket((Packet) packet.createDeepCopy(), dropped));
}
}
......@@ -229,14 +233,14 @@ public class AuditorImpl implements Auditor {
* queue that will be later processed (i.e. saved to the XML file).
*/
private class AuditPacket {
private XMPPPacket packet;
private Packet packet;
private String streamID;
private String sessionStatus;
private Date timestamp;
private boolean sending;
private boolean dropped;
public AuditPacket(XMPPPacket packet, boolean dropped) {
public AuditPacket(Packet packet, boolean dropped) {
this.packet = packet;
this.dropped = dropped;
this.timestamp = new Date();
......
......@@ -11,7 +11,7 @@
package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.forms.XDataForm;
import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
......@@ -62,7 +62,7 @@ public interface DiscoInfoProvider {
* @param senderJID the XMPPAddress of user that sent the disco info request.
* @return an XDataForm with the extended information about the entity or null if none.
*/
public abstract XDataForm getExtendedInfo(String name, String node, JID senderJID);
public abstract XDataFormImpl getExtendedInfo(String name, String node, JID senderJID);
/**
* Returns true if we can provide information related to the requested name and node. For
......
......@@ -19,6 +19,10 @@ import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.*;
import org.jivesoftware.messenger.user.spi.IQRosterItemImpl;
import org.xmpp.packet.Packet;
import org.xmpp.packet.JID;
import org.xmpp.packet.IQ;
import org.dom4j.Element;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.stream.XMLStreamException;
......@@ -83,10 +87,10 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
IQ returnPacket = null;
IQRoster roster = (IQRoster)packet;
XMPPAddress recipientJID = packet.getRecipient();
JID recipientJID = packet.getTo();
// The packet is bound for the server and must be roster management
if (recipientJID == null || recipientJID.getName() == null) {
if (recipientJID == null || recipientJID.getNode() == null) {
returnPacket = manageRoster(roster);
}
else { // The packet must be a roster removal from a foreign domain user
......@@ -110,20 +114,20 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
*/
private void removeRosterItem(IQRoster packet) throws
UnauthorizedException, XMLStreamException {
XMPPAddress recipientJID = packet.getRecipient();
XMPPAddress senderJID = packet.getSender();
JID recipientJID = packet.getTo();
JID senderJID = packet.getFrom();
try {
Iterator itemIter = packet.getRosterItems();
while (itemIter.hasNext()) {
RosterItem packetItem = (RosterItem)itemIter.next();
if (packetItem.getSubStatus() == RosterItem.SUB_REMOVE) {
Roster roster = userManager.getUser(recipientJID.getName()).getRoster();
Roster roster = userManager.getUser(recipientJID.getNode()).getRoster();
RosterItem item = roster.getRosterItem(senderJID);
roster.deleteRosterItem(senderJID);
item.setSubStatus(RosterItem.SUB_REMOVE);
item.setSubStatus(RosterItem.SUB_NONE);
XMPPPacket itemPacket = (XMPPPacket)packet.createDeepCopy();
Packet itemPacket = (Packet)packet.createDeepCopy();
sessionManager.userBroadcast(recipientJID.getName().toLowerCase(), itemPacket);
}
}
......@@ -199,13 +203,13 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
* Actual roster removal is done in the removeItem(Roster,RosterItem) method.
*
* @param roster The sender's roster.
* @param sender The XMPPAddress of the sender of the removal request
* @param sender The JID of the sender of the removal request
* @param item The removal item element
*/
private void removeItem(Roster roster, XMPPAddress sender, RosterItem item)
private void removeItem(Roster roster, JID sender, RosterItem item)
throws UnauthorizedException, XMLStreamException {
XMPPAddress recipient = item.getJid();
JID recipient = item.getJid();
// Remove recipient from the sender's roster
roster.deleteRosterItem(item.getJid());
// Forward set packet to the subscriber
......@@ -231,14 +235,15 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
* @param to The recipient address to use
* @return The forwarded packet generated
*/
private XMPPPacket createRemoveForward(XMPPAddress from, XMPPAddress to) throws UnauthorizedException {
private Packet createRemoveForward(JID from, JID to) throws UnauthorizedException {
IQ response = new IQ();
response.setFrom(from);
response.setTo(to);
response.setType(IQ.Type.set);
Element query = response.setChildElement("query", "jabber:iq:roster");
IQ response = packetFactory.getIQ();
response.setSender(from);
response.setRecipient(to);
response.setType(IQ.SET);
PayloadFragment query = new PayloadFragment("jabber:iq:roster", "query");
response.setChildFragment(query);
IQRosterItem responseItem = new IQRosterItemImpl(from);
responseItem.setSubStatus(RosterItem.SUB_REMOVE);
query.addFragment(responseItem);
......
......@@ -31,7 +31,7 @@ import java.util.*;
*
* @author Iain Shigeoka
*/
public class BasicServer extends BasicModule implements XMPPServer, BasicServerMBean {
public class BasicServer extends BasicModule implements XMPPServer {
private String name;
private Version version;
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.XMPPServerMBean;
/**
* JMX naming conventions dictate a properly named interface
* for static JMX MBeans.
*
* @author Iain Shigeoka
*/
public interface BasicServerMBean extends XMPPServerMBean {
}
......@@ -16,7 +16,7 @@ import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.XPPReader;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.spi.IQRosterImpl;
import org.jivesoftware.messenger.user.IQRoster;
import java.io.StringReader;
//import java.util.HashMap;
//import java.util.Iterator;
......@@ -72,7 +72,7 @@ public class PacketFactoryImpl extends BasicModule implements PacketFactory {
Document doc = XPPReader.parseDocument(xpp);
Element query = doc.getRootElement().element("query");
if (query != null && "jabber:iq:roster".equals(query.getNamespaceURI())) {
iq = new IQRosterImpl();
iq = new IQRoster();
((IQImpl)iq).parse(doc);
}
else {
......
......@@ -11,22 +11,183 @@
package org.jivesoftware.messenger.user;
import org.jivesoftware.messenger.IQ;
import java.util.Iterator;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.spi.IQRosterItemImpl;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.XPPReader;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
/**
* <p>An IQ packet representing an XMPP roster.</p>
* <p>Rosters are just standard iq with a 'query' sub-element
* containing zero or more RosterItem 'item' fragments.</p>
* A roster implemented against a JDBC database
*
* @author Iain Shigeoka
*/
public interface IQRoster extends IQ, Roster {
public class IQRoster extends IQ implements Roster {
private BasicIQRoster basicRoster = new BasicIQRoster();
/**
* <p>Parse the given XML document for Roster content.</p>
*
* @param doc The document to parse
* <p>Create an empty iq roster packet.</p>
*/
public void parse(Document doc);
}
\ No newline at end of file
public IQRoster() {
}
public String getChildNamespace() {
return "jabber:iq:roster";
}
public String getChildName() {
return "query";
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
try {
super.sendRoot(xmlSerializer, version, "iq", null);
xmlSerializer.setPrefix("", "jabber:iq:roster");
xmlSerializer.writeStartElement("query");
xmlSerializer.writeDefaultNamespace("jabber:iq:roster");
Iterator items = basicRoster.getRosterItems();
while (items.hasNext()) {
Object item = items.next();
if (item instanceof IQRosterItem) {
((IQRosterItem)item).send(xmlSerializer, version);
}
else {
new IQRosterItemImpl((RosterItem)item).send(xmlSerializer, version);
}
}
xmlSerializer.writeEndElement();
xmlSerializer.writeEndElement();
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
public void parse(Document doc) {
Element root = doc.getRootElement();
setTo(new JID(root.attributeValue("to")));
setType(Type.valueOf(root.attributeValue("type")));
setID(root.attributeValue("id"));
Iterator elements = root.elements().iterator();
while (elements.hasNext()) {
Element element = (Element)elements.next();
if ("query".equals(element.getName())) {
Iterator items = element.elementIterator("item");
while (items.hasNext()) {
try {
Element item = (Element)items.next();
RosterItem rosterItem = basicRoster.createRosterItem(new JID(item.attributeValue("jid")),
item.attributeValue("name"),
null);
rosterItem.setSubStatus("remove".equals(item.attributeValue("subscription")) ?
RosterItem.SUB_REMOVE : RosterItem.SUB_NONE);
Iterator groupElements = item.elementIterator("group");
while (groupElements.hasNext()) {
rosterItem.getGroups().add(((Element)groupElements.next()).getTextTrim());
}
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
catch (UserAlreadyExistsException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
}
}
public void parse(XMLStreamReader xpp) throws XMLStreamException {
// We're one past the root iq-element
int event = xpp.getEventType();
Document doc = null;
// The one query element or the error element
if (event == XMLStreamConstants.START_ELEMENT) {
if ("query".equals(xpp.getLocalName())) {
}
else {
// error, we'll punt and implement later
throw new XMLStreamException("Error packets not supported yet");
}
try {
doc = XPPReader.parseDocument(xpp);
this.setChildElement(doc.getRootElement().getName(), doc.getRootElement().getNamespaceURI());
}
catch (DocumentException e) {
throw new XMLStreamException();
}
}
while (event != XMLStreamConstants.END_ELEMENT) {
event = xpp.next();
}
}
// ##################################################################################
// Basic Roster usage - the downside of single inheritance
// ##################################################################################
private class BasicIQRoster extends BasicRoster {
protected RosterItem provideRosterItem(RosterItem item) throws UserAlreadyExistsException, UnauthorizedException {
return new IQRosterItemImpl(item);
}
protected RosterItem provideRosterItem(JID user, String nickname, List groups) throws UserAlreadyExistsException, UnauthorizedException {
return new IQRosterItemImpl(user, nickname, groups);
}
}
public boolean isRosterItem(JID user) {
return basicRoster.isRosterItem(user);
}
public Iterator getRosterItems() throws UnauthorizedException {
return basicRoster.getRosterItems();
}
public int getTotalRosterItemCount() throws UnauthorizedException {
return basicRoster.getTotalRosterItemCount();
}
public RosterItem getRosterItem(JID user)
throws UnauthorizedException, UserNotFoundException {
return basicRoster.getRosterItem(user);
}
public RosterItem createRosterItem(JID user)
throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(user);
}
public RosterItem createRosterItem(JID user, String nickname, List groups)
throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(user, nickname, groups);
}
public RosterItem createRosterItem(RosterItem item) throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(item);
}
public void updateRosterItem(RosterItem item)
throws UnauthorizedException, UserNotFoundException {
basicRoster.updateRosterItem(item);
}
public RosterItem deleteRosterItem(JID user) throws UnauthorizedException {
return basicRoster.deleteRosterItem(user);
}
}
......@@ -58,7 +58,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
}
public IQRoster getReset() throws UnauthorizedException {
IQRoster roster = new IQRosterImpl();
IQRoster roster = new IQRoster();
Iterator items = getRosterItems();
while (items.hasNext()) {
RosterItem item = (RosterItem)items.next();
......@@ -122,7 +122,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
item = rosterItemProvider.createItem(username, new BasicRosterItem(item));
// Broadcast the roster push to the user
IQRoster roster = new IQRosterImpl();
IQRoster roster = new IQRoster();
roster.setType(IQ.SET);
roster.createRosterItem(item);
broadcast(roster);
......@@ -155,7 +155,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
&& cachedItem.getAskStatus() == RosterItem.ASK_NONE)) {
try {
IQRoster roster = new IQRosterImpl();
IQRoster roster = new IQRoster();
roster.setType(IQ.SET);
roster.createRosterItem(cachedItem);
broadcast(roster);
......@@ -184,7 +184,7 @@ public class CachedRosterImpl extends BasicRoster implements CachedRoster {
try {
// broadcast the update to the user
IQRoster roster = new IQRosterImpl();
IQRoster roster = new IQRoster();
roster.setType(IQ.SET);
IQRosterItem iqItem = (IQRosterItem)roster.createRosterItem(user);
iqItem.setSubStatus(RosterItem.SUB_REMOVE);
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.user.spi;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.XPPReader;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.XMPPDOMFragment;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.spi.IQImpl;
import org.jivesoftware.messenger.user.*;
import java.util.Iterator;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
/**
* A roster implemented against a JDBC database
*
* @author Iain Shigeoka
*/
public class IQRosterImpl extends IQImpl implements IQRoster {
private BasicIQRoster basicRoster = new BasicIQRoster();
/**
* <p>Create an empty iq roster packet.</p>
*/
public IQRosterImpl() {
}
public String getChildNamespace() {
return "jabber:iq:roster";
}
public String getChildName() {
return "query";
}
public void send(XMLStreamWriter xmlSerializer, int version) throws
XMLStreamException {
try {
super.sendRoot(xmlSerializer, version, "iq", null);
xmlSerializer.setPrefix("", "jabber:iq:roster");
xmlSerializer.writeStartElement("query");
xmlSerializer.writeDefaultNamespace("jabber:iq:roster");
Iterator items = basicRoster.getRosterItems();
while (items.hasNext()) {
Object item = items.next();
if (item instanceof IQRosterItem) {
((IQRosterItem)item).send(xmlSerializer, version);
}
else {
new IQRosterItemImpl((RosterItem)item).send(xmlSerializer, version);
}
}
xmlSerializer.writeEndElement();
xmlSerializer.writeEndElement();
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
public void parse(Document doc) {
Element root = doc.getRootElement();
setRecipient(XMPPAddress.parseJID(root.attributeValue("to")));
setType(typeFromString(root.attributeValue("type")));
setID(root.attributeValue("id"));
Iterator elements = root.elements().iterator();
while (elements.hasNext()) {
Element element = (Element)elements.next();
if ("query".equals(element.getName())) {
Iterator items = element.elementIterator("item");
while (items.hasNext()) {
try {
Element item = (Element)items.next();
RosterItem rosterItem = basicRoster.createRosterItem(XMPPAddress.parseJID(item.attributeValue("jid")),
item.attributeValue("name"),
null);
rosterItem.setSubStatus("remove".equals(item.attributeValue("subscription")) ?
RosterItem.SUB_REMOVE : RosterItem.SUB_NONE);
Iterator groupElements = item.elementIterator("group");
while (groupElements.hasNext()) {
rosterItem.getGroups().add(((Element)groupElements.next()).getTextTrim());
}
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
catch (UserAlreadyExistsException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
}
}
public void parse(XMLStreamReader xpp) throws XMLStreamException {
// We're one past the root iq-element
int event = xpp.getEventType();
Document doc = null;
// The one query element or the error element
if (event == XMLStreamConstants.START_ELEMENT) {
if ("query".equals(xpp.getLocalName())) {
}
else {
// error, we'll punt and implement later
throw new XMLStreamException("Error packets not supported yet");
}
try {
doc = XPPReader.parseDocument(xpp);
setChildNamespace(doc.getRootElement().getNamespaceURI());
setChildName(doc.getRootElement().getName());
XMPPFragment fragment = new XMPPDOMFragment(doc.getRootElement());
addFragment(fragment);
setChildFragment(fragment);
}
catch (DocumentException e) {
throw new XMLStreamException();
}
}
while (event != XMLStreamConstants.END_ELEMENT) {
event = xpp.next();
}
}
// ##################################################################################
// Basic Roster usage - the downside of single inheritance
// ##################################################################################
private class BasicIQRoster extends BasicRoster {
protected RosterItem provideRosterItem(RosterItem item) throws UserAlreadyExistsException, UnauthorizedException {
return new IQRosterItemImpl(item);
}
protected RosterItem provideRosterItem(XMPPAddress user, String nickname, List groups) throws UserAlreadyExistsException, UnauthorizedException {
return new IQRosterItemImpl(user, nickname, groups);
}
}
public boolean isRosterItem(XMPPAddress user) {
return basicRoster.isRosterItem(user);
}
public Iterator getRosterItems() throws UnauthorizedException {
return basicRoster.getRosterItems();
}
public int getTotalRosterItemCount() throws UnauthorizedException {
return basicRoster.getTotalRosterItemCount();
}
public RosterItem getRosterItem(XMPPAddress user)
throws UnauthorizedException, UserNotFoundException {
return basicRoster.getRosterItem(user);
}
public RosterItem createRosterItem(XMPPAddress user)
throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(user);
}
public RosterItem createRosterItem(XMPPAddress user, String nickname, List groups)
throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(user, nickname, groups);
}
public RosterItem createRosterItem(RosterItem item) throws UnauthorizedException, UserAlreadyExistsException {
return basicRoster.createRosterItem(item);
}
public void updateRosterItem(RosterItem item)
throws UnauthorizedException, UserNotFoundException {
basicRoster.updateRosterItem(item);
}
public RosterItem deleteRosterItem(XMPPAddress user) throws UnauthorizedException {
return basicRoster.deleteRosterItem(user);
}
}
......@@ -12,8 +12,6 @@
package org.jivesoftware.messenger.user.spi;
import org.jivesoftware.util.ConcurrentHashSet;
import org.jivesoftware.messenger.XMPPAddress;
import org.jivesoftware.messenger.XMPPFragment;
import org.jivesoftware.messenger.user.BasicRosterItem;
import org.jivesoftware.messenger.user.IQRosterItem;
import org.jivesoftware.messenger.user.RosterItem;
......@@ -25,14 +23,15 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.xmpp.packet.JID;
public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
public IQRosterItemImpl(XMPPAddress jid) {
public IQRosterItemImpl(JID jid) {
super(jid);
}
public IQRosterItemImpl(XMPPAddress jid, String nickname, List groups) {
public IQRosterItemImpl(JID jid, String nickname, List groups) {
super(jid, nickname, groups);
}
......@@ -50,7 +49,7 @@ public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
public Element asXMLElement() {
Element item = DocumentHelper.createElement("item");
item.addAttribute("jid", jid.toBareString());
item.addAttribute("jid", jid.toBareJID());
item.addAttribute("subscription", subStatus.getName());
if (askStatus != ASK_NONE) {
item.addAttribute("ask", askStatus.getName());
......@@ -87,7 +86,7 @@ public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
public void send(XMLStreamWriter xmlSerializer, int version) throws XMLStreamException {
xmlSerializer.writeStartElement("jabber:iq:roster", "item");
xmlSerializer.writeAttribute("jid", jid.toBareString());
xmlSerializer.writeAttribute("jid", jid.toBareJID());
xmlSerializer.writeAttribute("subscription", subStatus.getName());
if (askStatus != ASK_NONE) {
xmlSerializer.writeAttribute("ask", askStatus.getName());
......@@ -107,15 +106,14 @@ public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
}
Iterator frags = fragments.iterator();
while (frags.hasNext()) {
XMPPFragment frag = (XMPPFragment)frags.next();
Element frag = (Element)frags.next();
frag.send(xmlSerializer, version);
}
xmlSerializer.writeEndElement();
}
public XMPPFragment createDeepCopy() {
IQRosterItemImpl item = new IQRosterItemImpl(new XMPPAddress(jid.getName(), jid.getHost(),
jid.getResource()));
public IQRosterItem createDeepCopy() {
IQRosterItemImpl item = new IQRosterItemImpl(new JID(jid.getNode(), jid.getDomain(), jid.getResource()));
item.subStatus = subStatus;
item.askStatus = askStatus;
item.recvStatus = recvStatus;
......@@ -130,7 +128,7 @@ public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
private ConcurrentHashSet fragments = new ConcurrentHashSet();
public void addFragment(XMPPFragment fragment) {
public void addFragment(Element fragment) {
fragments.add(fragment);
}
......@@ -138,13 +136,13 @@ public class IQRosterItemImpl extends BasicRosterItem implements IQRosterItem {
return fragments.iterator();
}
public XMPPFragment getFragment(String name, String namespace) {
public Element getFragment(String name, String namespace) {
if (fragments == null) {
return null;
}
XMPPFragment frag;
Element frag;
for (Iterator frags = fragments.iterator(); frags.hasNext();) {
frag = (XMPPFragment)frags.next();
frag = (Element)frags.next();
if (name.equals(frag.getName()) && namespace.equals(frag.getNamespace())) {
return frag;
}
......
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.user.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.UserNotFoundException;
/**
* <p>Implements the strategy as a basic server module.</p>
*
* @author Iain Shigeoka
*/
public class OfflineMessageStrategyImpl extends BasicModule implements OfflineMessageStrategy {
public OfflineMessageStrategyImpl() {
super("Offline Message Strategy");
}
private static int quota = -1;
private static Type type = Type.store;
public int getQuota() {
return quota;
}
public void setQuota(int quota) {
OfflineMessageStrategyImpl.quota = quota;
JiveGlobals.setProperty("xmpp.offline.quota", Integer.toString(quota));
}
public OfflineMessageStrategy.Type getType() {
return type;
}
public void setType(OfflineMessageStrategy.Type type) {
if (type == null) {
throw new IllegalArgumentException();
}
OfflineMessageStrategyImpl.type = type;
JiveGlobals.setProperty("xmpp.offline.type", type.toString());
}
public void storeOffline(Message message) throws UnauthorizedException, UserNotFoundException {
if (message != null) {
Session senderSession = message.getOriginatingSession();
XMPPAddress sender = senderSession.getAddress();
// server messages and anonymous messages can be silently dropped
if (sender == null || sender.getName() == null) {
// silently drop the server message
}
else {
if (type == Type.bounce) {
bounce(message);
}
else if (type == Type.store) {
store(message);
}
else if (type == Type.store_and_bounce) {
if (underQuota(message)) {
store(message);
}
else {
bounce(message);
}
}
else if (type == Type.store_and_drop) {
if (underQuota(message)) {
store(message);
}
}
}
}
}
private boolean underQuota(Message message) throws UnauthorizedException, UserNotFoundException {
return quota > messageStore.getSize(message.getRecipient().getNamePrep()) + message.getSize();
}
private void store(Message message) throws UnauthorizedException {
messageStore.addMessage(message);
}
public void initialize(Container container) {
super.initialize(container);
String quota = JiveGlobals.getProperty("xmpp.offline.quota");
if (quota != null && quota.length() > 0) {
OfflineMessageStrategyImpl.quota = Integer.parseInt(quota);
}
String type = JiveGlobals.getProperty("xmpp.offline.type");
if (type != null && type.length() > 0) {
OfflineMessageStrategyImpl.type = Type.valueOf(type);
}
}
private void bounce(Message message) {
// Generate a rejection response to the sender
try {
Message response = packetFactory.getMessage();
response.setOriginatingSession(xmppServer.getSession());
response.setRecipient(message.getSender());
response.setSender(xmppServer.createJID(null, null));
response.setBody("Message could not be delivered to " + message.getRecipient() + ". User is offline or unreachable.");
message.getOriginatingSession().getConnection().deliver(response);
Message errorResponse = (Message)message.createDeepCopy();
errorResponse.setError(XMPPError.Code.NOT_FOUND);
message.getOriginatingSession().getConnection().deliver(errorResponse);
}
catch (Exception e) {
//
}
}
public PacketFactory packetFactory;
public XMPPServer xmppServer;
public PacketDeliverer deliverer;
public OfflineMessageStore messageStore;
public TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(XMPPServer.class, "xmppServer");
trackInfo.getTrackerClasses().put(PacketFactory.class, "packetFactory");
trackInfo.getTrackerClasses().put(OfflineMessageStore.class, "messageStore");
return trackInfo;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment