Commit 82b0d989 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Refactoring to remove trackinfo logic.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@624 b35dd754-fafc-0310-a699-88a17e54d16e
parent 3678f041
......@@ -14,6 +14,7 @@ package org.jivesoftware.messenger;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.container.BasicModule;
import org.xmpp.packet.Message;
import org.dom4j.io.SAXReader;
import org.dom4j.DocumentFactory;
......@@ -31,7 +32,7 @@ import java.sql.Connection;
*
* @author Iain Shigeoka
*/
public class OfflineMessageStore {
public class OfflineMessageStore extends BasicModule {
private static final String INSERT_OFFLINE =
"INSERT INTO jiveOffline (username, messageID, creationDate, messageSize, message) " +
......@@ -43,7 +44,7 @@ public class OfflineMessageStore {
private static final String DELETE_OFFLINE =
"DELETE FROM jiveOffline WHERE username=?";
private static OfflineMessageStore instance = new OfflineMessageStore();
private static OfflineMessageStore instance;
/**
* Returns a singleton instance of OfflineMessageStore.
......@@ -57,8 +58,9 @@ public class OfflineMessageStore {
private SAXReader saxReader = new SAXReader();
private DocumentFactory docFactory = new DocumentFactory();
private OfflineMessageStore() {
public OfflineMessageStore() {
super("Offline Message Store");
instance = this;
}
/**
......
......@@ -13,8 +13,6 @@ 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;
......@@ -32,14 +30,11 @@ public class OfflineMessageStrategy extends BasicModule {
private static Type type = Type.store;
private SessionManager sessionManager;
public XMPPServer xmppServer;
public PacketDeliverer deliverer;
public OfflineMessageStore messageStore;
private XMPPServer xmppServer;
private OfflineMessageStore messageStore;
public OfflineMessageStrategy() {
super("Offline Message Strategy");
sessionManager = SessionManager.getInstance();
}
public int getQuota() {
......@@ -107,18 +102,6 @@ public class OfflineMessageStrategy extends BasicModule {
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 {
......@@ -141,13 +124,20 @@ public class OfflineMessageStrategy extends BasicModule {
}
}
public void initialize(XMPPServer server) {
super.initialize(server);
xmppServer = server;
messageStore = server.getOfflineMessageStore();
sessionManager = server.getSessionManager();
public TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(XMPPServer.class, "xmppServer");
trackInfo.getTrackerClasses().put(OfflineMessageStore.class, "messageStore");
return trackInfo;
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);
}
}
/**
......
......@@ -22,7 +22,6 @@ import org.dom4j.io.SAXReader;
import java.sql.*;
import java.sql.Connection;
import java.io.StringWriter;
import java.io.StringReader;
/**
* Private storage for user accounts (JEP-0049). It is used by some XMPP systems
......
......@@ -27,10 +27,8 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jivesoftware.messenger.audit.AuditStreamIDFactory;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.spi.BasicStreamIDFactory;
import org.jivesoftware.messenger.spi.PacketTransporterImpl;
import org.jivesoftware.messenger.spi.SessionImpl;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
......@@ -49,16 +47,14 @@ import org.xmlpull.v1.XmlPullParserException;
*
* @author Derek DeMoro
*/
public class SessionManager implements ConnectionCloseListener {
public class SessionManager extends BasicModule implements ConnectionCloseListener {
private int sessionCount = 0;
public static final int NEVER_KICK = -1;
public XMPPServer server;
public PacketRouter router;
public PacketTransporterImpl transporter;
private PacketRouter router;
private String serverName;
private JID serverAddress;
public UserManager userManager;
private UserManager userManager;
private int conflictLimit;
private Random randomResource = new Random();
......@@ -87,7 +83,12 @@ public class SessionManager implements ConnectionCloseListener {
return singleton;
}
private SessionManager() {
public SessionManager() {
super("Session Manager");
if (singleton != null) {
throw new IllegalStateException();
}
singleton = this;
if (JiveGlobals.getBooleanProperty("xmpp.audit.active")) {
streamIDFactory = new AuditStreamIDFactory();
}
......@@ -127,7 +128,7 @@ public class SessionManager implements ConnectionCloseListener {
* <p>Session manager must maintain the routing table as sessions are added and
* removed.</p>
*/
public RoutingTable routingTable;
private RoutingTable routingTable;
/**
* The standard Jive reader/writer lock to synchronize access to
......@@ -903,29 +904,14 @@ public class SessionManager implements ConnectionCloseListener {
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "server");
trackInfo.getTrackerClasses().put(PacketRouter.class, "router");
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
return trackInfo;
}
public void serviceAdded(Object service) {
if (service instanceof XMPPServer && server != null) {
public void initialize(XMPPServer server) {
super.initialize(server);
router = server.getPacketRouter();
userManager = server.getUserManager();
routingTable = server.getRoutingTable();
serverName = server.getServerInfo().getName();
serverAddress = new JID(serverName);
}
}
public void serviceRemoved(Object service) {
if (server == null) {
serverName = null;
}
}
public void initialize(Container container) {
if (JiveGlobals.getBooleanProperty("xmpp.audit.active")) {
streamIDFactory = new AuditStreamIDFactory();
}
......@@ -986,6 +972,7 @@ public class SessionManager implements ConnectionCloseListener {
}
public void stop() {
serverName = null;
sendServerMessage(null, LocaleUtils.getLocalizedString("admin.shutdown.now"));
try {
for (Session session : getSessions()) {
......
/**
* $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.audit.spi.AuditManagerImpl;
import org.jivesoftware.messenger.container.spi.BootstrapContainer;
import org.jivesoftware.messenger.disco.IQDiscoInfoHandler;
import org.jivesoftware.messenger.disco.IQDiscoItemsHandler;
import org.jivesoftware.messenger.handler.IQAuthHandler;
import org.jivesoftware.messenger.handler.IQPrivateHandler;
import org.jivesoftware.messenger.handler.IQRegisterHandler;
import org.jivesoftware.messenger.handler.IQRosterHandler;
import org.jivesoftware.messenger.handler.IQTimeHandler;
import org.jivesoftware.messenger.handler.IQVersionHandler;
import org.jivesoftware.messenger.handler.IQvCardHandler;
import org.jivesoftware.messenger.handler.PresenceSubscribeHandler;
import org.jivesoftware.messenger.handler.PresenceUpdateHandler;
import org.jivesoftware.messenger.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.messenger.spi.BasicServer;
import org.jivesoftware.messenger.spi.ConnectionManagerImpl;
import org.jivesoftware.messenger.spi.IQRouterImpl;
import org.jivesoftware.messenger.spi.MessageRouterImpl;
import org.jivesoftware.messenger.spi.PacketDelivererImpl;
import org.jivesoftware.messenger.spi.PacketRouterImpl;
import org.jivesoftware.messenger.spi.PacketTransporterImpl;
import org.jivesoftware.messenger.spi.PresenceManagerImpl;
import org.jivesoftware.messenger.spi.PresenceRouterImpl;
import org.jivesoftware.messenger.spi.RoutingTableImpl;
import org.jivesoftware.messenger.transport.TransportHandler;
import org.jivesoftware.messenger.user.spi.RosterManagerImpl;
import org.jivesoftware.messenger.user.spi.UserManagerImpl;
/**
* A bootstrap container to launch the Messenger XMPP server. This
* container knows what classes must be loaded to create a functional
* Jive Messenger deployment.
*
* @author Iain Shigeoka
*/
public class XMPPBootContainer extends BootstrapContainer {
protected String[] getSetupModuleNames() {
return new String[]{BasicServer.class.getName()};
}
protected String[] getBootModuleNames() {
return new String[]{
BasicServer.class.getName(),
RoutingTableImpl.class.getName(),
AuditManagerImpl.class.getName(),
UserManagerImpl.class.getName(),
RosterManagerImpl.class.getName(),
PrivateStorage.class.getName()};
}
protected String[] getCoreModuleNames() {
return new String[]{
ConnectionManagerImpl.class.getName(),
PresenceManagerImpl.class.getName(),
PacketRouterImpl.class.getName(),
IQRouterImpl.class.getName(),
MessageRouterImpl.class.getName(),
PresenceRouterImpl.class.getName(),
PacketTransporterImpl.class.getName(),
PacketDelivererImpl.class.getName(),
TransportHandler.class.getName(),
OfflineMessageStrategy.class.getName()};
}
protected String[] getStandardModuleNames() {
return new String[]{
IQAuthHandler.class.getName(),
IQPrivateHandler.class.getName(),
IQRegisterHandler.class.getName(),
IQRosterHandler.class.getName(),
IQTimeHandler.class.getName(),
IQvCardHandler.class.getName(),
IQVersionHandler.class.getName(),
PresenceSubscribeHandler.class.getName(),
PresenceUpdateHandler.class.getName(),
IQDiscoInfoHandler.class.getName(),
IQDiscoItemsHandler.class.getName(),
MultiUserChatServerImpl.class.getName()};
}
}
\ No newline at end of file
......@@ -11,6 +11,8 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.spi.BasicServer;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
......@@ -19,14 +21,14 @@ import javax.servlet.http.HttpServlet;
public class XMPPBootServlet extends HttpServlet {
private XMPPBootContainer container;
private Object containerLock = new Object();
private XMPPServer server;
private Object serverLock = new Object();
public void init(ServletConfig servletConfig) throws ServletException {
if (container == null) {
synchronized (containerLock) {
if (container == null) {
container = new XMPPBootContainer();
if (server == null) {
synchronized (serverLock) {
if (server == null) {
server = new BasicServer();
}
}
}
......
......@@ -11,8 +11,20 @@
package org.jivesoftware.messenger;
import org.jivesoftware.messenger.container.Module;
import org.xmpp.packet.JID;
import org.jivesoftware.messenger.user.RosterManager;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.handler.IQRegisterHandler;
import org.jivesoftware.messenger.handler.PresenceUpdateHandler;
import org.jivesoftware.messenger.handler.PresenceSubscribeHandler;
import org.jivesoftware.messenger.handler.IQHandler;
import org.jivesoftware.messenger.transport.TransportHandler;
import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.disco.ServerItemsProvider;
import org.jivesoftware.messenger.disco.IQDiscoInfoHandler;
import java.util.List;
/**
* The XMPP server definition. An interface allows us to implement the
......@@ -28,7 +40,7 @@ import org.xmpp.packet.JID;
*
* @author Iain Shigeoka
*/
public interface XMPPServer extends Module {
public interface XMPPServer {
/**
* Obtain a snapshot of the server's status.
......@@ -53,4 +65,49 @@ public interface XMPPServer extends Module {
*/
public JID createJID(String username, String resource);
public ConnectionManager getConnectionManager();
public RoutingTable getRoutingTable();
public PacketDeliverer getPacketDeliverer();
public RosterManager getRosterManager();
public PresenceManager getPresenceManager();
public OfflineMessageStore getOfflineMessageStore();
public OfflineMessageStrategy getOfflineMessageStrategy();
public PacketRouter getPacketRouter();
public IQRegisterHandler getIQRegisterHandler();
public List<IQHandler> getIQHandlers();
public SessionManager getSessionManager();
public TransportHandler getTransportHandler();
public PresenceUpdateHandler getPresenceUpdateHandler();
public PresenceSubscribeHandler getPresenceSubscribeHandler();
public IQRouter getIQRouter();
public MessageRouter getMessageRouter();
public PresenceRouter getPresenceRouter();
public UserManager getUserManager();
public AuditManager getAuditManager();
public List<ServerFeaturesProvider> getServerFeaturesProviders();
public List<ServerItemsProvider> getServerItemsProviders();
public IQDiscoInfoHandler getIQDiscoInfoHandler();
public PrivateStorage getPrivateStorage();
}
......@@ -12,10 +12,10 @@
package org.jivesoftware.messenger.audit.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.audit.Auditor;
import org.jivesoftware.messenger.JiveGlobals;
import org.jivesoftware.messenger.XMPPServer;
import java.util.*;
......@@ -145,8 +145,8 @@ public class AuditManagerImpl extends BasicModule implements AuditManager {
// Basic module methods
// #########################################################################
public void initialize(Container container) {
super.initialize(container);
public void initialize(XMPPServer server) {
super.initialize(server);
enabled = JiveGlobals.getBooleanProperty("xmpp.audit.active");
auditMessage = JiveGlobals.getBooleanProperty("xmpp.audit.message");
auditPresence = JiveGlobals.getBooleanProperty("xmpp.audit.presence");
......
......@@ -11,14 +11,7 @@
package org.jivesoftware.messenger.container;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jivesoftware.messenger.XMPPServer;
/**
* <p>A skeleton Module implementation that takes care of the most
......@@ -77,429 +70,6 @@ public class BasicModule implements Module {
}
}
// #####################################################################
// Override these methods to adjust the basic module behavior
// #####################################################################
/**
* <p>Return the services that this module implements.</p>
* <p>The basic module will register, and unregister these if not null</p>
*
* @return The services to register, or null if there are no services
*/
protected Object[] getServices() {
return null;
}
/**
* <p>Return the service that this module implements.</p>
* <p>The basic module will register, and unregister the service if not null.
* By default, basic module will register the module class in the lookup.</p>
*
* @return The service to register, or null if there is no service
*/
protected Object getService() {
return this;
}
/**
* <p>Return the service items that this module implements.</p>
* <p>The basic module will register, and unregister these if not null</p>
*
* @return The service items to register, or null if there are no service items
*/
protected ServiceItem[] getServiceItems() {
return null;
}
/**
* <p>Return the service item that this module implements.</p>
* <p>The basic module will register, and unregister the service item if not null</p>
*
* @return The service item to register, or null if there is no service item
*/
protected ServiceItem getServiceItem() {
return null;
}
/**
* <p>Override to use the built-in tracker and return the classes to be tracked.</p>
* <p>The tracker handles the possibly complex tasks of tracked services as they
* are registered and removed from the service lookup. For maximum flexibility while
* retaining ease of use, the basic module tries to manage the entire process for
* inheriting classes. The only responsibility of inheriting classes is to properly
* implement this method to return the correct tracker class information. However,
* if an inheriting class wishes to react to the adding and removal of services, they
* should override the serviceAdded() and serviceRemoved() methods.</p>
* <p/>
* <p>The tracker class map should contain:</p>
* <ul>
* <li>Key: (Class) tracked class type - The class of the service to be tracked.</li>
* <li>Value: (String) field name or (String[]) array of field names -
* The name of the fields
* to assign when a service matching the corresponding tracked class is
* added or set to null when the tracked class is removed.
* If the field is a list,
* tracked service objects are added and removed instead.</li>
* </ul>
* <p>The basic module will register each tracked
* class type as a notifyEvent template on the
* ServiceLookup, watching for services that implement
* that class. When services that match
* are added or removed from the lookup, the basic
* module will lookup the class type in
* the tracker map. For each key in the map that
* is an instanceof the service the
* basic module will obtain the value corresponding to
* that key. If the value is a
* String array, the following algorithm is carried
* out for each member of the array,
* otherwise it is conducted once. Assume in this
* description that the string value
* is "fieldName".</p>
* <ol>
* <li><b>setter/adder/remover</b> -
* If a service has been added, search for any method
* with a signature of (in this order):
* <ol>
* <li><code>void addfieldName(Foo)</code></li>
* <li><code>void addfieldName(Object)</code></li>
* <li><code>void setfieldName(Object)</code></li>
* <li><code>void setfieldName(Foo)</code></li>
* </ol>where (service instanceof Foo). If one
* exists, use the setter to set the value. If the
* service is being removed, then search for these methods:
* <ol>
* <li><code>void removefieldName(Foo)</code></li>
* <li><code>void removefieldName(Object)</code></li>
* <li><code>void setfieldName(Foo)</code></li>
* <li><code>void setfieldName(Object)</code></li>
* </ol>
* if a remove* method is found, the service is
* passed to the method. If no remove*
* method is found but a set* method is, then
* call the set* method with null. If no
* matchingmethods are found then the basic
* module will try to set a field directly.</li>
* <li><b>Field</b> - Search for any field of
* the class with the same name as the fieldName
* and of type Foo where (service instanceof Foo)
* or is a java.util.List. If the field is
* not a java.util.List, services added will
* set the field to reference the service, and
* removal will set the field to null. If the
* field is of type java.util.List, then
* added services will be added to the and removal
* will be remove the service from the
* list.</li>
* <li>If either a matching method, or field
* was found, call the serviceAdded or
* serviceRemoved method as appropriate with
* the service. This provides inheriting
* classes a chance to react to the change (operate in a new
* mode due to the appearance of a new service.</li>
* </ol>
* <p>As you can see, the basic module takes
* care of all the tedious housekeeping
* of managing services, and allows inheriting
* classes to essentially provide a mapping
* between the names of methods or fields and the
* types of services you would like to have
* associate with them. The basic module does it's
* best to keep these fields up to date.</p>
* <p/>
* <p>If you don't want to use a tracker, don't override
* this method (or return null).</p>
*
* @return The classes to track or null to indicate no tracker should be used.
*/
protected TrackInfo getTrackInfo() {
return null;
}
/**
* <p>Override this method to receive notification that a service has been added.</p>
* <p>This method is called after a service has been successfully added and set via
* a method or field of the class.</p>
*
* @param service The service that has been added.
*/
protected void serviceAdded(Object service) {
}
/**
* <p>Override this method to receive notification
* that a service has been removed.</p>
* <p>This method is called after a service has been successfully removed via
* a method or field (set to null) of the class.</p>
*
* @param service The service that has been removed.
*/
protected void serviceRemoved(Object service) {
}
/**
* <p>Add a service of type track class.</p>
*
* @param service The service to add
* @param trackClass The class of the service
* @param field The name of the method or field that corresponds to this service
* @return True if the service was successfully added
*/
private boolean doServiceAdd(Object service, Class trackClass, String field) {
boolean found = false;
if (field.length() == 0) {
found = true;
}
else {
found = tryMethod("add" + field, trackClass, service);
}
if (!found) {
found = tryMethod("add" + field, Object.class, service);
if (!found) {
found = tryMethod("set" + field, trackClass, service);
if (!found) {
found = tryMethod("set" + field, Object.class, service);
try {
Class parent = this.getClass();
while (!found && parent != null) {
found = matchFields(parent, field, service, true);
parent = parent.getSuperclass();
}
}
catch (Exception e) {
Log.error("Problem processing service", e);
}
}
}
}
return found;
}
/**
* <p>Tries to find a matching field and adds/removes the service.</p>
*
* @param parent The parent class to search
* @param field The field name we're searching for
* @param service The service to add/remove
* @param add True if matching fields result in an add, false to remove the service
* @return TRue if the service was successfully added
*/
private boolean matchFields(Class parent, String field, Object service, boolean add) {
boolean found = false;
Field[] fields = parent.getFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(field)) {
try {
Object fieldObject = fields[i].get(this);
if (add) {
if (fieldObject instanceof List) {
((List)fieldObject).add(service);
}
else {
fields[i].set(this, service);
}
}
else {
if (fieldObject instanceof List) {
((List)fieldObject).remove(service);
}
else {
fields[i].set(this, null);
}
}
found = true;
break;
}
catch (Exception e) {
Log.error("Problem processing service", e);
}
}
}
return found;
}
/**
* <p>Remove a service of type track class.</p>
*
* @param service The service to remove
* @param trackClass The class of the service
* @param field The name of the method or field that corresponds to this service
* @return True if the service was successfully removed
*/
private boolean doServiceRemove(Object service, Class trackClass, String field) {
boolean found = false;
if (field.length() == 0) {
found = true;
}
else {
found = tryMethod("remove" + field, trackClass, service);
}
if (!found) {
found = tryMethod("remove" + field, Object.class, service);
if (!found) {
found = tryMethod("set" + field, trackClass, null);
if (!found) {
found = tryMethod("set" + field, Object.class, null);
try {
Class parent = this.getClass();
while (parent != null && !found) {
found = matchFields(parent, field, service, false);
parent = parent.getSuperclass();
}
}
catch (Exception e) {
Log.error("Problem processing service", e);
}
}
}
}
return found;
}
/**
* <p>Try to call a method on this class that
* takes an object of type trackClass, and call
* it with the service.</p>
*
* @param methodName The name of the method to call
* @param trackClass The class of the single argument the method should take
* @param service The object to call the method with
* @return True if the method was found and called
*/
private boolean tryMethod(String methodName, Class trackClass, Object service) {
boolean found = false;
try {
Class parent = this.getClass();
while (parent != null) {
Method[] methods = parent.getMethods();
for (int i = 0; i < methods.length; i++) {
Class[] parameters = methods[i].getParameterTypes();
if (methods[i].getName().equals(methodName)
&& parameters.length == 1
&& parameters[0] == trackClass) {
try {
methods[i].invoke(this, new Object[]{service});
found = true;
break;
}
catch (Exception e) {
Log.error("Problem processing service", e);
}
}
}
if (found) {
break;
}
parent = parent.getSuperclass();
}
}
catch (Exception e) {
Log.error(e);
}
;
return found;
}
/**
* <p>Listens for tracked services and sets and removes them from the
* modules.</p>
*
* @author Iain Shigeoka
*/
private class BasicModuleTrackerListener implements ServiceTrackerListener {
/**
* <p>Runs through the tracked classes
* and assigns them according to the algorithm
* outlined in getTrackInfo.</p>
*
* @param service The service being added.
*/
public void addService(Object service) {
boolean success = false;
Iterator tracked = trackInfo.getTrackerClasses().keySet().iterator();
while (tracked.hasNext()) {
Class trackClass = (Class)tracked.next();
if (trackClass.isInstance(service)) {
Object field = trackInfo.getTrackerClasses().get(trackClass);
if (field instanceof String[]) {
String[] fields = (String[])field;
for (int i = 0; i < fields.length; i++) {
if (doServiceAdd(service, trackClass, fields[i])) {
success = true;
}
}
}
else {
if (doServiceAdd(service, trackClass, (String)field)) {
success = true;
}
}
}
}
if (success) {
serviceAdded(service);
}
}
/**
* <p>Runs trough the tracked classes and removes them according to
* the algorithm outlined in getTrackInfo().</p>
*
* @param service The service to remove
*/
public void removeService(Object service) {
boolean success = false;
Iterator tracked = trackInfo.getTrackerClasses().keySet().iterator();
while (tracked.hasNext()) {
Class trackClass = (Class)tracked.next();
if (trackClass.isInstance(service)) {
Object field = trackInfo.getTrackerClasses().get(trackClass);
if (field instanceof String[]) {
String[] fields = (String[])field;
for (int i = 0; i < fields.length; i++) {
if (doServiceRemove(service, trackClass, fields[i])) {
success = true;
}
}
}
else {
if (doServiceRemove(service, trackClass, (String)field)) {
success = true;
}
}
}
}
if (success) {
serviceRemoved(service);
}
}
}
// #####################################################################
// Basic module management - if you override, make sure to call the
// parent method as the first thing in the overrriden method.
// #####################################################################
/**
* <p>The 'local' lookup this module should use to locate services
* on the local server.</p>
*/
protected ServiceLookup lookup = null;
/**
* <p>The registrations the module has registered with the lookup.
* The BasicModule manages these registrations but inheriting classes
* may need to manipulate the registrations (such as when attributes for
* the registration should be changed.</p>
*/
protected ArrayList registrations = new ArrayList();
private ServiceTracker tracker = null;
private TrackInfo trackInfo = null;
/**
* <p>Obtain the name of the module.</p>
*
......@@ -515,24 +85,9 @@ public class BasicModule implements Module {
* <p>Inheriting classes that choose to override this method MUST
* call this initialize() method before accessing BasicModule resources.</p>
*
* @param container The container hosting the module
* @param server the server hosting this module.
*/
public void initialize(Container container) {
try {
lookup = container.getServiceLookup();
trackInfo = getTrackInfo();
if (trackInfo != null) {
int classCount = trackInfo.getTrackerClasses().keySet().size();
Class[] trackedClasses =
(Class[])trackInfo.getTrackerClasses().keySet().toArray(new Class[classCount]);
tracker = new ServiceTracker(lookup,
new BasicModuleTrackerListener(),
trackedClasses);
}
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
public void initialize(XMPPServer server) {
}
/**
......@@ -545,31 +100,6 @@ public class BasicModule implements Module {
* successfully returns
*/
public void start() throws IllegalStateException {
if (lookup == null) {
throw new IllegalStateException("Start called before initialize");
}
Object[] services = getServices();
if (services != null) {
for (int i = 0; i < services.length; i++) {
if (services[i] != null) {
registrations.add(lookup.register(new ServiceItem(null, services[i], null)));
}
}
}
if (getService() != null) {
registrations.add(lookup.register(new ServiceItem(null, getService(), null)));
}
ServiceItem[] items = getServiceItems();
if (items != null) {
for (int i = 0; i < items.length; i++) {
if (items[i] != null) {
registrations.add(lookup.register(items[i]));
}
}
}
if (getServiceItem() != null) {
registrations.add(lookup.register(getServiceItem()));
}
}
/**
......@@ -579,15 +109,6 @@ public class BasicModule implements Module {
* call this stop() method before accessing BasicModule resources.</p>
*/
public void stop() {
Iterator regs = registrations.iterator();
while (regs.hasNext()) {
((ServiceRegistration)regs.next()).cancel();
}
registrations.clear();
if (tracker != null) {
tracker.cancel();
tracker = null;
}
}
/**
......
......@@ -11,6 +11,8 @@
package org.jivesoftware.messenger.container;
import org.jivesoftware.messenger.XMPPServer;
/**
* Logical, server-managed entities must implement this interface. A module
* represents an operational unit and may contain zero or more services
......@@ -52,9 +54,9 @@ public interface Module {
* Modules may be initialized and never started, so modules
* should be prepared for a call to destroy() to follow initialize().
*
* @param container the container hosting this module.
* @param server the server hosting this module.
*/
void initialize(Container container);
void initialize(XMPPServer server);
/**
* Start the module (must return quickly). Any long running
......
/**
* $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.container.spi;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.messenger.container.*;
import org.jivesoftware.util.*;
import org.jivesoftware.messenger.JiveGlobals;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.io.*;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
/**
* <p>The initial container that hosts all other modules (and containers).</p>
* <p/>
* <p>The boostrap container operates in a similar manner to the basic container
* but alters the standard module layout for better packaging of server.
* Notice that the bootstrap server runs from the messengerHome directory whether
* the server is run in standalone mode (messengerHome == server directory) or
* as a web-app (messengerHome == setting in messenger_init.xml).</p>
* <p/>
* <p>Bootstrap systems should have a directory layout that looks like:</p>
* <p/>
* <ul>
* <li>conf - Contains configuration information for the server as a whole
* <ul>
* <li>jive-messenger.xml - The bootstrap configuration file.</li>
* </ul>
* </li>
* <li>logs - The root directory for log files</li>
* <li>security - The security keystores for the server (if any)</li>
* <li>plugins - The module directory for loading server modules</li>
* </li>
* <p/>
* <p>Note that the root lib directory is NOT part
* of the container's responsibilties. The jars in that
* directory are loaded by the ServerStarter in standalone mode, or by the
* web-app server from the WAR or web-app/WEB-INF/lib directory
* when deployed into an app server.</p>
*
* @author Derek DeMoro
* @author Iain Shigeoka
*/
public abstract class BootstrapContainer implements Container, ServiceLookupProvider {
/**
* <p>Obtain the full class names of the setup server modules.</p>
* <p/>
* <p>Setup modules are required for the setup admin UI and should
* be the minimum subset that will allow the setup to proceed.</p>
*
* @return An array of the full class names of the modules to load
*/
protected abstract String[] getSetupModuleNames();
/**
* <p>Obtain the full class names of the boot server modules.</p>
* <p/>
* <p>Boot modules are required for the runtime behavior of the server
* and MUST not depend on other modules (including other boot modules).
* These are the bootstrap modules that enable other modules to startup
* without worrying about startup dependencies.</p>
*
* @return An array of the full class names of the modules to load
*/
protected abstract String[] getBootModuleNames();
/**
* <p>Obtain the full class names of the core server modules.</p>
* <p/>
* <p>These modules are a core part of the standard runtime service
* profile. They often depend on the boot modules for proper operation.</p>
*
* @return An array of the full class names of the modules to load
*/
protected abstract String[] getCoreModuleNames();
/**
* <p>Obtain the full class names of the standard server modules.</p>
* <p/>
* <p>These modules are part of the standard runtime server
* profile. They often depend on the boot and core modules for proper
* operation.</p>
*
* @return An array of the full class names of the modules to load
*/
protected abstract String[] getStandardModuleNames();
/**
* The lookup for the bootstrap container.
*/
private ServiceLookup lookup;
/**
* The registration of the service with itself.
*/
private ServiceRegistration containerRegistration;
/**
* All modules loaded by this container
*/
private List<Module> modules = new ArrayList<Module>();
/**
* Location of the messengerHome directory. All configuration files should be
* located here.
*/
private File messengerHome;
private ClassLoader loader;
private PluginManager pluginManager;
/**
* True if in setup mode
*/
private boolean setupMode = true;
private static final String STARTER_CLASSNAME =
"org.jivesoftware.messenger.starter.ServerStarter";
private static final String WRAPPER_CLASSNAME =
"org.tanukisoftware.wrapper.WrapperManager";
/**
* Constructs the bootstrap server.
*/
public BootstrapContainer() {
ServiceLookupFactory.setLookupProvider(this);
start();
}
/**
* Starts the container.
*/
private void start() {
try {
locateMessenger();
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false;
}
if (isStandAlone()) {
Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());
}
lookup = new ServiceLookupImpl();
ServiceItem serverItem = new ServiceItem(null, this, null);
containerRegistration = lookup.register(serverItem);
loader = Thread.currentThread().getContextClassLoader();
if (setupMode) {
loadCoreModules(getSetupModuleNames());
}
else {
verifyDataSource();
loadCoreModules(getBootModuleNames());
loadCoreModules(getCoreModuleNames());
loadCoreModules(getStandardModuleNames());
}
startCoreModules();
// Load plugins.
File pluginDir = new File(messengerHome, "plugins");
pluginManager = new PluginManager(pluginDir);
pluginManager.start();
}
catch (Exception e) {
e.printStackTrace();
Log.error(e);
System.out.println(LocaleUtils.getLocalizedString("startup.error"));
shutdownContainer();
}
}
public boolean isRestartable() {
boolean restartable = false;
try {
restartable = Class.forName(WRAPPER_CLASSNAME) != null;
}
catch (ClassNotFoundException e) {
restartable = false;
}
return restartable;
}
public boolean isStandAlone() {
boolean standalone = false;
try {
standalone = Class.forName(STARTER_CLASSNAME) != null;
}
catch (ClassNotFoundException e) {
standalone = false;
}
return standalone;
}
/**
* Verify that the database is accessible.
*/
private void verifyDataSource() {
java.sql.Connection conn = null;
try {
conn = DbConnectionManager.getConnection();
PreparedStatement stmt = conn.prepareStatement(
"SELECT count(*) FROM jiveID");
ResultSet rs = stmt.executeQuery();
rs.next();
rs.close();
stmt.close();
}
catch (Exception e) {
System.err.println("Database setup or configuration error: " +
"Please verify your database settings and check the " +
"logs/error.log file for detailed error messages.");
Log.error("Database could not be accessed", e);
throw new IllegalArgumentException();
}
finally {
if (conn != null) {
try { conn.close(); }
catch (SQLException e) { Log.error(e); }
}
}
}
/**
* Load plugins that are integrated with the core server.
* <p/>
*
*/
private void loadCoreModules(String[] modules) {
for (int i = 0; i < modules.length; i++) {
Module mod = null;
boolean isInitialized = false;
try {
Class modClass = loader.loadClass(modules[i]);
mod = (Module)modClass.newInstance();
mod.initialize(this);
isInitialized = true;
this.modules.add(mod);
}
catch (Exception e) {
e.printStackTrace();
if (isInitialized) {
mod.stop();
mod.destroy();
}
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
/**
* <p>Following the loading and initialization of all the plugins
* this method is called to iterate through the known modules and
* start them.</p>
*/
private void startCoreModules() {
for (Module module : modules) {
boolean started = false;
try {
module.start();
}
catch (Exception e) {
if (started && module != null) {
module.stop();
module.destroy();
}
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
/**
* Makes a best effort attempt to shutdown the server
*/
private void shutdownContainer() {
// Unregister the container first
if (containerRegistration != null) {
containerRegistration.cancel();
containerRegistration = null;
}
// Now get all modules and stop and destroy them
Iterator loadedModules = modules.iterator();
while (loadedModules.hasNext()) {
Module mod = (Module)loadedModules.next();
mod.stop();
mod.destroy();
}
modules.clear();
// Stop all plugins
pluginManager.shutdown();
// TODO: hack to allow safe stopping
Log.info("Jive Messenger stopped");
}
public boolean isSetupMode() {
return setupMode;
}
public ServiceLookup getServiceLookup() throws UnauthorizedException {
return lookup;
}
public Object startService(Class service) throws UnauthorizedException {
Object instance = lookup.lookup(service);
if (instance == null) {
if (service.getName().equals("org.jivesoftware.messenger.user.UserManager")) {
loadCoreModules(new String[]{
"org.jivesoftware.messenger.user.spi.UserManagerImpl"});
instance = lookup.lookup(service);
}
}
return instance;
}
public void stopService(Class service) throws UnauthorizedException {
Iterator modIter = modules.iterator();
while (modIter.hasNext()) {
Object mod = modIter.next();
if (mod.getClass().isAssignableFrom(service)) {
modIter.remove();
((Module)mod).stop();
((Module)mod).destroy();
}
}
}
public Entry getLocalServerAttribute() throws UnauthorizedException {
return new Entry() {
};
}
/**
* <p>Restarts the container and all it's modules.</p>
*/
public void restart() {
if (isStandAlone() && isRestartable()) {
try {
Class wrapperClass = Class.forName(WRAPPER_CLASSNAME);
Method restartMethod = wrapperClass.getMethod("restart", (Class)null);
restartMethod.invoke(null, (Class)null);
}
catch (Exception e) {
Log.error("Could not restart container", e);
}
}
}
public void stop() throws UnauthorizedException {
// Only do a system exit if we're running standalone
if (isStandAlone()) {
// if we're in a wrapper, we have to tell the wrapper to shut us down
if (isRestartable()) {
try {
Class wrapperClass = Class.forName(WRAPPER_CLASSNAME);
Method stopMethod = wrapperClass.getMethod("stop",
new Class[]{Integer.TYPE});
stopMethod.invoke(null, new Object[]{0});
}
catch (Exception e) {
Log.error("Could not stop container", e);
}
}
else {
shutdownContainer();
Thread shutdownThread = new ShutdownThread();
shutdownThread.setDaemon(true);
shutdownThread.start();
}
}
}
/**
* <p>A thread to ensure the server shuts down no matter what.</p>
* <p>Spawned when stop() is called in standalone mode, we wait a few
* seconds then call system exit().</p>
*
* @author Iain Shigeoka
*/
private class ShutdownThread extends Thread {
/**
* <p>Shuts down the JVM after a 5 second delay.</p>
*/
public void run() {
try {
Thread.sleep(5000);
// No matter what, we make sure it's dead
System.exit(0);
}
catch (InterruptedException e) {
}
}
}
/**
* <p>A thread to ensure the server shuts down no matter what.</p>
* <p>Spawned when stop() is called in standalone mode, we wait a few
* seconds then call system exit().</p>
*
* @author Iain Shigeoka
*/
private class ShutdownHookThread extends Thread {
/**
* <p>Logs the server shutdown.</p>
*/
public void run() {
if (containerRegistration != null) {
shutdownContainer();
}
Log.info("Server halted");
System.err.println("Server halted");
}
}
/**
* Verifies that the given home guess is a real Messenger home directory.
* We do the verification by checking for the Messenger config file in
* the config dir of jiveHome.
*
* @param homeGuess a guess at the path to the home directory.
* @param jiveConfigName the name of the config file to check.
* @return a file pointing to the home directory or null if the
* home directory guess was wrong.
* @throws FileNotFoundException if there was a problem with the home
* directory provided
*/
private File verifyHome(String homeGuess, String jiveConfigName) throws FileNotFoundException {
File realHome = null;
File guess = new File(homeGuess);
File configFileGuess = new File(guess, jiveConfigName);
if (configFileGuess.exists()) {
realHome = guess;
}
File forumsHome = new File(guess, jiveConfigName);
if (!forumsHome.exists()) {
throw new FileNotFoundException();
}
try{
return new File(realHome.getCanonicalPath());
}
catch(Exception ex){
throw new FileNotFoundException();
}
}
/**
* <p>Retrieve the jive home for the container.</p>
*
* @throws FileNotFoundException If jiveHome could not be located
*/
private void locateMessenger() throws FileNotFoundException {
String jiveConfigName = "conf" + File.separator + "jive-messenger.xml";
// First, try to load it jiveHome as a system property.
if (messengerHome == null) {
String homeProperty = System.getProperty("messengerHome");
try {
if (homeProperty != null) {
messengerHome = verifyHome(homeProperty, jiveConfigName);
}
}
catch (FileNotFoundException fe) {
}
}
// If we still don't have messengerHome, let's assume this is standalone
// and just look for messengerHome in a standard sub-dir location and verify
// by looking for the config file
if (messengerHome == null) {
try {
messengerHome = verifyHome("..", jiveConfigName).getCanonicalFile();
}
catch (FileNotFoundException fe) {
}
catch (IOException ie) {
}
}
// If messengerHome is still null, no outside process has set it and
// we have to attempt to load the value from messenger_init.xml,
// which must be in the classpath.
if (messengerHome == null) {
InputStream in = null;
try {
in = getClass().getResourceAsStream("/messenger_init.xml");
if (in != null) {
SAXReader reader = new SAXReader();
Document doc = reader.read(in);
String path = doc.getRootElement().getText();
try {
if (path != null) {
messengerHome = verifyHome(path, jiveConfigName);
}
}
catch (FileNotFoundException fe) {
fe.printStackTrace();
}
}
}
catch (Exception e) {
System.err.println("Error loading messenger_init.xml to find messengerHome.");
e.printStackTrace();
}
finally {
try { if (in != null) { in.close(); } }
catch (Exception e) {
System.err.println("Could not close open connection");
e.printStackTrace();
}
}
}
if (messengerHome == null) {
System.err.println("Could not locate messengerHome");
throw new FileNotFoundException();
}
else {
JiveGlobals.messengerHome = messengerHome.toString();
}
}
}
/**
* $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.container.spi;
import org.jivesoftware.messenger.container.EventListener;
import org.jivesoftware.messenger.container.EventRegistration;
/**
* A simple registration event for services.
*
* @author Iain Shigeoka
*/
public class ServiceEventRegistrationImpl extends EventRegistration {
/**
* The listener for this registration.
*/
private EventListener listener;
/**
* Create an event registration with listener and lookup
*
* @param serviceLookup the lookup that generated the registration.
* @param eventListener the listener for the registration event.
* @param eventID the event ID to associate with this event.
* @param sequenceNo the sequence number this event will use
*/
public ServiceEventRegistrationImpl(ServiceLookupImpl serviceLookup,
EventListener eventListener,
long eventID,
long sequenceNo) {
super(eventID, serviceLookup, sequenceNo);
this.listener = eventListener;
}
public void cancel() {
((ServiceLookupImpl)this.getSource()).remove(listener);
}
}
/**
* $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.container.spi;
import org.jivesoftware.messenger.container.*;
import org.jivesoftware.messenger.container.EventListener;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import java.util.*;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* <p>Simple classs to track and manage service
* registrations and respond to service lookups.</p>
*
* @author Iain Shigeoka
*/
public class ServiceLookupImpl implements ServiceLookup {
private ServiceID id;
private Map idTable = new HashMap();
/**
* Simple constructor
*/
public ServiceLookupImpl() {
id = new ServiceID();
}
public ServiceID getServiceID() {
return id;
}
public Class[] getServiceTypes(ServiceTemplate tmpl, String prefix) {
throw new UnsupportedOperationException();
}
public Object lookup(Class type) {
ServiceTemplate tmpl = new ServiceTemplate();
tmpl.types = new Class[]{type};
return lookup(tmpl);
}
public Object lookup(ServiceTemplate tmpl) {
Object found = null;
try {
matchLock.readLock().lock();
Iterator itemItr;
// Add all matching service IDs to the items list
if (tmpl.serviceID == null) {
itemItr = idTable.values().iterator();
}
else {
LinkedList items = new LinkedList();
items.add(idTable.get(tmpl.serviceID));
itemItr = items.iterator();
}
// Now check each item for a match against attributes
while (itemItr.hasNext()) {
ServiceItem item = (ServiceItem)itemItr.next();
if (isMatch(tmpl, item)) {
found = item.service;
break;
}
}
}
finally {
matchLock.readLock().unlock();
}
return found;
}
private boolean isMatch(ServiceTemplate tmpl, ServiceItem item) {
boolean isMatch = true;
if (tmpl.attributes != null) {
for (int i = 0; i < tmpl.attributes.length; i++) {
boolean hasAttribute = false;
for (int j = 0; j < item.attributes.length; j++) {
if (item.attributes[j].equals(tmpl.attributes[i])) {
hasAttribute = true;
}
}
if (!hasAttribute) {
isMatch = false;
item = null;
}
}
}
if (item != null && tmpl.types != null) {
for (int i = 0; i < tmpl.types.length; i++) {
if (!tmpl.types[i].isInstance(item.service)) {
isMatch = false;
item = null;
break;
}
}
}
return isMatch;
}
public ServiceMatches lookup(ServiceTemplate tmpl, int maxMatches) {
throw new UnsupportedOperationException();
}
//private long eventID = 101;
private static final long EVENT_ID = 101;
private long sequenceID = 0;
private ReadWriteLock matchLock = new ReentrantReadWriteLock();
private HashMap matchMatchListeners = new HashMap();
private HashMap matchNoMatchListeners = new HashMap();
private HashMap noMatchMatchListeners = new HashMap();
private HashMap listeners = new HashMap();
public EventRegistration notifyRegister(ServiceTemplate tmpl,
int transitions,
EventListener listener) {
try {
matchLock.writeLock().lock();
if ((transitions & TRANSITION_MATCH_MATCH) != 0) {
matchMatchListeners.put(tmpl, listener);
}
if ((transitions & TRANSITION_MATCH_NOMATCH) != 0) {
matchNoMatchListeners.put(tmpl, listener);
}
if ((transitions & TRANSITION_NOMATCH_MATCH) != 0) {
noMatchMatchListeners.put(tmpl, listener);
}
List templates = (List)listeners.get(listener);
if (templates == null) {
templates = new LinkedList();
listeners.put(listener, templates);
}
templates.add(tmpl);
return new ServiceEventRegistrationImpl(this, listener, EVENT_ID, sequenceID);
}
finally {
matchLock.writeLock().unlock();
}
}
public ServiceRegistration register(ServiceItem item) {
// Generate a service id if needed
if (item.serviceID == null) {
item.serviceID = new ServiceID();
}
// Register the service
Object result = null;
try {
matchLock.writeLock().lock();
result = idTable.put(item.serviceID, item);
}
finally {
matchLock.writeLock().unlock();
}
// Handle transition notifications
// This can trigger a nomatch-match or match-match event
if (result == null) { // nomatch-match
notifyTransitions(noMatchMatchListeners, TRANSITION_NOMATCH_MATCH, item);
}
else { // match-match
notifyTransitions(matchMatchListeners, TRANSITION_MATCH_MATCH, item);
}
return new ServiceRegistrationImpl(this, item.serviceID);
}
private void notifyTransitions(Map listenerMap, int transition, ServiceItem item) {
LinkedList notifyListenerList = new LinkedList();
try {
matchLock.readLock().lock();
Iterator matches = listenerMap.keySet().iterator();
while (matches.hasNext()) {
ServiceTemplate tmpl = (ServiceTemplate)matches.next();
EventListener listener = (EventListener)listenerMap.get(tmpl);
if (isMatch(tmpl, item)) {
notifyListenerList.add(listener);
}
}
}
finally {
matchLock.readLock().unlock();
}
Iterator notifyListeners = notifyListenerList.iterator();
while (notifyListeners.hasNext()) {
EventListener listener = (EventListener)notifyListeners.next();
try {
listener.notifyEvent(new ServiceEvent(this,
EVENT_ID,
sequenceID++,
null,
item,
id,
transition));
}
catch (UnknownEventException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
/**
* Remove a service (only should be called by a ServiceRegistrationImpl.cancel()
*
* @param removeID The service id of the servce to remove
*/
final void remove(ServiceID removeID) {
ServiceItem item;
// Remove registration
try {
matchLock.writeLock().lock();
item = (ServiceItem)idTable.remove(removeID);
}
finally {
matchLock.writeLock().unlock();
}
// Notify listeners
if (item != null) {
notifyTransitions(matchNoMatchListeners, TRANSITION_MATCH_NOMATCH, item);
}
}
/**
* <p>Remove a service event listener
* (only should be called by ServiceEventRegistrationImpl.cancel()).</p>
*
* @param listener The event listener to remove
*/
final void remove(EventListener listener) {
try {
matchLock.writeLock().lock();
List templates = (List)listeners.remove(listener);
if (templates != null) {
Iterator templateItr = templates.iterator();
while (templateItr.hasNext()) {
Object template = templateItr.next();
matchMatchListeners.remove(template);
matchNoMatchListeners.remove(template);
noMatchMatchListeners.remove(template);
}
}
}
finally {
matchLock.writeLock().unlock();
}
}
/**
* Sets the attributes for an entry.
* Only should be called by a ServiceRegistrationImpl.setAttributes()
*
* @param serviceID The id of the service to modify
* @param attributes The new attributes for that service
*/
final void setAttributes(ServiceID serviceID, Entry[] attributes) {
try {
matchLock.writeLock().lock();
ServiceItem item = (ServiceItem)idTable.get(serviceID);
item.attributes = attributes;
}
finally {
matchLock.writeLock().unlock();
}
}
}
/**
* $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.container.spi;
import org.jivesoftware.messenger.container.EventListener;
import org.jivesoftware.messenger.container.EventRegistration;
import org.jivesoftware.messenger.container.ServiceID;
import org.jivesoftware.messenger.container.ServiceItem;
import org.jivesoftware.messenger.container.ServiceLookup;
import org.jivesoftware.messenger.container.ServiceMatches;
import org.jivesoftware.messenger.container.ServiceRegistration;
import org.jivesoftware.messenger.container.ServiceTemplate;
import org.jivesoftware.messenger.auth.AuthToken;
import org.jivesoftware.messenger.auth.Permissions;
/**
* Authorization proxy for service lookups.
*
* @author Iain Shigeoka
*/
public class ServiceLookupProxy implements ServiceLookup {
private AuthToken authToken;
private Permissions permissions;
private ServiceLookup lookup;
/**
* Create a lookup security proxy
*
* @param authToken the authentication token for the user.
* @param permissions the permissions of the user.
* @param lookup the lookup being proxied.
*/
public ServiceLookupProxy(AuthToken authToken, Permissions permissions, ServiceLookup lookup) {
this.authToken = authToken;
this.permissions = permissions;
this.lookup = lookup;
}
public ServiceID getServiceID() {
return lookup.getServiceID();
}
public Class[] getServiceTypes(ServiceTemplate tmpl, String prefix) {
return lookup.getServiceTypes(tmpl, prefix);
}
public Object lookup(Class type) {
return lookup.lookup(type);
}
public Object lookup(ServiceTemplate tmpl) {
return lookup.lookup(tmpl);
}
public ServiceMatches lookup(ServiceTemplate tmpl, int maxMatches) {
return lookup.lookup(tmpl, maxMatches);
}
public EventRegistration notifyRegister(ServiceTemplate tmpl, int transitions, EventListener listener) {
return lookup.notifyRegister(tmpl, transitions, listener);
}
public ServiceRegistration register(ServiceItem item) {
return lookup.register(item);
}
}
\ No newline at end of file
/**
* $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.container.spi;
import org.jivesoftware.messenger.container.Entry;
import org.jivesoftware.messenger.container.ServiceID;
import org.jivesoftware.messenger.container.ServiceRegistration;
/**
* A simple service registration implementation.
*
* @author Iain Shigeoka
*/
public class ServiceRegistrationImpl implements ServiceRegistration {
/**
* The lookup that owns this registration.
*/
private ServiceLookupImpl lookup;
/**
* The ID of the service regististered.
*/
private ServiceID id;
/**
* Create a service registration for the given lookup with the given ID.
*
* @param serviceLookup the service lookup that owns this registration.
* @param ID the id for the registration
*/
ServiceRegistrationImpl(ServiceLookupImpl serviceLookup, ServiceID ID) {
this.lookup = serviceLookup;
this.id = ID;
}
public ServiceID getServiceID() {
return id;
}
public void setAttributes(Entry[] attributes) {
lookup.setAttributes(id, attributes);
}
public void cancel() {
lookup.remove(id);
}
}
/**
* $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.disco;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.handler.IQHandler;
/**
* Base class for handling disco request. So far this class is not of much help since practically
* all the main behavior is located in each subclass.
*
* @author Gaston Dombiak
*/
public abstract class IQDiscoHandler extends IQHandler {
public XMPPServer localServer;
public IQDiscoHandler(String name) {
super(name);
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
return trackInfo;
}
}
......@@ -11,9 +11,9 @@
package org.jivesoftware.messenger.disco;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.handler.IQHandler;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -45,7 +45,7 @@ import org.xmpp.packet.JID;
*
* @author Gaston Dombiak
*/
public class IQDiscoInfoHandler extends IQDiscoHandler {
public class IQDiscoInfoHandler extends IQHandler {
private HashMap entities = new HashMap();
private List serverFeatures = new ArrayList();
......@@ -170,37 +170,20 @@ public class IQDiscoInfoHandler extends IQDiscoHandler {
*
* @param provider the ServerFeaturesProvider that provides new server features.
*/
public void addServerFeaturesProvider(ServerFeaturesProvider provider) {
private void addServerFeaturesProvider(ServerFeaturesProvider provider) {
for (Iterator it = provider.getFeatures(); it.hasNext();) {
serverFeatures.add(it.next());
}
}
/**
* Removes the features provided by the service that implements the ServerFeaturesProvider
* interface which is being removed. Example of features are: jabber:iq:agents,
* jabber:iq:time, etc.
*
* @param provider the ServerFeaturesProvider that was providing server features.
*/
public void removeServerFeaturesProvider(ServerFeaturesProvider provider) {
for (Iterator it = provider.getFeatures(); it.hasNext();) {
serverFeatures.remove(it.next());
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
public void initialize(XMPPServer server) {
super.initialize(server);
// Track the implementors of ServerFeaturesProvider so that we can collect the features
// provided by the server
trackInfo.getTrackerClasses().put(ServerFeaturesProvider.class, "ServerFeaturesProvider");
return trackInfo;
}
public void serviceAdded(Object service) {
if (service instanceof XMPPServer) {
setProvider(((XMPPServer)service).getServerInfo().getName(), getServerInfoProvider());
for (ServerFeaturesProvider provider : server.getServerFeaturesProviders()) {
addServerFeaturesProvider(provider);
}
setProvider(server.getServerInfo().getName(), getServerInfoProvider());
}
/**
......
......@@ -19,8 +19,8 @@ import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.messenger.IQHandlerInfo;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.messenger.handler.IQHandler;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
......@@ -48,12 +48,12 @@ import org.xmpp.packet.PacketError;
*
* @author Gaston Dombiak
*/
public class IQDiscoItemsHandler extends IQDiscoHandler implements ServerFeaturesProvider {
public class IQDiscoItemsHandler extends IQHandler implements ServerFeaturesProvider {
private HashMap entities = new HashMap();
private List serverItems = new ArrayList();
private IQHandlerInfo info;
public IQDiscoInfoHandler infoHandler;
private IQDiscoInfoHandler infoHandler;
public IQDiscoItemsHandler() {
super("XMPP Disco Items Handler");
......@@ -165,7 +165,7 @@ public class IQDiscoItemsHandler extends IQDiscoHandler implements ServerFeature
*
* @param provider the ServerItemsProvider that provides new server items.
*/
public void addServerItemsProvider(ServerItemsProvider provider) {
private void addServerItemsProvider(ServerItemsProvider provider) {
DiscoServerItem discoItem;
for (Iterator it = provider.getItems(); it.hasNext();) {
discoItem = (DiscoServerItem)it.next();
......@@ -184,51 +184,15 @@ public class IQDiscoItemsHandler extends IQDiscoHandler implements ServerFeature
}
}
/**
* Removes the items provided by the service that implements the ServerItemsProvider
* interface which is being removed. Example of item is:
* &lt;item jid='conference.localhost' name='Public chatrooms'/&gt;
*
* @param provider the ServerItemsProvider that was providing server items.
*/
public void removeServerItemsProvider(ServerItemsProvider provider) {
DiscoItem discoItem;
for (Iterator it = provider.getItems(); it.hasNext();) {
discoItem = (DiscoItem)it.next();
// Locate the element that represents the DiscoItem to remove
Element element = null;
boolean found = false;
for (Iterator itemsItr = serverItems.iterator(); !found && it.hasNext();) {
element = (Element)itemsItr.next();
if (discoItem.getJID().equals(element.attributeValue("jid"))) {
found = true;
break;
}
}
// If the element was found then remove it from the items provided by the server
if (found) {
serverItems.remove(element);
}
// Remove the item as a valid entity that could receive info and items disco requests
String host = StringUtils.parseServer(discoItem.getJID());
infoHandler.removeProvider(host);
removeProvider(host);
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
public void initialize(XMPPServer server) {
super.initialize(server);
// Track the implementors of ServerItemsProvider so that we can collect the items
// provided by the server
trackInfo.getTrackerClasses().put(ServerItemsProvider.class, "ServerItemsProvider");
trackInfo.getTrackerClasses().put(IQDiscoInfoHandler.class, "infoHandler");
return trackInfo;
}
public void serviceAdded(Object service) {
if (service instanceof XMPPServer) {
setProvider(((XMPPServer)service).getServerInfo().getName(), getServerItemsProvider());
infoHandler = server.getIQDiscoInfoHandler();
for (ServerItemsProvider provider : server.getServerItemsProviders()) {
addServerItemsProvider(provider);
}
setProvider(server.getServerInfo().getName(), getServerItemsProvider());
}
public Iterator getFeatures() {
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
......@@ -55,6 +54,10 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
private Element probeResponse;
private IQHandlerInfo info;
private UserManager userManager;
private XMPPServer localServer;
private SessionManager sessionManager;
/**
* Clients are not authenticated when accessing this handler.
*/
......@@ -76,7 +79,7 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
public synchronized IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
try {
Session session = SessionManager.getInstance().getSession(packet.getFrom());
Session session = sessionManager.getSession(packet.getFrom());
IQ response = null;
try {
Element iq = packet.getElement();
......@@ -226,15 +229,11 @@ public class IQAuthHandler extends IQHandler implements IQAuthInfo {
JiveGlobals.setProperty("xmpp.auth.anonymous", anonymousAllowed ? "true" : "false");
}
public UserManager userManager;
public XMPPServer localServer;
private SessionManager sessionManager = SessionManager.getInstance();
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
localServer = server;
userManager = server.getUserManager();
sessionManager = server.getSessionManager();
}
public IQHandlerInfo getInfo() {
......
......@@ -11,16 +11,9 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.ChannelHandler;
import org.jivesoftware.messenger.IQHandlerInfo;
import org.jivesoftware.messenger.IQRouter;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PacketException;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.SessionManager;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.xmlpull.v1.XmlPullParserException;
......@@ -39,10 +32,12 @@ import org.xmpp.packet.PacketError;
*/
public abstract class IQHandler extends BasicModule implements ChannelHandler {
public PacketDeliverer deliverer;
protected PacketDeliverer deliverer;
protected IQRouter router;
private SessionManager sessionManager;
/**
* Create a basic module with the given name.
*
......@@ -69,14 +64,14 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
try {
IQ response = IQ.createResultIQ(iq);
response.setError(PacketError.Condition.not_authorized);
Session session = SessionManager.getInstance().getSession(iq.getFrom());
Session session = sessionManager.getSession(iq.getFrom());
if (!session.getConnection().isClosed()) {
session.getConnection().deliver(response);
}
}
catch (Exception de) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), de);
SessionManager.getInstance().getSession(iq.getFrom()).getConnection().close();
sessionManager.getSession(iq.getFrom()).getConnection().close();
}
}
}
......@@ -107,9 +102,9 @@ public abstract class IQHandler extends BasicModule implements ChannelHandler {
*/
public abstract IQHandlerInfo getInfo();
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
deliverer = server.getPacketDeliverer();
sessionManager = server.getSessionManager();
}
}
\ No newline at end of file
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
......@@ -49,6 +48,7 @@ import org.xmpp.packet.IQ;
public class IQPrivateHandler extends IQHandler implements ServerFeaturesProvider {
private IQHandlerInfo info;
private PrivateStorage privateStorage = null;
public IQPrivateHandler() {
super("XMPP Private Storage Handler");
......@@ -77,12 +77,9 @@ public class IQPrivateHandler extends IQHandler implements ServerFeaturesProvide
return replyPacket;
}
public PrivateStorage privateStorage = null;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(PrivateStorage.class, "privateStorage");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
privateStorage = server.getPrivateStorage();
}
public IQHandlerInfo getInfo() {
......
......@@ -11,8 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.forms.DataForm;
import org.jivesoftware.messenger.forms.FormField;
......@@ -67,9 +65,10 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
private static Element probeResult;
public UserManager userManager;
public RosterManager rosterManager;
public PresenceUpdateHandler presenceHandler;
private UserManager userManager;
private RosterManager rosterManager;
private PresenceUpdateHandler presenceHandler;
private SessionManager sessionManager;
private IQHandlerInfo info;
// TODO: this value needs to be shared across all instances but not across the entire jvm...
......@@ -84,8 +83,13 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
info = new IQHandlerInfo("query", "jabber:iq:register");
}
public void initialize(Container container) {
super.initialize(container);
public void initialize(XMPPServer server) {
super.initialize(server);
userManager = server.getUserManager();
rosterManager = server.getRosterManager();
presenceHandler = server.getPresenceUpdateHandler();
sessionManager = server.getSessionManager();
if (probeResult == null) {
// Create the basic element of the probeResult which contains the basic registration
// information (e.g. username, passoword and email)
......@@ -154,7 +158,7 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
Session session = null;
try {
session = SessionManager.getInstance().getSession(packet.getFrom());
session = sessionManager.getSession(packet.getFrom());
}
catch (Exception e) {
}
......@@ -354,14 +358,6 @@ public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvid
delegates.remove(serviceName);
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(RosterManager.class, "rosterManager");
trackInfo.getTrackerClasses().put(PresenceUpdateHandler.class, "presenceHandler");
return trackInfo;
}
public IQHandlerInfo getInfo() {
return info;
}
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
......@@ -22,7 +21,6 @@ import org.jivesoftware.messenger.user.Roster;
import org.jivesoftware.messenger.user.spi.IQRosterItemImpl;
import org.xmpp.packet.*;
import org.dom4j.Element;
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
import java.util.Iterator;
......@@ -61,6 +59,11 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
private IQHandlerInfo info;
private UserManager userManager;
private XMPPServer localServer;
private SessionManager sessionManager;
private PacketRouter router;
public IQRosterHandler() {
super("XMPP Roster Handler");
info = new IQHandlerInfo("query", "jabber:iq:roster");
......@@ -111,7 +114,7 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
*
* @param packet The packet suspected of containing a roster removal
*/
private void removeRosterItem(IQRoster packet) throws UnauthorizedException, XmlPullParserException {
private void removeRosterItem(IQRoster packet) throws UnauthorizedException {
JID recipientJID = packet.getTo();
JID senderJID = packet.getFrom();
try {
......@@ -144,12 +147,12 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
* @param packet The packet that triggered this update
* @return Either a response to the roster update or null if the packet is corrupt and the session was closed down
*/
private IQ manageRoster(IQRoster packet) throws UnauthorizedException, UserAlreadyExistsException, XmlPullParserException {
private IQ manageRoster(IQRoster packet) throws UnauthorizedException, UserAlreadyExistsException {
IQ returnPacket = null;
Session session = null;
try {
SessionManager.getInstance().getSession(packet.getFrom());
sessionManager.getSession(packet.getFrom());
}
catch (Exception e) {
IQ error = IQ.createResultIQ(packet);
......@@ -258,21 +261,12 @@ public class IQRosterHandler extends IQHandler implements ServerFeaturesProvider
return response;
}
public UserManager userManager;
public XMPPServer localServer;
private SessionManager sessionManager = SessionManager.getInstance();
public PresenceManager presenceManager;
public PacketRouter router;
public RoutingTable routingTable;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
trackInfo.getTrackerClasses().put(PresenceManager.class, "presenceManager");
trackInfo.getTrackerClasses().put(PacketRouter.class, "router");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
localServer = server;
userManager = server.getUserManager();
router = server.getPacketRouter();
sessionManager = server.getSessionManager();
}
public IQHandlerInfo getInfo() {
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.IQHandlerInfo;
import org.jivesoftware.messenger.PacketException;
......@@ -49,6 +48,7 @@ public class IQVersionHandler extends IQHandler implements ServerFeaturesProvide
private static Element bodyElement;
private static Element versionElement;
private IQHandlerInfo info;
private XMPPServer localServer;
public IQVersionHandler() {
super("XMPP Server Version Handler");
......@@ -70,12 +70,9 @@ public class IQVersionHandler extends IQHandler implements ServerFeaturesProvide
return result;
}
public XMPPServer localServer;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
localServer = server;
}
public IQHandlerInfo getInfo() {
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.user.User;
......@@ -62,6 +61,7 @@ import org.xmpp.packet.PacketError;
public class IQvCardHandler extends IQHandler {
private IQHandlerInfo info;
private UserManager userManager;
public IQvCardHandler() {
super("XMPP vCard Handler");
......@@ -151,12 +151,9 @@ public class IQvCardHandler extends IQHandler {
return buf.toString();
}
public UserManager userManager;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = super.getTrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
userManager = server.getUserManager();
}
public IQHandlerInfo getInfo() {
......
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.util.CacheManager;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
......@@ -73,6 +72,10 @@ import java.util.Map;
*/
public class PresenceSubscribeHandler extends BasicModule implements ChannelHandler {
private RoutingTable routingTable;
private XMPPServer localServer;
private PacketDeliverer deliverer;
public PresenceSubscribeHandler() {
super("Presence subscription handler");
}
......@@ -358,18 +361,11 @@ public class PresenceSubscribeHandler extends BasicModule implements ChannelHand
}
}
public RoutingTable routingTable;
public UserManager userManager;
public XMPPServer localServer;
public PacketDeliverer deliverer;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
localServer = server;
routingTable = server.getRoutingTable();
deliverer = server.getPacketDeliverer();
}
public void setRouter(PresenceRouter router) {
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.handler;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
......@@ -23,7 +22,6 @@ import org.jivesoftware.messenger.user.RosterItem;
import org.jivesoftware.messenger.user.RosterManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.xmpp.packet.*;
import org.xmlpull.v1.XmlPullParserException;
import java.lang.ref.WeakReference;
import java.util.*;
......@@ -78,6 +76,13 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
private Map<String, Set> directedPresences = new HashMap<String, Set>();
private RosterManager rosterManager;
private XMPPServer localServer;
private PresenceManager presenceManager;
private PacketDeliverer deliverer;
private OfflineMessageStore messageStore;
private SessionManager sessionManager;
public PresenceUpdateHandler() {
super("Presence update handler");
}
......@@ -85,7 +90,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
public void process(Packet xmppPacket) throws UnauthorizedException, PacketException {
Presence presence = (Presence)xmppPacket;
try {
Session session = SessionManager.getInstance().getSession(presence.getFrom());
Session session = sessionManager.getSession(presence.getFrom());
Presence.Type type = presence.getType();
// Available
if (type == null) {
......@@ -137,7 +142,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
}
catch (UnauthorizedException e) {
try {
Session session = SessionManager.getInstance().getSession(presence.getFrom());
Session session = sessionManager.getSession(presence.getFrom());
presence = presence.createCopy();
if (session != null) {
presence.setFrom(new JID(null, session.getServerName(), null));
......@@ -169,7 +174,7 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
* @throws UnauthorizedException If the caller doesn't have the right permissions
* @throws UserNotFoundException If the user being updated does not exist
*/
private void initSession(Session session) throws UnauthorizedException, UserNotFoundException, XmlPullParserException {
private void initSession(Session session) throws UnauthorizedException, UserNotFoundException {
// Only user sessions need to be authenticated
if (!"".equals(session.getAddress().getNode())) {
......@@ -375,22 +380,14 @@ public class PresenceUpdateHandler extends BasicModule implements ChannelHandler
}
}
public RosterManager rosterManager;
public XMPPServer localServer;
private SessionManager sessionManager = SessionManager.getInstance();
public PresenceManager presenceManager;
public PacketDeliverer deliverer;
public OfflineMessageStore messageStore;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(RosterManager.class, "rosterManager");
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
trackInfo.getTrackerClasses().put(PresenceManager.class, "presenceManager");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(OfflineMessageStore.class, "messageStore");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
localServer = server;
rosterManager = server.getRosterManager();
presenceManager = server.getPresenceManager();
deliverer = server.getPacketDeliverer();
messageStore = server.getOfflineMessageStore();
sessionManager = server.getSessionManager();
}
/**
......
......@@ -26,16 +26,12 @@ import java.util.concurrent.LinkedBlockingQueue;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.messenger.JiveGlobals;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PacketRouter;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.RoutableChannelHandler;
import org.jivesoftware.messenger.RoutingTable;
import org.jivesoftware.messenger.XMPPServer;
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.disco.DiscoInfoProvider;
import org.jivesoftware.messenger.disco.DiscoItemsProvider;
import org.jivesoftware.messenger.disco.DiscoServerItem;
......@@ -130,22 +126,14 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
private HistoryStrategy historyStrategy;
private RoutingTable routingTable = null;
/**
* The packet deliverer for the server.
*/
public PacketDeliverer deliverer = null;
/**
* The packet router for the server.
*/
public PacketRouter router = null;
/**
* The packet manager for the server.
*/
public PresenceManager presenceManager = null;
private PacketRouter router = null;
/**
* The handler of packets with namespace jabber:iq:register for the server.
*/
public IQRegisterHandler registerHandler = null;
private IQRegisterHandler registerHandler = null;
/**
* The total time all agents took to chat *
*/
......@@ -375,36 +363,6 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
}
}
/**
* Initialize the track info for the server.
*
* @return the track information for this server.
*/
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketRouter.class, "router");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(PresenceManager.class, "presenceManager");
// TODO Remove the tracking for IQRegisterHandler when the component JEP gets implemented.
trackInfo.getTrackerClasses().put(IQRegisterHandler.class, "registerHandler");
return trackInfo;
}
public void serviceAdded(Object service) {
if (service instanceof RoutingTable) {
((RoutingTable)service).addRoute(chatServiceAddress, this);
ArrayList params = new ArrayList();
params.clear();
params.add(chatServiceName);
Log.info(LocaleUtils.getLocalizedString("startup.starting.muc", params));
}
else if (service instanceof IQRegisterHandler) {
((IQRegisterHandler) service).addDelegate(
getServiceName(),
new IQMUCRegisterHandler(this));
}
}
public void setServiceName(String name) {
JiveGlobals.setProperty("xmpp.muc.service", name);
}
......@@ -528,8 +486,8 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
JiveGlobals.setProperty("xmpp.muc.create.jid", fromArray(jids));
}
public void initialize(Container container) {
super.initialize(container);
public void initialize(XMPPServer server) {
super.initialize(server);
chatServiceName = JiveGlobals.getProperty("xmpp.muc.service");
// Trigger the strategy to load itself from the context
......@@ -593,19 +551,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
chatServiceName = "conference";
}
String serverName = null;
try {
XMPPServer server = (XMPPServer)lookup.lookup(XMPPServer.class);
if (server != null) {
serverName = server.getServerInfo().getName();
}
else {
// Try to get serverName directly.
serverName = JiveGlobals.getProperty("xmpp.domain");
}
}
catch (Exception e) {
Log.error(e);
}
if (serverName != null) {
chatServiceName += "." + serverName;
}
......@@ -618,11 +564,23 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
// (default values)
logConversationTask = new LogConversationTask();
timer.schedule(logConversationTask, log_timeout, log_timeout);
routingTable = server.getRoutingTable();
router = server.getPacketRouter();
// TODO Remove the tracking for IQRegisterHandler when the component JEP gets implemented.
registerHandler = server.getIQRegisterHandler();
registerHandler.addDelegate(getServiceName(), new IQMUCRegisterHandler(this));
// Add the route to this service
routingTable.addRoute(chatServiceAddress, this);
ArrayList params = new ArrayList();
params.clear();
params.add(chatServiceName);
Log.info(LocaleUtils.getLocalizedString("startup.starting.muc", params));
}
public void start() {
super.start();
routingTable = (RoutingTable)lookup.lookup(RoutingTable.class);
routingTable.addRoute(chatServiceAddress, this);
ArrayList params = new ArrayList();
params.clear();
......@@ -636,6 +594,7 @@ public class MultiUserChatServerImpl extends BasicModule implements MultiUserCha
public void stop() {
super.stop();
routingTable.removeRoute(chatServiceAddress);
timer.cancel();
logAllConversation();
if (registerHandler != null) {
......
......@@ -11,16 +11,38 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.container.ServiceLookup;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.audit.AuditManager;
import org.jivesoftware.messenger.audit.spi.AuditManagerImpl;
import org.jivesoftware.messenger.container.Module;
import org.jivesoftware.messenger.container.PluginManager;
import org.jivesoftware.messenger.disco.IQDiscoInfoHandler;
import org.jivesoftware.messenger.disco.IQDiscoItemsHandler;
import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
import org.jivesoftware.messenger.disco.ServerItemsProvider;
import org.jivesoftware.messenger.handler.*;
import org.jivesoftware.messenger.muc.spi.MultiUserChatServerImpl;
import org.jivesoftware.messenger.transport.TransportHandler;
import org.jivesoftware.messenger.user.RosterManager;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.spi.RosterManagerImpl;
import org.jivesoftware.messenger.user.spi.UserManagerImpl;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.Version;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.xmpp.packet.JID;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.*;
......@@ -31,33 +53,51 @@ import java.util.*;
*
* @author Iain Shigeoka
*/
public class BasicServer extends BasicModule implements XMPPServer {
public class BasicServer implements XMPPServer {
private String name;
private Version version;
private Date startDate;
private Date stopDate;
private ServiceLookup lookup;
private ConnectionManager connectionManager;
private boolean initialized = false;
/**
* Create a default loopback test server.
* All modules loaded by this container
*/
private Map<Class,Module> modules = new HashMap<Class,Module>();
/**
* Location of the messengerHome directory. All configuration files should be
* located here.
*/
private File messengerHome;
private ClassLoader loader;
private PluginManager pluginManager;
/**
* True if in setup mode
*/
private boolean setupMode = true;
private static final String STARTER_CLASSNAME =
"org.jivesoftware.messenger.starter.ServerStarter";
private static final String WRAPPER_CLASSNAME =
"org.tanukisoftware.wrapper.WrapperManager";
/**
* Creates a server and starts it.
*/
public BasicServer() {
super("XMPP Server");
start();
}
public XMPPServerInfo getServerInfo() {
Iterator ports;
if (connectionManager == null) {
connectionManager = (ConnectionManager)lookup.lookup(ConnectionManager.class);
}
if (connectionManager == null) {
if (getConnectionManager() == null) {
ports = Collections.EMPTY_LIST.iterator();
}
else {
ports = connectionManager.getPorts();
ports = getConnectionManager().getPorts();
}
if (!initialized) {
throw new IllegalStateException("Not initialized yet");
......@@ -77,29 +117,43 @@ public class BasicServer extends BasicModule implements XMPPServer {
return new JID(username, name, resource);
}
public String getName() {
return "XMPP Server Kernel";
}
private void initialize() throws FileNotFoundException {
locateMessenger();
public void initialize(Container container) {
super.initialize(container);
try {
lookup = container.getServiceLookup();
name = JiveGlobals.getProperty("xmpp.domain");
if (name == null) {
name = "127.0.0.1";
}
version = new Version(2, 1, 0, Version.ReleaseStatus.Beta, -1);
initialized = true;
if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
setupMode = false;
}
catch (UnauthorizedException e) {
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
if (isStandAlone()) {
Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());
}
loader = Thread.currentThread().getContextClassLoader();
initialized = true;
}
public void start() {
super.start();
try {
initialize();
if (!setupMode) {
verifyDataSource();
loadModules();
initModules();
startModules();
}
// Load plugins.
File pluginDir = new File(messengerHome, "plugins");
pluginManager = new PluginManager(pluginDir);
pluginManager.start();
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.MEDIUM);
List params = new ArrayList();
......@@ -109,19 +163,461 @@ public class BasicServer extends BasicModule implements XMPPServer {
Log.info(startupBanner);
System.out.println(startupBanner);
// params.clear();
// params.add(name);
// Log.info(LocaleUtils.getLocalizedString("startup.starting", params));
// Register the server as an MBean.
// MBeanManager.registerMBean(this, ("Server:Name=" + getName()));
startDate = new Date();
stopDate = null;
}
catch (Exception e) {
e.printStackTrace();
Log.error(e);
System.out.println(LocaleUtils.getLocalizedString("startup.error"));
shutdownServer();
}
}
private void loadModules() {
// Load boot modules
loadModule(RoutingTableImpl.class.getName());
loadModule(AuditManagerImpl.class.getName());
loadModule(UserManagerImpl.class.getName());
loadModule(RosterManagerImpl.class.getName());
loadModule(PrivateStorage.class.getName());
// Load core modules
loadModule(ConnectionManagerImpl.class.getName());
loadModule(PresenceManagerImpl.class.getName());
loadModule(SessionManager.class.getName());
loadModule(PacketRouterImpl.class.getName());
loadModule(IQRouterImpl.class.getName());
loadModule(MessageRouterImpl.class.getName());
loadModule(PresenceRouterImpl.class.getName());
loadModule(PacketTransporterImpl.class.getName());
loadModule(PacketDelivererImpl.class.getName());
loadModule(TransportHandler.class.getName());
loadModule(OfflineMessageStrategy.class.getName());
loadModule(OfflineMessageStore.class.getName());
// Load standard modules
loadModule(IQAuthHandler.class.getName());
loadModule(IQPrivateHandler.class.getName());
loadModule(IQRegisterHandler.class.getName());
loadModule(IQRosterHandler.class.getName());
loadModule(IQTimeHandler.class.getName());
loadModule(IQvCardHandler.class.getName());
loadModule(IQVersionHandler.class.getName());
loadModule(PresenceSubscribeHandler.class.getName());
loadModule(PresenceUpdateHandler.class.getName());
loadModule(IQDiscoInfoHandler.class.getName());
loadModule(IQDiscoItemsHandler.class.getName());
loadModule(MultiUserChatServerImpl.class.getName());
}
/**
* Loads a module.
*
* @param module the name of the class that implements the Module interface.
*/
private void loadModule(String module) {
Module mod = null;
try {
Class modClass = loader.loadClass(module);
mod = (Module)modClass.newInstance();
this.modules.put(modClass, mod);
}
catch (Exception e) {
e.printStackTrace();
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
private void initModules() {
for (Module module : modules.values()) {
boolean isInitialized = false;
try {
module.initialize(this);
isInitialized = true;
}
catch (Exception e) {
e.printStackTrace();
// Remove the failed initialized module
this.modules.remove(module.getClass());
if (isInitialized) {
module.stop();
module.destroy();
}
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
/**
* <p>Following the loading and initialization of all the modules
* this method is called to iterate through the known modules and
* start them.</p>
*/
private void startModules() {
for (Module module : modules.values()) {
boolean started = false;
try {
module.start();
}
catch (Exception e) {
if (started && module != null) {
module.stop();
module.destroy();
}
Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
}
}
}
public void stop() {
super.stop();
// Only do a system exit if we're running standalone
if (isStandAlone()) {
// if we're in a wrapper, we have to tell the wrapper to shut us down
if (isRestartable()) {
try {
Class wrapperClass = Class.forName(WRAPPER_CLASSNAME);
Method stopMethod = wrapperClass.getMethod("stop",
new Class[]{Integer.TYPE});
stopMethod.invoke(null, new Object[]{0});
}
catch (Exception e) {
Log.error("Could not stop container", e);
}
}
else {
shutdownServer();
stopDate = new Date();
Thread shutdownThread = new ShutdownThread();
shutdownThread.setDaemon(true);
shutdownThread.start();
}
}
}
private boolean isRestartable() {
boolean restartable = false;
try {
restartable = Class.forName(WRAPPER_CLASSNAME) != null;
}
catch (ClassNotFoundException e) {
restartable = false;
}
return restartable;
}
private boolean isStandAlone() {
boolean standalone = false;
try {
standalone = Class.forName(STARTER_CLASSNAME) != null;
}
catch (ClassNotFoundException e) {
standalone = false;
}
return standalone;
}
/**
* Verify that the database is accessible.
*/
private void verifyDataSource() {
java.sql.Connection conn = null;
try {
conn = DbConnectionManager.getConnection();
PreparedStatement stmt = conn.prepareStatement(
"SELECT count(*) FROM jiveID");
ResultSet rs = stmt.executeQuery();
rs.next();
rs.close();
stmt.close();
}
catch (Exception e) {
System.err.println("Database setup or configuration error: " +
"Please verify your database settings and check the " +
"logs/error.log file for detailed error messages.");
Log.error("Database could not be accessed", e);
throw new IllegalArgumentException();
}
finally {
if (conn != null) {
try { conn.close(); }
catch (SQLException e) { Log.error(e); }
}
}
}
/**
* Verifies that the given home guess is a real Messenger home directory.
* We do the verification by checking for the Messenger config file in
* the config dir of jiveHome.
*
* @param homeGuess a guess at the path to the home directory.
* @param jiveConfigName the name of the config file to check.
* @return a file pointing to the home directory or null if the
* home directory guess was wrong.
* @throws java.io.FileNotFoundException if there was a problem with the home
* directory provided
*/
private File verifyHome(String homeGuess, String jiveConfigName) throws FileNotFoundException {
File realHome = null;
File guess = new File(homeGuess);
File configFileGuess = new File(guess, jiveConfigName);
if (configFileGuess.exists()) {
realHome = guess;
}
File forumsHome = new File(guess, jiveConfigName);
if (!forumsHome.exists()) {
throw new FileNotFoundException();
}
try{
return new File(realHome.getCanonicalPath());
}
catch(Exception ex){
throw new FileNotFoundException();
}
}
/**
* <p>Retrieve the jive home for the container.</p>
*
* @throws FileNotFoundException If jiveHome could not be located
*/
private void locateMessenger() throws FileNotFoundException {
String jiveConfigName = "conf" + File.separator + "jive-messenger.xml";
// First, try to load it jiveHome as a system property.
if (messengerHome == null) {
String homeProperty = System.getProperty("messengerHome");
try {
if (homeProperty != null) {
messengerHome = verifyHome(homeProperty, jiveConfigName);
}
}
catch (FileNotFoundException fe) {
}
}
// If we still don't have messengerHome, let's assume this is standalone
// and just look for messengerHome in a standard sub-dir location and verify
// by looking for the config file
if (messengerHome == null) {
try {
messengerHome = verifyHome("..", jiveConfigName).getCanonicalFile();
}
catch (FileNotFoundException fe) {
}
catch (IOException ie) {
}
}
// If messengerHome is still null, no outside process has set it and
// we have to attempt to load the value from messenger_init.xml,
// which must be in the classpath.
if (messengerHome == null) {
InputStream in = null;
try {
in = getClass().getResourceAsStream("/messenger_init.xml");
if (in != null) {
SAXReader reader = new SAXReader();
Document doc = reader.read(in);
String path = doc.getRootElement().getText();
try {
if (path != null) {
messengerHome = verifyHome(path, jiveConfigName);
}
}
catch (FileNotFoundException fe) {
fe.printStackTrace();
}
}
}
catch (Exception e) {
System.err.println("Error loading messenger_init.xml to find messengerHome.");
e.printStackTrace();
}
finally {
try { if (in != null) { in.close(); } }
catch (Exception e) {
System.err.println("Could not close open connection");
e.printStackTrace();
}
}
}
if (messengerHome == null) {
System.err.println("Could not locate messengerHome");
throw new FileNotFoundException();
}
else {
JiveGlobals.messengerHome = messengerHome.toString();
}
}
/**
* <p>A thread to ensure the server shuts down no matter what.</p>
* <p>Spawned when stop() is called in standalone mode, we wait a few
* seconds then call system exit().</p>
*
* @author Iain Shigeoka
*/
private class ShutdownHookThread extends Thread {
/**
* <p>Logs the server shutdown.</p>
*/
public void run() {
shutdownServer();
Log.info("Server halted");
System.err.println("Server halted");
}
}
/**
* <p>A thread to ensure the server shuts down no matter what.</p>
* <p>Spawned when stop() is called in standalone mode, we wait a few
* seconds then call system exit().</p>
*
* @author Iain Shigeoka
*/
private class ShutdownThread extends Thread {
/**
* <p>Shuts down the JVM after a 5 second delay.</p>
*/
public void run() {
try {
Thread.sleep(5000);
// No matter what, we make sure it's dead
System.exit(0);
}
catch (InterruptedException e) {
}
}
}
/**
* Makes a best effort attempt to shutdown the server
*/
private void shutdownServer() {
// Get all modules and stop and destroy them
for (Module module : modules.values()) {
module.stop();
module.destroy();
}
modules.clear();
// Stop all plugins
if (pluginManager != null) {
pluginManager.shutdown();
}
// TODO: hack to allow safe stopping
Log.info("Jive Messenger stopped");
}
public ConnectionManager getConnectionManager() {
return (ConnectionManager) modules.get(ConnectionManagerImpl.class);
}
public RoutingTable getRoutingTable() {
return (RoutingTable) modules.get(RoutingTableImpl.class);
}
public PacketDeliverer getPacketDeliverer() {
return (PacketDeliverer) modules.get(PacketDelivererImpl.class);
}
public RosterManager getRosterManager() {
return (RosterManager) modules.get(RosterManagerImpl.class);
}
public PresenceManager getPresenceManager() {
return (PresenceManager) modules.get(PresenceManagerImpl.class);
}
public OfflineMessageStore getOfflineMessageStore() {
return (OfflineMessageStore) modules.get(OfflineMessageStore.class);
}
public OfflineMessageStrategy getOfflineMessageStrategy() {
return (OfflineMessageStrategy) modules.get(OfflineMessageStrategy.class);
}
public PacketRouter getPacketRouter() {
return (PacketRouter) modules.get(PacketRouterImpl.class);
}
public IQRegisterHandler getIQRegisterHandler() {
return (IQRegisterHandler) modules.get(IQRegisterHandler.class);
}
public List<IQHandler> getIQHandlers() {
List<IQHandler> answer = new ArrayList<IQHandler>();
for (Module module : modules.values()) {
if (module instanceof IQHandler) {
answer.add((IQHandler)module);
}
}
return answer;
}
public SessionManager getSessionManager() {
return (SessionManager) modules.get(SessionManager.class);
}
public TransportHandler getTransportHandler() {
return (TransportHandler) modules.get(TransportHandler.class);
}
public PresenceUpdateHandler getPresenceUpdateHandler() {
return (PresenceUpdateHandler) modules.get(PresenceUpdateHandler.class);
}
public PresenceSubscribeHandler getPresenceSubscribeHandler() {
return (PresenceSubscribeHandler) modules.get(PresenceSubscribeHandler.class);
}
public IQRouter getIQRouter() {
return (IQRouter) modules.get(IQRouterImpl.class);
}
public MessageRouter getMessageRouter() {
return (MessageRouter) modules.get(MessageRouterImpl.class);
}
public PresenceRouter getPresenceRouter() {
return (PresenceRouter) modules.get(PresenceRouterImpl.class);
}
public UserManager getUserManager() {
return (UserManager) modules.get(UserManagerImpl.class);
}
public AuditManager getAuditManager() {
return (AuditManager) modules.get(AuditManagerImpl.class);
}
public List<ServerFeaturesProvider> getServerFeaturesProviders() {
List<ServerFeaturesProvider> answer = new ArrayList<ServerFeaturesProvider>();
for (Module module : modules.values()) {
if (module instanceof ServerFeaturesProvider) {
answer.add((ServerFeaturesProvider) module);
}
}
return answer;
}
public List<ServerItemsProvider> getServerItemsProviders() {
List<ServerItemsProvider> answer = new ArrayList<ServerItemsProvider>();
for (Module module : modules.values()) {
if (module instanceof ServerItemsProvider) {
answer.add((ServerItemsProvider) module);
}
}
return answer;
}
public IQDiscoInfoHandler getIQDiscoInfoHandler() {
return (IQDiscoInfoHandler) modules.get(IQDiscoInfoHandler.class);
}
public PrivateStorage getPrivateStorage() {
return (PrivateStorage) modules.get(PrivateStorage.class);
}
}
\ No newline at end of file
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
......@@ -36,6 +35,13 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
private SSLSocketAcceptThread sslSocketThread;
private ArrayList ports;
private AuditManager auditManager;
private SessionManager sessionManager;
private PacketDeliverer deliverer;
private PacketRouter router;
private String serverName;
private XMPPServer server;
public ConnectionManagerImpl() {
super("Connection Manager");
ports = new ArrayList(2);
......@@ -100,13 +106,6 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
return ports.iterator();
}
public AuditManager auditManager;
private SessionManager sessionManager = SessionManager.getInstance();
public PacketDeliverer deliverer;
public PacketRouter router;
private String serverName;
public XMPPServer server;
public void addSocket(Socket sock, boolean isSecure) {
try {
// the order of these calls is critical (stupid huh?)
......@@ -129,20 +128,13 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
}
}
public TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "server");
trackInfo.getTrackerClasses().put(PacketRouter.class, "router");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(AuditManager.class, "auditManager");
return trackInfo;
}
public void serviceAdded(Object service) {
if (service instanceof XMPPServer) {
serverName = server.getServerInfo().getName();
}
createSocket();
public void initialize(XMPPServer server) {
super.initialize(server);
this.server = server;
router = server.getPacketRouter();
deliverer = server.getPacketDeliverer();
auditManager = server.getAuditManager();
sessionManager = server.getSessionManager();
}
// Used to know if the sockets can be started (the connection manager has been started)
......@@ -150,12 +142,6 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
// Used to know if the sockets have been started
private boolean isSocketStarted = false;
public void serviceRemoved(Object service) {
if (server == null) {
serverName = null;
}
}
// #####################################################################
// Module management
// #####################################################################
......@@ -163,6 +149,7 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
public void start() {
super.start();
isStarted = true;
serverName = server.getServerInfo().getName();
createSocket();
}
......@@ -176,5 +163,6 @@ public class ConnectionManagerImpl extends BasicModule implements ConnectionMana
sslSocketThread.shutdown();
sslSocketThread = null;
}
serverName = null;
}
}
......@@ -18,7 +18,6 @@ import java.util.Map;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.handler.IQHandler;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
......@@ -34,10 +33,8 @@ import org.dom4j.Element;
*/
public class IQRouterImpl extends BasicModule implements IQRouter {
public XMPPServer localServer;
public OfflineMessageStore messageStore;
public RoutingTable routingTable;
public LinkedList iqHandlers = new LinkedList();
private RoutingTable routingTable;
private LinkedList iqHandlers = new LinkedList();
private Map namespace2Handlers = new HashMap();
private SessionManager sessionManager;
......@@ -46,14 +43,13 @@ public class IQRouterImpl extends BasicModule implements IQRouter {
*/
public IQRouterImpl() {
super("XMPP IQ Router");
sessionManager = SessionManager.getInstance();
}
public void route(IQ packet) {
if (packet == null) {
throw new NullPointerException();
}
Session session = SessionManager.getInstance().getSession(packet.getFrom());
Session session = sessionManager.getSession(packet.getFrom());
if (session == null || session.getStatus() == Session.STATUS_AUTHENTICATED
|| (isLocalServer(packet.getTo())
&& ("jabber:iq:auth".equals(packet.getChildElement().getNamespaceURI())
......@@ -188,13 +184,10 @@ public class IQRouterImpl extends BasicModule implements IQRouter {
return handler;
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
trackInfo.getTrackerClasses().put(OfflineMessageStore.class, "messageStore");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
trackInfo.getTrackerClasses().put(IQHandler.class, "iqHandlers");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
routingTable = server.getRoutingTable();
iqHandlers.addAll(server.getIQHandlers());
sessionManager = server.getSessionManager();
}
}
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.util.Log;
......@@ -27,8 +26,9 @@ import org.xmpp.packet.PacketError;
*/
public class MessageRouterImpl extends BasicModule implements MessageRouter {
public OfflineMessageStrategy messageStrategy;
public RoutingTable routingTable;
private OfflineMessageStrategy messageStrategy;
private RoutingTable routingTable;
private SessionManager sessionManager;
/**
* <p>Create a packet router.</p>
......@@ -41,7 +41,7 @@ public class MessageRouterImpl extends BasicModule implements MessageRouter {
if (packet == null) {
throw new NullPointerException();
}
Session session = SessionManager.getInstance().getSession(packet.getFrom());
Session session = sessionManager.getSession(packet.getFrom());
if (session == null
|| session.getStatus() == Session.STATUS_AUTHENTICATED)
{
......@@ -74,11 +74,10 @@ public class MessageRouterImpl extends BasicModule implements MessageRouter {
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(OfflineMessageStrategy.class, "messageStrategy");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
messageStrategy = server.getOfflineMessageStrategy();
routingTable = server.getRoutingTable();
sessionManager = server.getSessionManager();
}
}
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.net.SocketPacketWriteHandler;
......@@ -30,8 +29,8 @@ public class PacketDelivererImpl extends BasicModule implements PacketDeliverer
*/
protected ChannelHandler deliverHandler;
public OfflineMessageStrategy messageStrategy;
private SessionManager sessionManager = SessionManager.getInstance();
private OfflineMessageStrategy messageStrategy;
private SessionManager sessionManager;
public PacketDelivererImpl() {
super("Packet Delivery");
......@@ -47,21 +46,19 @@ public class PacketDelivererImpl extends BasicModule implements PacketDeliverer
deliverHandler.process(packet);
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(OfflineMessageStrategy.class, "messageStrategy");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
messageStrategy = server.getOfflineMessageStrategy();
sessionManager = server.getSessionManager();
}
public void serviceAdded(Object service) {
if (sessionManager != null && messageStrategy != null) {
public void start() throws IllegalStateException {
super.start();
deliverHandler = new SocketPacketWriteHandler(sessionManager, messageStrategy);
}
}
public void serviceRemoved(Object service) {
if (sessionManager == null || messageStrategy == null) {
public void stop() {
super.stop();
deliverHandler = null;
}
}
}
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.*;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Message;
......@@ -25,9 +24,9 @@ import org.xmpp.packet.IQ;
* @author Iain Shigeoka
*/
public class PacketRouterImpl extends BasicModule implements PacketRouter {
public IQRouter iqRouter;
public PresenceRouter presenceRouter;
public MessageRouter messageRouter;
private IQRouter iqRouter;
private PresenceRouter presenceRouter;
private MessageRouter messageRouter;
/**
* Initialize ComponentManager to handle delegation of packets.
......@@ -103,11 +102,10 @@ public class PacketRouterImpl extends BasicModule implements PacketRouter {
return false;
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(IQRouter.class, "iqRouter");
trackInfo.getTrackerClasses().put(MessageRouter.class, "messageRouter");
trackInfo.getTrackerClasses().put(PresenceRouter.class, "presenceRouter");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
iqRouter = server.getIQRouter();
messageRouter = server.getMessageRouter();
presenceRouter = server.getPresenceRouter();
}
}
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.auth.UnauthorizedException;
......@@ -29,17 +28,17 @@ public class PacketTransporterImpl extends BasicModule {
/**
* The handler that does the actual delivery (could be a channel instead)
*/
public TransportHandler transportHandler;
private TransportHandler transportHandler;
/**
* deliverer for xmpp server
*/
public PacketDeliverer deliverer;
private PacketDeliverer deliverer;
/**
* xmpp server
*/
public XMPPServer xmppServer;
private XMPPServer xmppServer;
/**
* This is a singleton, you can't create one. Be very careful not to do anything
......@@ -88,11 +87,10 @@ public class PacketTransporterImpl extends BasicModule {
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "xmppServer");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(TransportHandler.class, "transportHandler");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
xmppServer = server;
deliverer = server.getPacketDeliverer();
transportHandler = server.getTransportHandler();
}
}
......@@ -23,14 +23,11 @@ import org.jivesoftware.messenger.Component;
import org.jivesoftware.messenger.ComponentManager;
import org.jivesoftware.messenger.PacketDeliverer;
import org.jivesoftware.messenger.PresenceManager;
import org.jivesoftware.messenger.RoutingTable;
import org.jivesoftware.messenger.Session;
import org.jivesoftware.messenger.SessionManager;
import org.jivesoftware.messenger.XMPPServer;
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.User;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
......@@ -56,11 +53,10 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
*/
private Cache foreignUserCache;
public UserManager userManager;
private SessionManager sessionManager = SessionManager.getInstance();
public RoutingTable routingTable;
public XMPPServer server;
public PacketDeliverer deliverer;
private UserManager userManager;
private SessionManager sessionManager;
private XMPPServer server;
private PacketDeliverer deliverer;
private ComponentManager componentManager;
......@@ -392,20 +388,15 @@ public class PresenceManagerImpl extends BasicModule implements PresenceManager
// Module management
// #####################################################################
public void initialize(Container container) {
super.initialize(container);
public void initialize(XMPPServer server) {
super.initialize(server);
this.server = server;
userManager = server.getUserManager();
deliverer = server.getPacketDeliverer();
sessionManager = server.getSessionManager();
initializeCaches();
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(UserManager.class, "userManager");
trackInfo.getTrackerClasses().put(XMPPServer.class, "server");
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
return trackInfo;
}
public Component getPresenceComponent(JID probee) {
// Check for registered components
Component component = componentManager.getComponent(probee.toBareJID());
......
......@@ -12,7 +12,6 @@
package org.jivesoftware.messenger.spi;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.messenger.*;
......@@ -30,10 +29,10 @@ import org.xmpp.packet.PacketError;
*/
public class PresenceRouterImpl extends BasicModule implements PresenceRouter {
public XMPPServer localServer;
public RoutingTable routingTable;
public PresenceUpdateHandler updateHandler;
public PresenceSubscribeHandler subscribeHandler;
private RoutingTable routingTable;
private PresenceUpdateHandler updateHandler;
private PresenceSubscribeHandler subscribeHandler;
private SessionManager sessionManager;
/**
* Create a packet router.
......@@ -46,7 +45,7 @@ public class PresenceRouterImpl extends BasicModule implements PresenceRouter {
if (packet == null) {
throw new NullPointerException();
}
Session session = SessionManager.getInstance().getSession(packet.getFrom());
Session session = sessionManager.getSession(packet.getFrom());
if (session == null || session.getStatus() == Session.STATUS_AUTHENTICATED) {
handle(packet);
}
......@@ -105,7 +104,7 @@ public class PresenceRouterImpl extends BasicModule implements PresenceRouter {
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error.routing"), e);
try {
Session session = SessionManager.getInstance().getSession(packet.getFrom());
Session session = sessionManager.getSession(packet.getFrom());
if (session != null) {
Connection conn = session.getConnection();
if (conn != null) {
......@@ -119,13 +118,11 @@ public class PresenceRouterImpl extends BasicModule implements PresenceRouter {
}
}
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(XMPPServer.class, "localServer");
trackInfo.getTrackerClasses().put(RoutingTable.class, "routingTable");
trackInfo.getTrackerClasses().put(PresenceUpdateHandler.class, "updateHandler");
trackInfo.getTrackerClasses().put(PresenceSubscribeHandler.class, "subscribeHandler");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
routingTable = server.getRoutingTable();
updateHandler = server.getPresenceUpdateHandler();
subscribeHandler = server.getPresenceSubscribeHandler();
sessionManager = server.getSessionManager();
}
}
......@@ -81,7 +81,7 @@ public class SessionImpl implements Session {
conn = connection;
this.streamID = streamID;
this.serverName = serverName;
this.address = new JID(null, null, null);
this.address = new JID(null, serverName, null);
presence = new Presence();
this.sessionManager = SessionManager.getInstance();
......
......@@ -50,7 +50,7 @@ public class ServerStarter {
Thread.currentThread().setContextClassLoader(loader);
Class containerClass = loader.loadClass(
"org.jivesoftware.messenger.XMPPBootContainer");
"org.jivesoftware.messenger.spi.BasicServer");
containerClass.newInstance();
}
catch (Exception e) {
......
......@@ -11,7 +11,6 @@
package org.jivesoftware.messenger.transport;
import org.jivesoftware.messenger.container.TrackInfo;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
......@@ -33,6 +32,8 @@ public class TransportHandler extends BasicModule implements ChannelHandler {
private Map<String, Channel> transports = new ConcurrentHashMap<String, Channel>();
private PacketDeliverer deliverer;
public TransportHandler() {
super("Transport handler");
}
......@@ -68,11 +69,8 @@ public class TransportHandler extends BasicModule implements ChannelHandler {
}
}
public PacketDeliverer deliverer;
protected TrackInfo getTrackInfo() {
TrackInfo trackInfo = new TrackInfo();
trackInfo.getTrackerClasses().put(PacketDeliverer.class, "deliverer");
return trackInfo;
public void initialize(XMPPServer server) {
super.initialize(server);
deliverer = server.getPacketDeliverer();
}
}
\ No newline at end of file
......@@ -22,12 +22,12 @@ import java.util.List;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.messenger.auth.UnauthorizedException;
import org.jivesoftware.messenger.container.BasicModule;
import org.jivesoftware.messenger.container.Container;
import org.jivesoftware.messenger.user.User;
import org.jivesoftware.messenger.user.UserAlreadyExistsException;
import org.jivesoftware.messenger.user.UserManager;
import org.jivesoftware.messenger.user.UserNotFoundException;
import org.jivesoftware.messenger.user.UserProviderFactory;
import org.jivesoftware.messenger.XMPPServer;
import org.jivesoftware.stringprep.Stringprep;
import org.jivesoftware.stringprep.StringprepException;
import org.jivesoftware.util.Cache;
......@@ -291,8 +291,8 @@ public class UserManagerImpl extends BasicModule implements UserManager {
// Module management
// #####################################################################
public void initialize(Container container) {
super.initialize(container);
public void initialize(XMPPServer server) {
super.initialize(server);
initializeCaches();
}
}
\ No newline at end of file
......@@ -114,10 +114,6 @@ public class AcceptManagerImpl extends BasicModule implements AcceptManager {
return trackInfo;
}
public void initialize(Container container) {
super.initialize(container);
}
protected void serviceAdded(Object service) {
if (service instanceof ConnectionManager){
connManager = (ConnectionManager) service;
......
......@@ -12,7 +12,6 @@
org.jivesoftware.messenger.container.ServiceLookupFactory,
org.jivesoftware.messenger.auth.UnauthorizedException,
org.jivesoftware.messenger.JiveGlobals,
org.jivesoftware.messenger.XMPPBootContainer,
java.util.Map,
java.util.Iterator"
%>
......
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