1 /*
2  * Copyright (C) 2004-2008 Jive Software. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.jivesoftware.openfire;
18 
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.InputStreamReader;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.Method;
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 import java.sql.Connection;
30 import java.sql.PreparedStatement;
31 import java.sql.ResultSet;
32 import java.util.*;
33 import java.util.concurrent.CopyOnWriteArrayList;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit;
37 
38 import com.google.common.util.concurrent.SimpleTimeLimiter;
39 import com.google.common.util.concurrent.ThreadFactoryBuilder;
40 import org.apache.logging.log4j.LogManager;
41 import org.dom4j.Document;
42 import org.jivesoftware.database.DbConnectionManager;
43 import org.jivesoftware.database.JNDIDataSourceProvider;
44 import org.jivesoftware.openfire.admin.AdminManager;
45 import org.jivesoftware.openfire.audit.AuditManager;
46 import org.jivesoftware.openfire.audit.spi.AuditManagerImpl;
47 import org.jivesoftware.openfire.auth.AuthFactory;
48 import org.jivesoftware.openfire.cluster.ClusterManager;
49 import org.jivesoftware.openfire.cluster.ClusterMonitor;
50 import org.jivesoftware.openfire.cluster.NodeID;
51 import org.jivesoftware.openfire.commands.AdHocCommandHandler;
52 import org.jivesoftware.openfire.component.InternalComponentManager;
53 import org.jivesoftware.openfire.container.AdminConsolePlugin;
54 import org.jivesoftware.openfire.container.Module;
55 import org.jivesoftware.openfire.container.PluginManager;
56 import org.jivesoftware.openfire.disco.IQDiscoInfoHandler;
57 import org.jivesoftware.openfire.disco.IQDiscoItemsHandler;
58 import org.jivesoftware.openfire.disco.ServerFeaturesProvider;
59 import org.jivesoftware.openfire.disco.ServerIdentitiesProvider;
60 import org.jivesoftware.openfire.disco.ServerItemsProvider;
61 import org.jivesoftware.openfire.disco.UserFeaturesProvider;
62 import org.jivesoftware.openfire.disco.UserIdentitiesProvider;
63 import org.jivesoftware.openfire.disco.UserItemsProvider;
64 import org.jivesoftware.openfire.entitycaps.EntityCapabilitiesManager;
65 import org.jivesoftware.openfire.filetransfer.DefaultFileTransferManager;
66 import org.jivesoftware.openfire.filetransfer.FileTransferManager;
67 import org.jivesoftware.openfire.filetransfer.proxy.FileTransferProxy;
68 import org.jivesoftware.openfire.group.GroupManager;
69 import org.jivesoftware.openfire.handler.IQBindHandler;
70 import org.jivesoftware.openfire.handler.IQBlockingHandler;
71 import org.jivesoftware.openfire.handler.IQEntityTimeHandler;
72 import org.jivesoftware.openfire.handler.IQHandler;
73 import org.jivesoftware.openfire.handler.IQLastActivityHandler;
74 import org.jivesoftware.openfire.handler.IQMessageCarbonsHandler;
75 import org.jivesoftware.openfire.handler.IQOfflineMessagesHandler;
76 import org.jivesoftware.openfire.handler.IQPingHandler;
77 import org.jivesoftware.openfire.handler.IQPrivacyHandler;
78 import org.jivesoftware.openfire.handler.IQPrivateHandler;
79 import org.jivesoftware.openfire.handler.IQRegisterHandler;
80 import org.jivesoftware.openfire.handler.IQRosterHandler;
81 import org.jivesoftware.openfire.handler.IQSessionEstablishmentHandler;
82 import org.jivesoftware.openfire.handler.IQSharedGroupHandler;
83 import org.jivesoftware.openfire.handler.IQVersionHandler;
84 import org.jivesoftware.openfire.handler.IQvCardHandler;
85 import org.jivesoftware.openfire.handler.PresenceSubscribeHandler;
86 import org.jivesoftware.openfire.handler.PresenceUpdateHandler;
87 import org.jivesoftware.openfire.keystore.CertificateStoreManager;
88 import org.jivesoftware.openfire.keystore.IdentityStore;
89 import org.jivesoftware.openfire.lockout.LockOutManager;
90 import org.jivesoftware.openfire.mediaproxy.MediaProxyService;
91 import org.jivesoftware.openfire.muc.MultiUserChatManager;
92 import org.jivesoftware.openfire.net.MulticastDNSService;
93 import org.jivesoftware.openfire.net.ServerTrafficCounter;
94 import org.jivesoftware.openfire.pep.IQPEPHandler;
95 import org.jivesoftware.openfire.pep.IQPEPOwnerHandler;
96 import org.jivesoftware.openfire.pubsub.PubSubModule;
97 import org.jivesoftware.openfire.roster.DefaultRosterItemProvider;
98 import org.jivesoftware.openfire.roster.RosterItem;
99 import org.jivesoftware.openfire.roster.RosterItemProvider;
100 import org.jivesoftware.openfire.roster.RosterManager;
101 import org.jivesoftware.openfire.sasl.AnonymousSaslServer;
102 import org.jivesoftware.openfire.security.SecurityAuditManager;
103 import org.jivesoftware.openfire.session.ConnectionSettings;
104 import org.jivesoftware.openfire.session.RemoteSessionLocator;
105 import org.jivesoftware.openfire.session.SoftwareVersionManager;
106 import org.jivesoftware.openfire.session.SoftwareServerVersionManager;
107 import org.jivesoftware.openfire.spi.ConnectionManagerImpl;
108 import org.jivesoftware.openfire.spi.ConnectionType;
109 import org.jivesoftware.openfire.spi.PacketDelivererImpl;
110 import org.jivesoftware.openfire.spi.PacketRouterImpl;
111 import org.jivesoftware.openfire.spi.PacketTransporterImpl;
112 import org.jivesoftware.openfire.spi.PresenceManagerImpl;
113 import org.jivesoftware.openfire.spi.RoutingTableImpl;
114 import org.jivesoftware.openfire.spi.XMPPServerInfoImpl;
115 import org.jivesoftware.openfire.transport.TransportHandler;
116 import org.jivesoftware.openfire.update.UpdateManager;
117 import org.jivesoftware.openfire.user.User;
118 import org.jivesoftware.openfire.user.UserManager;
119 import org.jivesoftware.openfire.vcard.VCardManager;
120 import org.jivesoftware.util.*;
121 import org.jivesoftware.openfire.archive.ArchiveManager;
122 import org.jivesoftware.util.cache.CacheFactory;
123 import org.slf4j.Logger;
124 import org.slf4j.LoggerFactory;
125 import org.xmpp.packet.JID;
126 import org.xmpp.packet.Message;
127 
128 import com.google.common.reflect.ClassPath;
129 
130 /**
131  * The main XMPP server that will load, initialize and start all the server's
132  * modules. The server is unique in the JVM and could be obtained by using the
133  * {@link #getInstance()} method.
134  * <p>
135  * The loaded modules will be initialized and may access through the server other
136  * modules. This means that the only way for a module to locate another module is
137  * through the server. The server maintains a list of loaded modules.
138  * </p>
139  * <p>
140  * After starting up all the modules the server will load any available plugin.
141  * For more information see: {@link org.jivesoftware.openfire.container.PluginManager}.
142  * </p>
143  * <p>A configuration file keeps the server configuration. This information is required for the
144  * server to work correctly. The server assumes that the configuration file is named
145  * <b>openfire.xml</b> and is located in the <b>conf</b> folder. The folder that keeps
146  * the configuration file must be located under the home folder. The server will try different
147  * methods to locate the home folder.</p>
148  * <ol>
149  * <li><b>system property</b> - The server will use the value defined in the <i>openfireHome</i>
150  * system property.</li>
151  * <li><b>working folder</b> -  The server will check if there is a <i>conf</i> folder in the
152  * working directory. This is the case when running in standalone mode.</li>
153  * <li><b>openfire_init.xml file</b> - Attempt to load the value from openfire_init.xml which
154  * must be in the classpath</li>
155  * </ol>
156  *
157  * @author Gaston Dombiak
158  */
159 public class XMPPServer {
160 
161     private static final Logger logger = LoggerFactory.getLogger(XMPPServer.class);
162 
163     private static XMPPServer instance;
164 
165     private boolean initialized = false;
166     private boolean started = false;
167     private NodeID nodeID;
168     private static final NodeID DEFAULT_NODE_ID = NodeID.getInstance( UUID.randomUUID().toString().getBytes() );
169 
170     private Timer terminatorTimer;
171     public static final String EXIT = "exit";
172     private final static Set<String> XML_ONLY_PROPERTIES;
173     static {
174         final List<String> properties = new ArrayList<>(Arrays.asList(
175             // Admin console network settings
176             "adminConsole.port", "adminConsole.securePort", "adminConsole.interface", "network.interface",
177             // Misc. settings
178             "locale", "fqdn", "setup", ClusterManager.CLUSTER_PROPERTY_NAME,
179             // Database config
180             "connectionProvider.className",
181             "database.defaultProvider.driver", "database.defaultProvider.serverURL", "database.defaultProvider.username",
182             "database.defaultProvider.password", "database.defaultProvider.testSQL", "database.defaultProvider.testBeforeUse",
183             "database.defaultProvider.testAfterUse", "database.defaultProvider.testTimeout", "database.defaultProvider.timeBetweenEvictionRuns",
184             "database.defaultProvider.minIdleTime", "database.defaultProvider.maxWaitTime", "database.defaultProvider.minConnections",
185             "database.defaultProvider.maxConnections", "database.defaultProvider.connectionTimeout", "database.mysql.useUnicode",
186             "database.JNDIProvider.name"
187         ));
188         // JDNI database config
Arrays.asList(JNDIDataSourceProvider.jndiPropertyKeys)189         properties.addAll(Arrays.asList(JNDIDataSourceProvider.jndiPropertyKeys));
190         XML_ONLY_PROPERTIES = Collections.unmodifiableSet(new HashSet<>(properties));
191     }
192 
193     /**
194      * All modules loaded by this server
195      */
196     private Map<Class, Module> modules = new LinkedHashMap<>();
197 
198     /**
199      * Listeners that will be notified when the server has started or is about to be stopped.
200      */
201     private List<XMPPServerListener> listeners = new CopyOnWriteArrayList<>();
202 
203     /**
204      * Location of the home directory. All configuration files should be
205      * located here.
206      */
207     private File openfireHome;
208     private ClassLoader loader;
209 
210     private PluginManager pluginManager;
211     private InternalComponentManager componentManager;
212     private RemoteSessionLocator remoteSessionLocator;
213 
214     /**
215      * True if in setup mode
216      */
217     private boolean setupMode = true;
218 
219     private static final String STARTER_CLASSNAME =
220             "org.jivesoftware.openfire.starter.ServerStarter";
221     private static final String WRAPPER_CLASSNAME =
222             "org.tanukisoftware.wrapper.WrapperManager";
223     private boolean shuttingDown;
224     private XMPPServerInfoImpl xmppServerInfo;
225 
226     /**
227      * Returns a singleton instance of XMPPServer.
228      *
229      * @return an instance.
230      */
getInstance()231     public static XMPPServer getInstance() {
232         return instance;
233     }
234 
235     /**
236      * TODO: (2019-04-24) Remove and replace with <a href="https://github.com/mockito/mockito/issues/1013">Mockito mocking of static methods</a>, when available
237      *
238      * @param instance the mock/stub/spy XMPPServer to return when {@link #getInstance()} is called.
239      * @deprecated - for test use only
240      */
241     @Deprecated
setInstance(final XMPPServer instance)242     public static void setInstance(final XMPPServer instance) {
243         XMPPServer.instance = instance;
244     }
245 
246     /**
247      * Creates a server and starts it.
248      */
XMPPServer()249     public XMPPServer() {
250         // We may only have one instance of the server running on the JVM
251         if (instance != null) {
252             throw new IllegalStateException("A server is already running");
253         }
254         instance = this;
255         start();
256     }
257 
258     /**
259      * Returns a snapshot of the server's status.
260      *
261      * @return the server information current at the time of the method call.
262      */
getServerInfo()263     public XMPPServerInfo getServerInfo() {
264         if (!initialized) {
265             throw new IllegalStateException("Not initialized yet");
266         }
267         return xmppServerInfo;
268     }
269 
270     /**
271      * Returns true if the given address is local to the server (managed by this
272      * server domain). Return false even if the jid's domain matches a local component's
273      * service JID.
274      *
275      * @param jid the JID to check.
276      * @return true if the address is a local address to this server.
277      */
isLocal( JID jid )278     public boolean isLocal( JID jid )
279     {
280         return jid != null && jid.getDomain().equals( xmppServerInfo.getXMPPDomain() );
281     }
282 
283     /**
284      * Returns true if the domain-part of the given address does not match the local server hostname and does not
285      * match a component service JID
286      *
287      * @param jid the JID to check.
288      * @return true if the given address does not match the local server hostname and does not
289      *         match a component service JID.
290      */
isRemote( JID jid )291     public boolean isRemote( JID jid )
292     {
293         return jid != null
294                 && !jid.getDomain().equals( xmppServerInfo.getXMPPDomain() )
295                 && !componentManager.hasComponent( new JID(null, jid.getDomain(), null, true) );
296     }
297 
298     /**
299      * Returns an ID that uniquely identifies this server in a cluster. When not running in cluster mode
300      * the returned value is always the same. However, when in cluster mode the value should be set
301      * when joining the cluster and must be unique even upon restarts of this node.
302      *
303      * @return an ID that uniquely identifies this server in a cluster.
304      */
getNodeID()305     public NodeID getNodeID() {
306         return nodeID == null ? DEFAULT_NODE_ID : nodeID;
307     }
308 
309     /**
310      * Sets an ID that uniquely identifies this server in a cluster. When not running in cluster mode
311      * the returned value is always the same. However, when in cluster mode the value should be set
312      * when joining the cluster and must be unique even upon restarts of this node.
313      *
314      * @param nodeID an ID that uniquely identifies this server in a cluster or null if not in a cluster.
315      */
setNodeID(NodeID nodeID)316     public void setNodeID(NodeID nodeID) {
317         this.nodeID = nodeID;
318     }
319 
320     /**
321      * Returns the default node ID used by this server before clustering is
322      * initialized.
323      *
324      * @return The default node ID.
325      */
getDefaultNodeID()326     public NodeID getDefaultNodeID() {
327         return DEFAULT_NODE_ID;
328     }
329 
330     /**
331      * Returns true if the domain-part of the given address matches a component service JID for a component that is
332      * connected to the local XMPP domain.
333      *
334      * @param jid the JID to check.
335      * @return true if the given address matches a component service JID.
336      */
matchesComponent( JID jid )337     public boolean matchesComponent( JID jid )
338     {
339         return jid != null
340                 && !jid.getDomain().equals( xmppServerInfo.getXMPPDomain() )
341                 && componentManager.hasComponent( new JID(null, jid.getDomain(), null, true) );
342     }
343 
344     /**
345      * Creates an XMPPAddress local to this server.
346      *
347      * @param username the user name portion of the id or null to indicate none is needed.
348      * @param resource the resource portion of the id or null to indicate none is needed.
349      * @return an XMPPAddress for the server.
350      */
createJID(String username, String resource)351     public JID createJID(String username, String resource) {
352         return new JID(username, xmppServerInfo.getXMPPDomain(), resource);
353     }
354 
355     /**
356      * Creates an XMPPAddress local to this server. The construction of the new JID
357      * can be optimized by skipping stringprep operations.
358      *
359      * @param username the user name portion of the id or null to indicate none is needed.
360      * @param resource the resource portion of the id or null to indicate none is needed.
361      * @param skipStringprep true if stringprep should not be applied.
362      * @return an XMPPAddress for the server.
363      */
createJID(String username, String resource, boolean skipStringprep)364     public JID createJID(String username, String resource, boolean skipStringprep) {
365         return new JID(username, xmppServerInfo.getXMPPDomain(), resource, skipStringprep);
366     }
367 
368     /**
369      * Returns a collection with the JIDs of the server's admins. The collection may include
370      * JIDs of local users and users of remote servers.
371      *
372      * @return a collection with the JIDs of the server's admins.
373      */
getAdmins()374     public Collection<JID> getAdmins() {
375         return AdminManager.getInstance().getAdminAccounts();
376     }
377 
378     /**
379      * Adds a new server listener that will be notified when the server has been started
380      * or is about to be stopped.
381      *
382      * @param listener the new server listener to add.
383      */
addServerListener(XMPPServerListener listener)384     public void addServerListener(XMPPServerListener listener) {
385         listeners.add(listener);
386     }
387 
388     /**
389      * Removes a server listener that was being notified when the server was being started
390      * or was about to be stopped.
391      *
392      * @param listener the server listener to remove.
393      */
removeServerListener(XMPPServerListener listener)394     public void removeServerListener(XMPPServerListener listener) {
395         listeners.remove(listener);
396     }
397 
initialize()398     private void initialize() throws FileNotFoundException {
399         locateOpenfire();
400 
401         if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
402             setupMode = false;
403         }
404 
405         if (isStandAlone()) {
406             logger.info("Registering shutdown hook (standalone mode)");
407             Runtime.getRuntime().addShutdownHook(new ShutdownHookThread());
408             terminatorTimer = new Timer(); // Not using TaskEngine here, as that requires configuration to be available, which it is not yet.
409             terminatorTimer.schedule(new Terminator(), 1000, 1000);
410         }
411 
412         loader = Thread.currentThread().getContextClassLoader();
413 
414         try {
415             CacheFactory.initialize();
416         } catch (InitializationException e) {
417             e.printStackTrace();
418             logger.error(e.getMessage(), e);
419         }
420 
421         JiveGlobals.migrateProperty(XMPPServerInfo.XMPP_DOMAIN.getKey());
422 
423         JiveGlobals.migrateProperty(Log.DEBUG_ENABLED.getKey());
424         if (Log.DEBUG_ENABLED.getValue()) {
425             Log.setDebugEnabled(true);
426         }
427         if (Log.TRACE_ENABLED.getValue()) {
428             Log.setTraceEnabled(true);
429         }
430 
431         // Update server info
432         xmppServerInfo = new XMPPServerInfoImpl(new Date());
433 
434         initialized = true;
435 
436         if (setupMode && "true".equals(JiveGlobals.getXMLProperty("autosetup.run"))) {
437             this.runAutoSetup();
438             JiveGlobals.deleteXMLProperty("autosetup");
439             JiveGlobals.deleteProperty("autosetup");
440         }
441 
442         // OF-1548: Move the storage of the FQDN from the database to the XML configuration
443         final String hostNameFromDatabase = JiveGlobals.getProperty("xmpp.fqdn", "");
444         final String hostNameFromXML = JiveGlobals.getXMLProperty("fqdn", "");
445         if (!hostNameFromDatabase.isEmpty() && hostNameFromXML.isEmpty()) {
446             final String hostname;
447             if (ClusterManager.isClusteringEnabled()) {
448                 // The database value has at best a 50% chance of being right - so instead use a sensible default
449                 String hostnameFromOS;
450                 try {
451                     hostnameFromOS = InetAddress.getLocalHost().getCanonicalHostName();
452                 } catch (final UnknownHostException e) {
453                     logger.warn("Unable to determine local hostname", e);
454                     hostnameFromOS = "localhost";
455                 }
456                 hostname = hostnameFromOS;
457             } else {
458                 hostname = hostNameFromDatabase;
459             }
460             JiveGlobals.setXMLProperty("fqdn", hostname);
461             JiveGlobals.deleteProperty("xmpp.fqdn");
462         }
463     }
464 
runAutoSetup()465     void runAutoSetup() {
466         // Setup property encryptor as early as possible so that database related properties can use it
467         JiveGlobals.setupPropertyEncryptionAlgorithm(JiveGlobals.getXMLProperty("autosetup.encryption.algorithm", "Blowfish")); // or AES
468         JiveGlobals.setupPropertyEncryptionKey(JiveGlobals.getXMLProperty("autosetup.encryption.key", null));
469 
470         // steps from setup-datasource-standard.jsp
471         // do this first so that other changes persist
472         if ("standard".equals(JiveGlobals.getXMLProperty("autosetup.database.mode"))) {
473             JiveGlobals.setXMLProperty("database.defaultProvider.driver", JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.driver"));
474             JiveGlobals.setXMLProperty("database.defaultProvider.serverURL", JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.serverURL"));
475             JiveGlobals.setXMLProperty("database.defaultProvider.username", JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.username"));
476             JiveGlobals.setXMLProperty("database.defaultProvider.password", JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.password"));
477 
478             int minConnections;
479             int maxConnections;
480             double connectionTimeout;
481 
482             try {
483                 minConnections = Integer.parseInt(
484                     JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.minConnections"));
485             }
486             catch (Exception e) {
487                 minConnections = 5;
488             }
489             try {
490                 maxConnections = Integer.parseInt(
491                     JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.maxConnections"));
492             }
493             catch (Exception e) {
494                 maxConnections = 25;
495             }
496             try {
497                 connectionTimeout = Double.parseDouble(
498                     JiveGlobals.getXMLProperty("autosetup.database.defaultProvider.connectionTimeout"));
499             }
500             catch (Exception e) {
501                 connectionTimeout = 1.0;
502             }
503 
504             JiveGlobals.setXMLProperty("database.defaultProvider.minConnections",
505                 Integer.toString(minConnections));
506             JiveGlobals.setXMLProperty("database.defaultProvider.maxConnections",
507                 Integer.toString(maxConnections));
508             JiveGlobals.setXMLProperty("database.defaultProvider.connectionTimeout",
509                 Double.toString(connectionTimeout));
510         }
511 
512         // mark setup as done, so that other things can be written to the DB
513         JiveGlobals.setXMLProperty("setup","true");
514 
515         // steps from index.jsp
516         String localeCode = JiveGlobals.getXMLProperty("autosetup.locale");
517         logger.warn("Setting locale to " + localeCode);
518         JiveGlobals.setLocale(LocaleUtils.localeCodeToLocale(localeCode.trim()));
519 
520         // steps from setup-host-settings.jsp
521         JiveGlobals.setXMLProperty(XMPPServerInfo.XMPP_DOMAIN.getKey(), JiveGlobals.getXMLProperty("autosetup." + XMPPServerInfo.XMPP_DOMAIN.getKey()));
522         JiveGlobals.setXMLProperty("fqdn", JiveGlobals.getXMLProperty("autosetup.xmpp.fqdn"));
523         JiveGlobals.migrateProperty(XMPPServerInfo.XMPP_DOMAIN.getKey());
524 
525         ConnectionSettings.Client.ENABLE_OLD_SSLPORT_PROPERTY.setValue(Boolean.valueOf(JiveGlobals.getXMLProperty("autosetup." + ConnectionSettings.Client.ENABLE_OLD_SSLPORT_PROPERTY.getKey(), "true")));
526         AnonymousSaslServer.ENABLED.setValue(Boolean.valueOf(JiveGlobals.getXMLProperty("autosetup." + AnonymousSaslServer.ENABLED.getKey(), "false")));
527 
528 
529         // steps from setup-profile-settings.jsp
530         if ("default".equals(JiveGlobals.getXMLProperty("autosetup.authprovider.mode", "default"))) {
531             JiveGlobals.setXMLProperty("connectionProvider.className",
532                 "org.jivesoftware.database.DefaultConnectionProvider");
533 
534             JiveGlobals.setProperty(AuthFactory.AUTH_PROVIDER.getKey(), JiveGlobals.getXMLProperty(AuthFactory.AUTH_PROVIDER.getKey(),
535                 AuthFactory.AUTH_PROVIDER.getDefaultValue().getName()));
536             JiveGlobals.setProperty(UserManager.USER_PROVIDER.getKey(), JiveGlobals.getXMLProperty(UserManager.USER_PROVIDER.getKey(),
537                 UserManager.USER_PROVIDER.getDefaultValue().getName()));
538             JiveGlobals.setProperty(GroupManager.GROUP_PROVIDER.getKey(), JiveGlobals.getXMLProperty(GroupManager.GROUP_PROVIDER.getKey(),
539                 GroupManager.GROUP_PROVIDER.getDefaultValue().getName()));
540             JiveGlobals.setProperty(VCardManager.VCARD_PROVIDER.getKey(), JiveGlobals.getXMLProperty(VCardManager.VCARD_PROVIDER.getKey(),
541                 VCardManager.VCARD_PROVIDER.getDefaultValue().getName()));
542             JiveGlobals.setProperty(LockOutManager.LOCKOUT_PROVIDER.getKey(), JiveGlobals.getXMLProperty(LockOutManager.LOCKOUT_PROVIDER.getKey(),
543                 LockOutManager.LOCKOUT_PROVIDER.getDefaultValue().getName()));
544             JiveGlobals.setProperty(SecurityAuditManager.AUDIT_PROVIDER.getKey(), JiveGlobals.getXMLProperty(SecurityAuditManager.AUDIT_PROVIDER.getKey(),
545                 SecurityAuditManager.AUDIT_PROVIDER.getDefaultValue().getName()));
546             JiveGlobals.setProperty(AdminManager.ADMIN_PROVIDER.getKey(), JiveGlobals.getXMLProperty(AdminManager.ADMIN_PROVIDER.getKey(),
547                 AdminManager.ADMIN_PROVIDER.getDefaultValue().getName()));
548 
549             // make configurable?
550             JiveGlobals.setProperty("user.scramHashedPasswordOnly", "true");
551         }
552 
553         // steps from setup-admin-settings.jsp
554         try {
555             User adminUser = UserManager.getInstance().getUser("admin");
556             adminUser.setPassword(JiveGlobals.getXMLProperty("autosetup.admin.password"));
557             adminUser.setEmail(JiveGlobals.getXMLProperty("autosetup.admin.email"));
558             Date now = new Date();
559             adminUser.setCreationDate(now);
560             adminUser.setModificationDate(now);
561         } catch (Exception e) {
562             e.printStackTrace();
563             logger.warn("There was an unexpected error encountered when "
564                 + "setting the new admin information. Please check your error "
565                 + "logs and try to remedy the problem.");
566         }
567 
568         // Import any provisioned users.
569         try {
570             RosterItemProvider rosterItemProvider = null;
571             for (int userId = 1; userId < Integer.MAX_VALUE; userId++ ) {
572                 final String username = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".username" );
573                 final String password = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".password" );
574                 if (username == null || password == null) {
575                     break;
576                 }
577                 final String name = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".name" );
578                 final String email = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".email" );
579 
580                 final User user = UserManager.getInstance().createUser(username, password, name, email );
581                 for (int itemId = 1; itemId < Integer.MAX_VALUE; itemId++) {
582                     final String jid = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".roster.item" + itemId + ".jid" );
583                     if (jid == null) {
584                         break;
585                     }
586                     final String nickname = JiveGlobals.getXMLProperty( "autosetup.users.user" + userId + ".roster.item" + itemId + ".nickname" );
587                     final RosterItem rosterItem = new RosterItem(new JID(jid), RosterItem.SubType.BOTH, RosterItem.AskType.NONE, RosterItem.RecvType.NONE, nickname, null);
588 
589                     if (rosterItemProvider == null) {
590                         // Modules have not started at this point, so we can't go through the roster. Use the default provider instead.
591                         rosterItemProvider = new DefaultRosterItemProvider();
592                     }
593                     rosterItemProvider.createItem(user.getUsername(), rosterItem);
594                 }
595             }
596         } catch (Exception e) {
597             e.printStackTrace();
598             logger.warn("There was an unexpected error encountered when provisioning auto-setup provided users.", e);
599         }
600 
601         // finish setup
602         this.finalSetupSteps();
603         setupMode = false;
604     }
605 
finalSetupSteps()606     private void finalSetupSteps() {
607         for (String propName : JiveGlobals.getXMLPropertyNames()) {
608             if (!XML_ONLY_PROPERTIES.contains(propName)) {
609                 if (JiveGlobals.getProperty(propName) == null) {
610                     JiveGlobals.setProperty(propName, JiveGlobals.getXMLProperty(propName));
611                 }
612                 JiveGlobals.setPropertyEncrypted(propName, JiveGlobals.isXMLPropertyEncrypted(propName));
613             }
614         }
615 
616         // Check if keystore (that out-of-the-box is a fallback for all keystores) already has certificates for current domain.
617         CertificateStoreManager certificateStoreManager = null; // Will be a module after finishing setup.
618         try {
619             certificateStoreManager = new CertificateStoreManager();
620             certificateStoreManager.initialize( this );
621             certificateStoreManager.start();
622             final IdentityStore identityStore = certificateStoreManager.getIdentityStore( ConnectionType.SOCKET_C2S );
623             identityStore.ensureDomainCertificate();
624 
625         } catch (Exception e) {
626             logger.error("Error generating self-signed certificates", e);
627         } finally {
628             if (certificateStoreManager != null)
629             {
630                 certificateStoreManager.stop();
631                 certificateStoreManager.destroy();
632             }
633         }
634 
635         // Initialize list of admins now (before we restart Jetty)
636         AdminManager.getInstance().getAdminAccounts();
637     }
638 
639     /**
640      * Finish the setup process. Because this method is meant to be called from inside
641      * the Admin console plugin, it spawns its own thread to do the work so that the
642      * class loader is correct.
643      */
finishSetup()644     public void finishSetup() {
645         if (!setupMode) {
646             return;
647         }
648 
649         this.finalSetupSteps();
650 
651         // Make sure that setup finished correctly.
652         if ("true".equals(JiveGlobals.getXMLProperty("setup"))) {
653             // Iterate through all the provided XML properties and set the ones that haven't
654             // already been touched by setup prior to this method being called.
655 
656             Thread finishSetup = new Thread() {
657                 @Override
658                 public void run() {
659                     try {
660                         if (isStandAlone()) {
661                             // Always restart the HTTP server manager. This covers the case
662                             // of changing the ports, as well as generating self-signed certificates.
663 
664                             // Wait a short period before shutting down the admin console.
665                             // Otherwise, the page that requested the setup finish won't
666                             // render properly!
667                             Thread.sleep(1000);
668                             ((AdminConsolePlugin) pluginManager.getPlugin("admin")).restart();
669                         }
670 
671                         verifyDataSource();
672                         // First load all the modules so that modules may access other modules while
673                         // being initialized
674                         loadModules();
675                         // Initize all the modules
676                         initModules();
677                         // Start all the modules
678                         startModules();
679                         scanForSystemPropertyClasses();
680                     }
681                     catch (Exception e) {
682                         e.printStackTrace();
683                         logger.error(e.getMessage(), e);
684                         shutdownServer();
685                     }
686                 }
687             };
688             // Use the correct class loader.
689             finishSetup.setContextClassLoader(loader);
690             finishSetup.start();
691             // We can now safely indicate that setup has finished
692             setupMode = false;
693         }
694     }
695 
start()696     public void start() {
697         try {
698             initialize();
699 
700             // Create PluginManager now (but don't start it) so that modules may use it
701             File pluginDir = new File(openfireHome, "plugins");
702             pluginManager = new PluginManager(pluginDir);
703 
704             // If the server has already been setup then we can start all the server's modules
705             if (!setupMode) {
706                 verifyDataSource();
707                 // First load all the modules so that modules may access other modules while
708                 // being initialized
709                 loadModules();
710                 // Initize all the modules
711                 initModules();
712                 // Start all the modules
713                 startModules();
714             }
715             // Initialize statistics
716             ServerTrafficCounter.initStatistics();
717 
718             // Load plugins (when in setup mode only the admin console will be loaded)
719             pluginManager.start();
720 
721             // Log that the server has been started
722             String startupBanner = LocaleUtils.getLocalizedString("short.title") + " " + xmppServerInfo.getVersion().getVersionString() +
723                     " [" + JiveGlobals.formatDateTime(new Date()) + "]";
724             logger.info(startupBanner);
725             System.out.println(startupBanner);
726 
727             started = true;
728 
729             // Notify server listeners that the server has been started
730             for (XMPPServerListener listener : listeners) {
731                 try {
732                     listener.serverStarted();
733                 } catch (Exception e) {
734                     logger.warn("An exception occurred while dispatching a 'serverStarted' event!", e);
735                 }
736             }
737 
738             if (!setupMode) {
739                 scanForSystemPropertyClasses();
740             }
741         }
742         catch (Exception e) {
743             e.printStackTrace();
744             logger.error(e.getMessage(), e);
745             System.out.println(LocaleUtils.getLocalizedString("startup.error"));
746             shutdownServer();
747         }
748     }
749 
750     // A SystemProperty class will not appear in the System Properties screen until it is referenced. This method
751     // ensures that they are all referenced immediately.
752     // The following class cannot always be loaded as it references a class that's part of the Install4J launcher
753     private static final Set<String> CLASSES_TO_EXCLUDE = Collections.singleton("org.jivesoftware.openfire.launcher.Uninstaller");
754 
scanForSystemPropertyClasses()755     private void scanForSystemPropertyClasses() {
756 
757         try {
758             final Set<ClassPath.ClassInfo> classesInPackage = ClassPath.from(getClass().getClassLoader()).getTopLevelClassesRecursive("org.jivesoftware.openfire");
759             for (final ClassPath.ClassInfo classInfo : classesInPackage) {
760                 final String className = classInfo.getName();
761                 if (!CLASSES_TO_EXCLUDE.contains(className)) {
762                     try {
763                         final Class<?> clazz = classInfo.load();
764                         final Field[] fields = clazz.getDeclaredFields();
765                         for (final Field field : fields) {
766                             if (field.getType().equals(SystemProperty.class)) {
767                                 try {
768                                     field.setAccessible(true);
769                                     logger.info("Accessing SystemProperty field {}#{}", className, field.getName());
770                                     field.get(null);
771                                 } catch (final Throwable t) {
772                                     logger.warn("Unable to access field {}#{}", className, field.getName(), t);
773                                 }
774                             }
775                         }
776                     } catch (final Throwable t) {
777                         logger.warn("Unable to load class {}", className, t);
778                     }
779                 }
780             }
781         } catch (final Throwable t) {
782             logger.warn("Unable to scan classpath for SystemProperty classes", t);
783         }
784     }
785 
loadModules()786     private void loadModules() {
787         // Load boot modules
788         loadModule(RoutingTableImpl.class.getName());
789         loadModule(AuditManagerImpl.class.getName());
790         loadModule(RosterManager.class.getName());
791         loadModule(PrivateStorage.class.getName());
792         // Load core modules
793         loadModule(PresenceManagerImpl.class.getName());
794         loadModule(SessionManager.class.getName());
795         loadModule(PacketRouterImpl.class.getName());
796         loadModule(IQRouter.class.getName());
797         loadModule(MessageRouter.class.getName());
798         loadModule(PresenceRouter.class.getName());
799         loadModule(MulticastRouter.class.getName());
800         loadModule(PacketTransporterImpl.class.getName());
801         loadModule(PacketDelivererImpl.class.getName());
802         loadModule(TransportHandler.class.getName());
803         loadModule(OfflineMessageStrategy.class.getName());
804         loadModule(OfflineMessageStore.class.getName());
805         loadModule(VCardManager.class.getName());
806         // Load standard modules
807         loadModule(IQBindHandler.class.getName());
808         loadModule(IQSessionEstablishmentHandler.class.getName());
809         loadModule(IQPingHandler.class.getName());
810         loadModule(IQBlockingHandler.class.getName());
811         loadModule(IQPrivateHandler.class.getName());
812         loadModule(IQRegisterHandler.class.getName());
813         loadModule(IQRosterHandler.class.getName());
814         loadModule(IQEntityTimeHandler.class.getName());
815         loadModule(IQvCardHandler.class.getName());
816         loadModule(IQVersionHandler.class.getName());
817         loadModule(IQLastActivityHandler.class.getName());
818         loadModule(PresenceSubscribeHandler.class.getName());
819         loadModule(PresenceUpdateHandler.class.getName());
820         loadModule(IQOfflineMessagesHandler.class.getName());
821         loadModule(IQPEPHandler.class.getName());
822         loadModule(IQPEPOwnerHandler.class.getName());
823         loadModule(MulticastDNSService.class.getName());
824         loadModule(IQSharedGroupHandler.class.getName());
825         loadModule(AdHocCommandHandler.class.getName());
826         loadModule(IQPrivacyHandler.class.getName());
827         loadModule(DefaultFileTransferManager.class.getName());
828         loadModule(FileTransferProxy.class.getName());
829         loadModule(MediaProxyService.class.getName());
830         loadModule(PubSubModule.class.getName());
831         loadModule(IQDiscoInfoHandler.class.getName());
832         loadModule(IQDiscoItemsHandler.class.getName());
833         loadModule(UpdateManager.class.getName());
834         loadModule(InternalComponentManager.class.getName());
835         loadModule(MultiUserChatManager.class.getName());
836         loadModule(IQMessageCarbonsHandler.class.getName());
837         loadModule(ArchiveManager.class.getName());
838         loadModule(CertificateStoreManager.class.getName());
839         loadModule(EntityCapabilitiesManager.class.getName());
840         loadModule(SoftwareVersionManager.class.getName());
841         loadModule(SoftwareServerVersionManager.class.getName());
842 
843         // Load this module always last since we don't want to start listening for clients
844         // before the rest of the modules have been started
845         loadModule(ConnectionManagerImpl.class.getName());
846         loadModule(ClusterMonitor.class.getName());
847         // Keep a reference to the internal component manager
848         componentManager = getComponentManager();
849     }
850 
851     /**
852      * Loads a module.
853      *
854      * @param module the name of the class that implements the Module interface.
855      */
loadModule(String module)856     private void loadModule(String module) {
857         try {
858             Class<Module> modClass = (Class<Module>) loader.loadClass(module);
859             Module mod = modClass.newInstance();
860             this.modules.put(modClass, mod);
861         }
862         catch (Exception e) {
863             e.printStackTrace();
864             logger.error(LocaleUtils.getLocalizedString("admin.error"), e);
865         }
866     }
867 
initModules()868     private void initModules() {
869         for (Module module : modules.values()) {
870             try {
871                 module.initialize(this);
872             }
873             catch (Exception e) {
874                 e.printStackTrace();
875                 // Remove the failed initialized module
876                 this.modules.remove(module.getClass());
877                 module.stop();
878                 module.destroy();
879                 logger.error(LocaleUtils.getLocalizedString("admin.error"), e);
880             }
881         }
882 
883         // Register modules with service discovery provides where applicable.
884         for (Module module : modules.values() )
885         {
886             // Service discovery info
887             if (module instanceof ServerFeaturesProvider) {
888                 getIQDiscoInfoHandler().addServerFeaturesProvider( (ServerFeaturesProvider) module );
889             }
890 
891             if (module instanceof ServerIdentitiesProvider) {
892                 getIQDiscoInfoHandler().addServerIdentitiesProvider( (ServerIdentitiesProvider) module );
893             }
894 
895             if (module instanceof UserIdentitiesProvider) {
896                 getIQDiscoInfoHandler().addUserIdentitiesProvider( (UserIdentitiesProvider) module );
897             }
898 
899             if (module instanceof UserFeaturesProvider ) {
900                 getIQDiscoInfoHandler().addUserFeaturesProvider( (UserFeaturesProvider) module );
901             }
902 
903             // Service discovery items
904             if (module instanceof ServerItemsProvider) {
905                 getIQDiscoItemsHandler().addServerItemsProvider( (ServerItemsProvider) module );
906             }
907 
908             if (module instanceof UserItemsProvider) {
909                 getIQDiscoItemsHandler().addUserItemsProvider( (UserItemsProvider) module);
910             }
911         }
912 
913     }
914 
915     /**
916      * <p>Following the loading and initialization of all the modules
917      * this method is called to iterate through the known modules and
918      * start them.</p>
919      */
startModules()920     private void startModules() {
921         for (Module module : modules.values()) {
922             try {
923                 logger.debug( "Starting module: " + module.getName() );
924                 module.start();
925             }
926             catch (Exception e) {
927                 logger.error( "An exception occurred while starting module '{}'.", module.getName(), e );
928             }
929         }
930     }
931 
932     /**
933      * Restarts the server and all it's modules only if the server is restartable. Otherwise do
934      * nothing.
935      */
restart()936     public void restart() {
937         if (isStandAlone() && isRestartable()) {
938             try {
939                 Class<?> wrapperClass = Class.forName(WRAPPER_CLASSNAME);
940                 Method restartMethod = wrapperClass.getMethod("restart", (Class []) null);
941                 restartMethod.invoke(null, (Object []) null);
942             }
943             catch (Exception e) {
944                 logger.error("Could not restart container", e);
945             }
946         }
947     }
948 
949     /**
950      * Restarts the HTTP server only when running in stand alone mode. The restart
951      * process will be done in another thread that will wait 1 second before doing
952      * the actual restart. The delay will give time to the page that requested the
953      * restart to fully render its content.
954      */
restartHTTPServer()955     public void restartHTTPServer() {
956         Thread restartThread = new Thread() {
957             @Override
958             public void run() {
959                 if (isStandAlone()) {
960                     // Restart the HTTP server manager. This covers the case
961                     // of changing the ports, as well as generating self-signed certificates.
962 
963                     // Wait a short period before shutting down the admin console.
964                     // Otherwise, this page won't render properly!
965                     try {
966                         Thread.sleep(1000);
967                         ((AdminConsolePlugin) pluginManager.getPlugin("admin")).restart();
968                     } catch (Exception e) {
969                         e.printStackTrace();
970                     }
971                 }
972             }
973         };
974         restartThread.setContextClassLoader(loader);
975         restartThread.start();
976     }
977 
978     /**
979      * Stops the server only if running in standalone mode. Do nothing if the server is running
980      * inside of another server.
981      */
stop()982     public void stop() {
983         logger.info("Initiating shutdown ...");
984         // Only do a system exit if we're running standalone
985         if (isStandAlone()) {
986             // if we're in a wrapper, we have to tell the wrapper to shut us down
987             if (isRestartable()) {
988                 try {
989                     Class<?> wrapperClass = Class.forName(WRAPPER_CLASSNAME);
990                     Method stopMethod = wrapperClass.getMethod("stop", Integer.TYPE);
991                     stopMethod.invoke(null, 0);
992                 }
993                 catch (Exception e) {
994                     logger.error("Could not stop container", e);
995                 }
996             }
997             else {
998                 shutdownServer();
999                 Thread shutdownThread = new ShutdownThread();
1000                 shutdownThread.setDaemon(true);
1001                 shutdownThread.start();
1002             }
1003         }
1004         else {
1005             // Close listening socket no matter what the condition is in order to be able
1006             // to be restartable inside a container.
1007             shutdownServer();
1008         }
1009     }
1010 
isSetupMode()1011     public boolean isSetupMode() {
1012         return setupMode;
1013     }
1014 
isRestartable()1015     public boolean isRestartable() {
1016         boolean restartable;
1017         try {
1018             restartable = Class.forName(WRAPPER_CLASSNAME) != null;
1019         }
1020         catch (ClassNotFoundException e) {
1021             restartable = false;
1022         }
1023         return restartable;
1024     }
1025 
1026     /**
1027      * Returns if the server is running in standalone mode. We consider that it's running in
1028      * standalone if the "org.jivesoftware.openfire.starter.ServerStarter" class is present in the
1029      * system.
1030      *
1031      * @return true if the server is running in standalone mode.
1032      */
isStandAlone()1033     public boolean isStandAlone() {
1034         boolean standalone;
1035         try {
1036             standalone = Class.forName(STARTER_CLASSNAME) != null;
1037         }
1038         catch (ClassNotFoundException e) {
1039             standalone = false;
1040         }
1041         return standalone;
1042     }
1043 
1044     /**
1045      * Verify that the database is accessible.
1046      */
verifyDataSource()1047     private void verifyDataSource() {
1048         Connection con = null;
1049         PreparedStatement pstmt = null;
1050         ResultSet rs = null;
1051         try {
1052             con = DbConnectionManager.getConnection();
1053             pstmt = con.prepareStatement("SELECT count(*) FROM ofID");
1054             rs = pstmt.executeQuery();
1055             rs.next();
1056         }
1057         catch (Exception e) {
1058             System.err.println("Database setup or configuration error: " +
1059                     "Please verify your database settings and check the " +
1060                     "logs/error.log file for detailed error messages.");
1061             logger.error("Database could not be accessed", e);
1062             throw new IllegalArgumentException(e);
1063         }
1064         finally {
1065             DbConnectionManager.closeConnection(rs, pstmt, con);
1066         }
1067     }
1068 
1069     /**
1070      * Verifies that the given home guess is a real Openfire home directory.
1071      * We do the verification by checking for the Openfire config file in
1072      * the config dir of jiveHome.
1073      *
1074      * @param homeGuess a guess at the path to the home directory.
1075      * @param jiveConfigName the name of the config file to check.
1076      * @return a file pointing to the home directory or null if the
1077      *         home directory guess was wrong.
1078      * @throws java.io.FileNotFoundException if there was a problem with the home
1079      *                                       directory provided
1080      */
verifyHome(String homeGuess, String jiveConfigName)1081     private File verifyHome(String homeGuess, String jiveConfigName) throws FileNotFoundException {
1082         File openfireHome = new File(homeGuess);
1083         File configFile = new File(openfireHome, jiveConfigName);
1084         if (!configFile.exists()) {
1085             throw new FileNotFoundException();
1086         }
1087         else {
1088             try {
1089                 return new File(openfireHome.getCanonicalPath());
1090             }
1091             catch (Exception ex) {
1092                 throw new FileNotFoundException();
1093             }
1094         }
1095     }
1096 
1097     /**
1098      * <p>Retrieve the jive home for the container.</p>
1099      *
1100      * @throws FileNotFoundException If jiveHome could not be located
1101      */
locateOpenfire()1102     private void locateOpenfire() throws FileNotFoundException {
1103         String jiveConfigName = "conf" + File.separator + "openfire.xml";
1104         // First, try to load it openfireHome as a system property.
1105         if (openfireHome == null) {
1106             String homeProperty = System.getProperty("openfireHome");
1107             try {
1108                 if (homeProperty != null) {
1109                     openfireHome = verifyHome(homeProperty, jiveConfigName);
1110                 }
1111             }
1112             catch (FileNotFoundException fe) {
1113                 // Ignore.
1114             }
1115         }
1116 
1117         // If we still don't have home, let's assume this is standalone
1118         // and just look for home in a standard sub-dir location and verify
1119         // by looking for the config file
1120         if (openfireHome == null) {
1121             try {
1122                 openfireHome = verifyHome("..", jiveConfigName).getCanonicalFile();
1123             } catch (IOException ie) {
1124                 // Ignore.
1125             }
1126         }
1127 
1128         // If home is still null, no outside process has set it and
1129         // we have to attempt to load the value from openfire_init.xml,
1130         // which must be in the classpath.
1131         if (openfireHome == null) {
1132             try (InputStream in = getClass().getResourceAsStream("/openfire_init.xml")) {
1133                 if (in != null) {
1134                     String path = SAXReaderUtil.readRootElement(in).getText();
1135                     try {
1136                         if (path != null) {
1137                             openfireHome = verifyHome(path, jiveConfigName);
1138                         }
1139                     }
1140                     catch (FileNotFoundException fe) {
1141                         fe.printStackTrace();
1142                     }
1143                 }
1144             }
1145             catch (Exception e) {
1146                 System.err.println("Error loading openfire_init.xml to find home.");
1147                 e.printStackTrace();
1148                 if (e instanceof InterruptedException) {
1149                     Thread.currentThread().interrupt();
1150                 }
1151             }
1152         }
1153 
1154         if (openfireHome == null) {
1155             System.err.println("Could not locate home");
1156             throw new FileNotFoundException();
1157         }
1158         else {
1159             // Set the home directory for the config file
1160             JiveGlobals.setHomeDirectory(openfireHome.toString());
1161             // Set the name of the config file
1162             JiveGlobals.setConfigName(jiveConfigName);
1163         }
1164     }
1165 
1166     /**
1167      * This timer task is used to monitor the System input stream
1168      * for a "terminate" command from the launcher (or the console).
1169      * This allows for a graceful shutdown when Openfire is started
1170      * via the launcher, especially in Windows.
1171      */
1172     private class Terminator extends TimerTask {
1173         private BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
1174         @Override
run()1175         public void run() {
1176             try {
1177                 if (stdin.ready()) {
1178                     if (EXIT.equalsIgnoreCase(stdin.readLine())) {
1179                         System.exit(0); // invokes shutdown hook(s)
1180                     }
1181                 }
1182             } catch (IOException ioe) {
1183                 logger.error("Error reading console input", ioe);
1184             }
1185         }
1186     }
1187 
1188     /**
1189      * <p>A thread to ensure the server shuts down no matter what.</p>
1190      * <p>Spawned when stop() is called in standalone mode, we wait a few
1191      * seconds then call system exit().</p>
1192      *
1193      * @author Iain Shigeoka
1194      */
1195     private class ShutdownHookThread extends Thread {
1196 
1197         /**
1198          * <p>Logs the server shutdown.</p>
1199          */
1200         @Override
run()1201         public void run() {
1202             System.err.println("Halting server...");
1203             shutdownServer();
1204             System.err.println("Server halted");
1205         }
1206     }
1207 
1208     /**
1209      * <p>A thread to ensure the server shuts down no matter what.</p>
1210      * <p>Spawned when stop() is called in standalone mode, we wait a few
1211      * seconds then call system exit().</p>
1212      *
1213      * @author Iain Shigeoka
1214      */
1215     private class ShutdownThread extends Thread {
1216 
1217         /**
1218          * <p>Shuts down the JVM after a 5 second delay.</p>
1219          */
1220         @Override
run()1221         public void run() {
1222             try {
1223                 Thread.sleep(5000);
1224                 // No matter what, we make sure it's dead
1225                 System.out.println( "Openfire process forcefully killed." );
1226                 System.exit(0);
1227             }
1228             catch (InterruptedException e) {
1229                 // Ignore.
1230             }
1231 
1232         }
1233     }
1234 
1235     /**
1236      * Makes a best effort attempt to shutdown the server
1237      */
shutdownServer()1238     private void shutdownServer() {
1239         shuttingDown = true;
1240 
1241         if (terminatorTimer != null) {
1242             terminatorTimer.cancel();
1243         }
1244 
1245         ClusterManager.shutdown();
1246         // Notify server listeners that the server is about to be stopped
1247         for (XMPPServerListener listener : listeners) {
1248             try {
1249                 listener.serverStopping();
1250             } catch (Exception ex) {
1251                 logger.error("Exception during listener shutdown", ex);
1252             }
1253         }
1254         // If we don't have modules then the server has already been shutdown
1255         if (modules.isEmpty()) {
1256             return;
1257         }
1258 
1259         // Stop all plugins
1260         logger.info("Shutting down plugins ...");
1261         if (pluginManager != null) {
1262             try {
1263                 pluginManager.shutdown();
1264             } catch (Exception ex) {
1265                 logger.error("Exception during plugin shutdown", ex);
1266             }
1267         }
1268 
1269         logger.info("Shutting down " + modules.size() + " modules ...");
1270 
1271         final SimpleTimeLimiter timeLimiter = SimpleTimeLimiter.create( Executors.newSingleThreadExecutor(
1272             new ThreadFactoryBuilder()
1273                 .setDaemon( true )
1274                 .setNameFormat( "shutdown-thread-%d" )
1275                 .build() ) );
1276 
1277         // OF-1996" Get all modules and stop and destroy them. Do this in the reverse order in which the were created.
1278         // This ensures that the 'most important' / core modules are shut down last, giving other modules the
1279         // opportunity to make use of their functionality during their shutdown (eg: MUC wants to send messages during
1280         // shutdown).
1281         final List<Class> reverseInsertionOrder = new ArrayList<>( modules.keySet() );
1282         Collections.reverse( reverseInsertionOrder );
1283 
1284         for( final Class moduleClass : reverseInsertionOrder ) {
1285             final Module module = modules.get( moduleClass );
1286             try {
1287                 // OF-1607: Apply a configurable timeout to the duration of stop/destroy invocation.
1288                 timeLimiter.runWithTimeout(() -> {
1289                     stopAndDestroyModule(module);
1290                 }, JiveGlobals.getLongProperty("shutdown.modules.timeout-millis", Long.MAX_VALUE), TimeUnit.MILLISECONDS);
1291             } catch ( Exception e ) {
1292                 logger.warn("An exception occurred while stopping / destroying module '{}'.", module.getName(), e);
1293                 System.err.println(e);
1294             }
1295         }
1296 
1297         modules.clear();
1298         // Stop the Db connection manager.
1299         try {
1300             DbConnectionManager.destroyConnectionProvider();
1301         } catch (Exception ex) {
1302             logger.error("Exception during DB shutdown", ex);
1303         }
1304 
1305         // Shutdown the task engine.
1306         TaskEngine.getInstance().shutdown();
1307 
1308         // hack to allow safe stopping
1309         logger.info("Openfire stopped");
1310 
1311         // Shut down the logging framework (causing the last few log entries to be flushed)
1312         LogManager.shutdown();
1313     }
1314 
1315     /**
1316      * Stops and destroys a module.
1317      *
1318      * @param module The module to be stopped (cannot be null).
1319      */
stopAndDestroyModule( final Module module )1320     private static void stopAndDestroyModule( final Module module ) {
1321         try {
1322             logger.debug("Stopping and shutting down module '{}'", module.getName() );
1323             module.stop();
1324             module.destroy();
1325         } catch (Exception ex) {
1326             logger.error("Exception during module '{}' shutdown", module.getName(), ex);
1327         }
1328     }
1329 
1330     /**
1331      * Returns true if the server is being shutdown.
1332      *
1333      * @return true if the server is being shutdown.
1334      */
isShuttingDown()1335     public boolean isShuttingDown() {
1336         return shuttingDown;
1337     }
1338 
1339     /**
1340      * Returns the <code>ConnectionManager</code> registered with this server. The
1341      * <code>ConnectionManager</code> was registered with the server as a module while starting up
1342      * the server.
1343      *
1344      * @return the <code>ConnectionManager</code> registered with this server.
1345      */
getConnectionManager()1346     public ConnectionManager getConnectionManager() {
1347         return (ConnectionManager) modules.get(ConnectionManagerImpl.class);
1348     }
1349 
1350     /**
1351      * Returns the <code>RoutingTable</code> registered with this server. The
1352      * <code>RoutingTable</code> was registered with the server as a module while starting up
1353      * the server.
1354      *
1355      * @return the <code>RoutingTable</code> registered with this server.
1356      */
getRoutingTable()1357     public RoutingTable getRoutingTable() {
1358         return (RoutingTable) modules.get(RoutingTableImpl.class);
1359     }
1360 
1361     /**
1362      * Returns the <code>PacketDeliverer</code> registered with this server. The
1363      * <code>PacketDeliverer</code> was registered with the server as a module while starting up
1364      * the server.
1365      *
1366      * @return the <code>PacketDeliverer</code> registered with this server.
1367      */
getPacketDeliverer()1368     public PacketDeliverer getPacketDeliverer() {
1369         return (PacketDeliverer) modules.get(PacketDelivererImpl.class);
1370     }
1371 
1372     /**
1373      * Returns the <code>RosterManager</code> registered with this server. The
1374      * <code>RosterManager</code> was registered with the server as a module while starting up
1375      * the server.
1376      *
1377      * @return the <code>RosterManager</code> registered with this server.
1378      */
getRosterManager()1379     public RosterManager getRosterManager() {
1380         return (RosterManager) modules.get(RosterManager.class);
1381     }
1382 
1383     /**
1384      * Returns the <code>PresenceManager</code> registered with this server. The
1385      * <code>PresenceManager</code> was registered with the server as a module while starting up
1386      * the server.
1387      *
1388      * @return the <code>PresenceManager</code> registered with this server.
1389      */
getPresenceManager()1390     public PresenceManager getPresenceManager() {
1391         return (PresenceManager) modules.get(PresenceManagerImpl.class);
1392     }
1393 
1394     /**
1395      * Returns the <code>OfflineMessageStore</code> registered with this server. The
1396      * <code>OfflineMessageStore</code> was registered with the server as a module while starting up
1397      * the server.
1398      *
1399      * @return the <code>OfflineMessageStore</code> registered with this server.
1400      */
getOfflineMessageStore()1401     public OfflineMessageStore getOfflineMessageStore() {
1402         return (OfflineMessageStore) modules.get(OfflineMessageStore.class);
1403     }
1404 
1405     /**
1406      * Returns the <code>OfflineMessageStrategy</code> registered with this server. The
1407      * <code>OfflineMessageStrategy</code> was registered with the server as a module while starting
1408      * up the server.
1409      *
1410      * @return the <code>OfflineMessageStrategy</code> registered with this server.
1411      */
getOfflineMessageStrategy()1412     public OfflineMessageStrategy getOfflineMessageStrategy() {
1413         return (OfflineMessageStrategy) modules.get(OfflineMessageStrategy.class);
1414     }
1415 
1416     /**
1417      * Returns the <code>PacketRouter</code> registered with this server. The
1418      * <code>PacketRouter</code> was registered with the server as a module while starting up
1419      * the server.
1420      *
1421      * @return the <code>PacketRouter</code> registered with this server.
1422      */
getPacketRouter()1423     public PacketRouter getPacketRouter() {
1424         return (PacketRouter) modules.get(PacketRouterImpl.class);
1425     }
1426 
1427     /**
1428      * Returns the <code>IQRegisterHandler</code> registered with this server. The
1429      * <code>IQRegisterHandler</code> was registered with the server as a module while starting up
1430      * the server.
1431      *
1432      * @return the <code>IQRegisterHandler</code> registered with this server.
1433      */
getIQRegisterHandler()1434     public IQRegisterHandler getIQRegisterHandler() {
1435         return (IQRegisterHandler) modules.get(IQRegisterHandler.class);
1436     }
1437 
1438     /**
1439      * Returns the <code>IQPEPHandler</code> registered with this server. The
1440      * <code>IQPEPHandler</code> was registered with the server as a module while starting up
1441      * the server.
1442      *
1443      * @return the <code>IQPEPHandler</code> registered with this server.
1444      */
getIQPEPHandler()1445     public IQPEPHandler getIQPEPHandler() {
1446         return (IQPEPHandler) modules.get(IQPEPHandler.class);
1447     }
1448 
1449     /**
1450      * Returns the <code>PluginManager</code> instance registered with this server.
1451      *
1452      * @return the PluginManager instance.
1453      */
getPluginManager()1454     public PluginManager getPluginManager() {
1455         return pluginManager;
1456     }
1457 
1458     /**
1459      * Returns the <code>PubSubModule</code> registered with this server. The
1460      * <code>PubSubModule</code> was registered with the server as a module while starting up
1461      * the server.
1462      *
1463      * @return the <code>PubSubModule</code> registered with this server.
1464      */
getPubSubModule()1465     public PubSubModule getPubSubModule() {
1466         return (PubSubModule) modules.get(PubSubModule.class);
1467     }
1468 
1469     /**
1470      * Returns the <code>ArchiveManager</code> registered with this server. The
1471      * <code>ArchiveManager</code> was registered with the server as a module while starting up
1472      * the server.
1473      *
1474      * @return the <code>ArchiveManager</code> registered with this server.
1475      */
getArchiveManager()1476     public ArchiveManager getArchiveManager() {
1477         return (ArchiveManager) modules.get(ArchiveManager.class);
1478     }
1479 
1480     /**
1481      * Returns a list with all the modules registered with the server that inherit from IQHandler.
1482      *
1483      * @return a list with all the modules registered with the server that inherit from IQHandler.
1484      */
getIQHandlers()1485     public List<IQHandler> getIQHandlers() {
1486         List<IQHandler> answer = new ArrayList<>();
1487         for (Module module : modules.values()) {
1488             if (module instanceof IQHandler) {
1489                 answer.add((IQHandler) module);
1490             }
1491         }
1492         return answer;
1493     }
1494 
1495     /**
1496      * Returns the <code>SessionManager</code> registered with this server. The
1497      * <code>SessionManager</code> was registered with the server as a module while starting up
1498      * the server.
1499      *
1500      * @return the <code>SessionManager</code> registered with this server.
1501      */
getSessionManager()1502     public SessionManager getSessionManager() {
1503         return (SessionManager) modules.get(SessionManager.class);
1504     }
1505 
1506     /**
1507      * Returns the <code>TransportHandler</code> registered with this server. The
1508      * <code>TransportHandler</code> was registered with the server as a module while starting up
1509      * the server.
1510      *
1511      * @return the <code>TransportHandler</code> registered with this server.
1512      */
getTransportHandler()1513     public TransportHandler getTransportHandler() {
1514         return (TransportHandler) modules.get(TransportHandler.class);
1515     }
1516 
1517     /**
1518      * Returns the <code>PresenceUpdateHandler</code> registered with this server. The
1519      * <code>PresenceUpdateHandler</code> was registered with the server as a module while starting
1520      * up the server.
1521      *
1522      * @return the <code>PresenceUpdateHandler</code> registered with this server.
1523      */
getPresenceUpdateHandler()1524     public PresenceUpdateHandler getPresenceUpdateHandler() {
1525         return (PresenceUpdateHandler) modules.get(PresenceUpdateHandler.class);
1526     }
1527 
1528     /**
1529      * Returns the <code>PresenceSubscribeHandler</code> registered with this server. The
1530      * <code>PresenceSubscribeHandler</code> was registered with the server as a module while
1531      * starting up the server.
1532      *
1533      * @return the <code>PresenceSubscribeHandler</code> registered with this server.
1534      */
getPresenceSubscribeHandler()1535     public PresenceSubscribeHandler getPresenceSubscribeHandler() {
1536         return (PresenceSubscribeHandler) modules.get(PresenceSubscribeHandler.class);
1537     }
1538 
1539     /**
1540      * Returns the <code>IQRouter</code> registered with this server. The
1541      * <code>IQRouter</code> was registered with the server as a module while starting up
1542      * the server.
1543      *
1544      * @return the <code>IQRouter</code> registered with this server.
1545      */
getIQRouter()1546     public IQRouter getIQRouter() {
1547         return (IQRouter) modules.get(IQRouter.class);
1548     }
1549 
1550     /**
1551      * Returns the <code>MessageRouter</code> registered with this server. The
1552      * <code>MessageRouter</code> was registered with the server as a module while starting up
1553      * the server.
1554      *
1555      * @return the <code>MessageRouter</code> registered with this server.
1556      */
getMessageRouter()1557     public MessageRouter getMessageRouter() {
1558         return (MessageRouter) modules.get(MessageRouter.class);
1559     }
1560 
1561     /**
1562      * Returns the <code>PresenceRouter</code> registered with this server. The
1563      * <code>PresenceRouter</code> was registered with the server as a module while starting up
1564      * the server.
1565      *
1566      * @return the <code>PresenceRouter</code> registered with this server.
1567      */
getPresenceRouter()1568     public PresenceRouter getPresenceRouter() {
1569         return (PresenceRouter) modules.get(PresenceRouter.class);
1570     }
1571 
1572     /**
1573      * Returns the <code>MulticastRouter</code> registered with this server. The
1574      * <code>MulticastRouter</code> was registered with the server as a module while starting up
1575      * the server.
1576      *
1577      * @return the <code>MulticastRouter</code> registered with this server.
1578      */
getMulticastRouter()1579     public MulticastRouter getMulticastRouter() {
1580         return (MulticastRouter) modules.get(MulticastRouter.class);
1581     }
1582 
1583     /**
1584      * Returns the <code>UserManager</code> registered with this server. The
1585      * <code>UserManager</code> was registered with the server as a module while starting up
1586      * the server.
1587      *
1588      * @return the <code>UserManager</code> registered with this server.
1589      */
getUserManager()1590     public UserManager getUserManager() {
1591         return UserManager.getInstance();
1592     }
1593 
1594     /**
1595      * Returns the <code>LockOutManager</code> registered with this server.  The
1596      * <code>LockOutManager</code> was registered with the server as a module while starting up
1597      * the server.
1598      *
1599      * @return the <code>LockOutManager</code> registered with this server.
1600      */
getLockOutManager()1601     public LockOutManager getLockOutManager() {
1602         return LockOutManager.getInstance();
1603     }
1604 
1605     /**
1606      * Returns the <code>UpdateManager</code> registered with this server. The
1607      * <code>UpdateManager</code> was registered with the server as a module while starting up
1608      * the server.
1609      *
1610      * @return the <code>UpdateManager</code> registered with this server.
1611      */
getUpdateManager()1612     public UpdateManager getUpdateManager() {
1613         return (UpdateManager) modules.get(UpdateManager.class);
1614     }
1615 
1616     /**
1617      * Returns the <code>AuditManager</code> registered with this server. The
1618      * <code>AuditManager</code> was registered with the server as a module while starting up
1619      * the server.
1620      *
1621      * @return the <code>AuditManager</code> registered with this server.
1622      */
getAuditManager()1623     public AuditManager getAuditManager() {
1624         return (AuditManager) modules.get(AuditManagerImpl.class);
1625     }
1626 
1627     /**
1628      * Returns the <code>EntityCapabilitiesManager</code> registered with this server. The
1629      * <code>EntityCapabilitiesManager</code> was registered with the server as a module while starting up
1630      * the server.
1631      *
1632      * @return the <code>EntityCapabilitiesManager</code> registered with this server.
1633      */
getEntityCapabilitiesManager()1634     public EntityCapabilitiesManager getEntityCapabilitiesManager() {
1635         return (EntityCapabilitiesManager) modules.get(EntityCapabilitiesManager.class);
1636     }
1637 
1638     /**
1639      * Returns a list with all the modules that provide "discoverable" features.
1640      *
1641      * @return a list with all the modules that provide "discoverable" features.
1642      * @deprecated Use {@link IQDiscoInfoHandler} instead.
1643      */
1644     @Deprecated
getServerFeaturesProviders()1645     public List<ServerFeaturesProvider> getServerFeaturesProviders() {
1646         List<ServerFeaturesProvider> answer = new ArrayList<>();
1647         for (Module module : modules.values()) {
1648             if (module instanceof ServerFeaturesProvider) {
1649                 answer.add((ServerFeaturesProvider) module);
1650             }
1651         }
1652         return answer;
1653     }
1654 
1655     /**
1656      * Returns a list with all the modules that provide "discoverable" identities.
1657      *
1658      * @return a list with all the modules that provide "discoverable" identities.
1659      * @deprecated Use {@link IQDiscoInfoHandler} instead.
1660      */
1661     @Deprecated
getServerIdentitiesProviders()1662     public List<ServerIdentitiesProvider> getServerIdentitiesProviders() {
1663         List<ServerIdentitiesProvider> answer = new ArrayList<>();
1664         for (Module module : modules.values()) {
1665             if (module instanceof ServerIdentitiesProvider) {
1666                 answer.add((ServerIdentitiesProvider) module);
1667             }
1668         }
1669         return answer;
1670     }
1671 
1672     /**
1673      * Returns a list with all the modules that provide "discoverable" items associated with
1674      * the server.
1675      *
1676      * @return a list with all the modules that provide "discoverable" items associated with
1677      *         the server.
1678      * @deprecated Use {@link IQDiscoItemsHandler} instead.
1679      */
1680     @Deprecated
getServerItemsProviders()1681     public List<ServerItemsProvider> getServerItemsProviders() {
1682         List<ServerItemsProvider> answer = new ArrayList<>();
1683         for (Module module : modules.values()) {
1684             if (module instanceof ServerItemsProvider) {
1685                 answer.add((ServerItemsProvider) module);
1686             }
1687         }
1688         return answer;
1689     }
1690 
1691     /**
1692      * Returns a list with all the modules that provide "discoverable" user identities.
1693      *
1694      * @return a list with all the modules that provide "discoverable" user identities.
1695      * @deprecated Use {@link IQDiscoInfoHandler} instead.
1696      */
1697     @Deprecated
getUserIdentitiesProviders()1698     public List<UserIdentitiesProvider> getUserIdentitiesProviders() {
1699         List<UserIdentitiesProvider> answer = new ArrayList<>();
1700         for (Module module : modules.values()) {
1701             if (module instanceof UserIdentitiesProvider) {
1702                 answer.add((UserIdentitiesProvider) module);
1703             }
1704         }
1705         return answer;
1706     }
1707 
1708     /**
1709      * Returns a list with all the modules that provide "discoverable" items associated with
1710      * users.
1711      *
1712      * @return a list with all the modules that provide "discoverable" items associated with
1713      *         users.
1714      * @deprecated Use {@link IQDiscoInfoHandler} instead.
1715      */
1716     @Deprecated
getUserItemsProviders()1717     public List<UserItemsProvider> getUserItemsProviders() {
1718         List<UserItemsProvider> answer = new ArrayList<>();
1719         for (Module module : modules.values()) {
1720             if (module instanceof UserItemsProvider) {
1721                 answer.add((UserItemsProvider) module);
1722             }
1723         }
1724         return answer;
1725     }
1726 
1727     /**
1728      * Returns the <code>IQDiscoInfoHandler</code> registered with this server. The
1729      * <code>IQDiscoInfoHandler</code> was registered with the server as a module while starting up
1730      * the server.
1731      *
1732      * @return the <code>IQDiscoInfoHandler</code> registered with this server.
1733      */
getIQDiscoInfoHandler()1734     public IQDiscoInfoHandler getIQDiscoInfoHandler() {
1735         return (IQDiscoInfoHandler) modules.get(IQDiscoInfoHandler.class);
1736     }
1737 
1738     /**
1739      * Returns the <code>IQDiscoItemsHandler</code> registered with this server. The
1740      * <code>IQDiscoItemsHandler</code> was registered with the server as a module while starting up
1741      * the server.
1742      *
1743      * @return the <code>IQDiscoItemsHandler</code> registered with this server.
1744      */
getIQDiscoItemsHandler()1745     public IQDiscoItemsHandler getIQDiscoItemsHandler() {
1746         return (IQDiscoItemsHandler) modules.get(IQDiscoItemsHandler.class);
1747     }
1748 
1749     /**
1750      * Returns the <code>PrivateStorage</code> registered with this server. The
1751      * <code>PrivateStorage</code> was registered with the server as a module while starting up
1752      * the server.
1753      *
1754      * @return the <code>PrivateStorage</code> registered with this server.
1755      */
getPrivateStorage()1756     public PrivateStorage getPrivateStorage() {
1757         return (PrivateStorage) modules.get(PrivateStorage.class);
1758     }
1759 
1760     /**
1761      * Returns the <code>MultiUserChatManager</code> registered with this server. The
1762      * <code>MultiUserChatManager</code> was registered with the server as a module while starting up
1763      * the server.
1764      *
1765      * @return the <code>MultiUserChatManager</code> registered with this server.
1766      */
getMultiUserChatManager()1767     public MultiUserChatManager getMultiUserChatManager() {
1768         return (MultiUserChatManager) modules.get(MultiUserChatManager.class);
1769     }
1770 
1771     /**
1772      * Returns the <code>AdHocCommandHandler</code> registered with this server. The
1773      * <code>AdHocCommandHandler</code> was registered with the server as a module while starting up
1774      * the server.
1775      *
1776      * @return the <code>AdHocCommandHandler</code> registered with this server.
1777      */
getAdHocCommandHandler()1778     public AdHocCommandHandler getAdHocCommandHandler() {
1779         return (AdHocCommandHandler) modules.get(AdHocCommandHandler.class);
1780     }
1781 
1782     /**
1783      * Returns the <code>FileTransferProxy</code> registered with this server. The
1784      * <code>FileTransferProxy</code> was registered with the server as a module while starting up
1785      * the server.
1786      *
1787      * @return the <code>FileTransferProxy</code> registered with this server.
1788      */
getFileTransferProxy()1789     public FileTransferProxy getFileTransferProxy() {
1790         return (FileTransferProxy) modules.get(FileTransferProxy.class);
1791     }
1792 
1793     /**
1794      * Returns the <code>FileTransferManager</code> registered with this server. The
1795      * <code>FileTransferManager</code> was registered with the server as a module while starting up
1796      * the server.
1797      *
1798      * @return the <code>FileTransferProxy</code> registered with this server.
1799      */
getFileTransferManager()1800     public FileTransferManager getFileTransferManager() {
1801         return (FileTransferManager) modules.get(DefaultFileTransferManager.class);
1802     }
1803 
1804     /**
1805      * Returns the <code>MediaProxyService</code> registered with this server. The
1806      * <code>MediaProxyService</code> was registered with the server as a module while starting up
1807      * the server.
1808      *
1809      * @return the <code>MediaProxyService</code> registered with this server.
1810      */
getMediaProxyService()1811     public MediaProxyService getMediaProxyService() {
1812         return (MediaProxyService) modules.get(MediaProxyService.class);
1813     }
1814 
1815     /**
1816      * Returns the <code>VCardManager</code> registered with this server. The
1817      * <code>VCardManager</code> was registered with the server as a module while starting up
1818      * the server.
1819      * @return the <code>VCardManager</code> registered with this server.
1820      */
getVCardManager()1821     public VCardManager getVCardManager() {
1822         return VCardManager.getInstance();
1823     }
1824 
1825     /**
1826      * Returns the <code>InternalComponentManager</code> registered with this server. The
1827      * <code>InternalComponentManager</code> was registered with the server as a module while starting up
1828      * the server.
1829      *
1830      * @return the <code>InternalComponentManager</code> registered with this server.
1831      */
getComponentManager()1832     private InternalComponentManager getComponentManager() {
1833         return (InternalComponentManager) modules.get(InternalComponentManager.class);
1834     }
1835 
1836     /**
1837      * Returns the <code>CertificateStoreManager</code> registered with this server. The
1838      * <code>CertificateStoreManager</code> was registered with the server as a module while starting up
1839      * the server.
1840      *
1841      * @return the <code>CertificateStoreManager</code> registered with this server.
1842      */
getCertificateStoreManager()1843     public CertificateStoreManager getCertificateStoreManager() {
1844         return (CertificateStoreManager) modules.get( CertificateStoreManager.class );
1845     }
1846     /**
1847      * Returns the locator to use to find sessions hosted in other cluster nodes. When not running
1848      * in a cluster a {@code null} value is returned.
1849      *
1850      * @return the locator to use to find sessions hosted in other cluster nodes.
1851      */
getRemoteSessionLocator()1852     public RemoteSessionLocator getRemoteSessionLocator() {
1853         return remoteSessionLocator;
1854     }
1855 
1856     /**
1857      * Sets the locator to use to find sessions hosted in other cluster nodes. When not running
1858      * in a cluster set a {@code null} value.
1859      *
1860      * @param remoteSessionLocator the locator to use to find sessions hosted in other cluster nodes.
1861      */
setRemoteSessionLocator(RemoteSessionLocator remoteSessionLocator)1862     public void setRemoteSessionLocator(RemoteSessionLocator remoteSessionLocator) {
1863         this.remoteSessionLocator = remoteSessionLocator;
1864     }
1865 
1866     /**
1867      * Returns whether or not the server has been started.
1868      *
1869      * @return whether or not the server has been started.
1870      */
isStarted()1871     public boolean isStarted() {
1872         return started;
1873     }
1874 
1875     /**
1876      * Asynchronously send a message to every administrator on the system.
1877      *
1878      * @param message The message to send
1879      * @return the future result of sending the message.
1880      */
sendMessageToAdmins(final String message)1881     public Future<?> sendMessageToAdmins(final String message) {
1882         return TaskEngine.getInstance().submit(() -> {
1883             final MessageRouter messageRouter = getMessageRouter();
1884             final Collection<JID> admins = XMPPServer.getInstance().getAdmins();
1885             final Message notification = new Message();
1886             notification.setFrom(getServerInfo().getXMPPDomain());
1887             notification.setBody(message);
1888             admins.forEach(jid -> {
1889                 logger.debug("Sending message to admin [jid={}, message={}]", jid, message);
1890                 notification.setTo(jid);
1891                 messageRouter.route(notification);
1892             });
1893         });
1894     }
1895 }
1896