org.jivesoftware.openfire.interceptor.InterceptorManager Maven / Gradle / Ivy
/*
* Copyright (C) 2005-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.interceptor;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.Packet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* An InterceptorManager manages the list of global interceptors and per-user
* interceptors that are invoked before and after packets are read and sent.
* If an interceptor is installed for a user then it will receive all packets
* sent or received for any connection of that user.
*
* PacketInterceptors that are invoked before the packet is sent or processed
* (when read) may change the original packet or reject the packet by throwing
* a {@link PacketRejectedException}. If the interceptor rejects a received packet
* then the sender of the packet receive a
* {@link org.xmpp.packet.PacketError.Condition#not_allowed not_allowed} error.
*
* @see PacketInterceptor
* @author Gaston Dombiak
*/
public class InterceptorManager {
private static final Logger Log = LoggerFactory.getLogger(InterceptorManager.class);
private static InterceptorManager instance = new InterceptorManager();
private XMPPServer server = XMPPServer.getInstance();
private List globalInterceptors =
new CopyOnWriteArrayList<>();
private Map> usersInterceptors =
new ConcurrentHashMap<>();
/**
* Returns a singleton instance of InterceptorManager.
*
* @return an instance of InterceptorManager.
*/
public static InterceptorManager getInstance() {
return instance;
}
/**
* Returns an unmodifiable list of global packet interceptors. Global
* interceptors are applied to all packets read and sent by the server.
*
* @return an unmodifiable list of the global packet interceptors.
*/
public List getInterceptors() {
return Collections.unmodifiableList(globalInterceptors);
}
/**
* Inserts a new interceptor at the end of the list of currently configured
* interceptors. This interceptor will be used for all the sent and received packets.
*
* @param interceptor the interceptor to add.
*/
public void addInterceptor(PacketInterceptor interceptor) {
if (interceptor == null) {
throw new NullPointerException("Parameter interceptor was null.");
}
// Remove the interceptor from the list since the position might have changed
if (globalInterceptors.contains(interceptor)) {
globalInterceptors.remove(interceptor);
}
globalInterceptors.add(interceptor);
}
/**
* Inserts a new interceptor at specified index in the list of currently configured
* interceptors. This interceptor will be used for all the sent and received packets.
*
* @param index the index in the list to insert the new interceptor at.
* @param interceptor the interceptor to add.
*/
public void addInterceptor(int index, PacketInterceptor interceptor) {
if (index < 0 || (index > globalInterceptors.size())) {
throw new IndexOutOfBoundsException("Index " + index + " invalid.");
}
if (interceptor == null) {
throw new NullPointerException("Parameter interceptor was null.");
}
// Remove the interceptor from the list since the position might have changed
if (globalInterceptors.contains(interceptor)) {
int oldIndex = globalInterceptors.indexOf(interceptor);
if (oldIndex < index) {
index -= 1;
}
globalInterceptors.remove(interceptor);
}
globalInterceptors.add(index, interceptor);
}
/**
* Removes the global interceptor from the list.
*
* @param interceptor the interceptor to remove.
* @return true if the item was present in the list
*/
public boolean removeInterceptor(PacketInterceptor interceptor) {
return globalInterceptors.remove(interceptor);
}
/**
* Returns an unmodifable list of packet interceptors that are related to the
* specified username.
*
* @param username the name of the user.
* @return an unmodifiable list of packet interceptors that are related to
* the specified username.
*/
public List getUserInterceptors(String username) {
List userInterceptors = usersInterceptors.get(username);
if (userInterceptors == null) {
return Collections.emptyList();
}
else {
return Collections.unmodifiableList(userInterceptors);
}
}
/**
* Inserts a new interceptor at specified index in the list of currently configured
* interceptors for a specific username. This interceptor will be used only when a packet
* was sent or received by the specified username.
*
* @param username the name of the user.
* @param index the index in the list to insert the new interceptor at.
* @param interceptor the interceptor to add.
*/
public void addUserInterceptor(String username, int index, PacketInterceptor interceptor) {
List userInterceptors = usersInterceptors.get(username);
if (userInterceptors == null) {
userInterceptors = new CopyOnWriteArrayList<>();
usersInterceptors.put(username, userInterceptors);
}
else {
if (index < 0 || (index > userInterceptors.size())) {
throw new IndexOutOfBoundsException("Index " + index + " invalid.");
}
if (interceptor == null) {
throw new NullPointerException("Parameter interceptor was null.");
}
// Remove the interceptor from the list since the position might have changed
if (userInterceptors.contains(interceptor)) {
int oldIndex = userInterceptors.indexOf(interceptor);
if (oldIndex < index) {
index -= 1;
}
userInterceptors.remove(interceptor);
}
}
userInterceptors.add(index, interceptor);
}
/**
* Removes the interceptor from the list of interceptors that are related to a specific
* username.
*
* @param username the name of the user.
* @param interceptor the interceptor to remove.
* @return true if the item was present in the list
*/
public boolean removeUserInterceptor(String username, PacketInterceptor interceptor) {
boolean answer = false;
List userInterceptors = usersInterceptors.get(username);
if (userInterceptors != null) {
answer = userInterceptors.remove(interceptor);
// Remove the entry for this username if the list is now empty
if (userInterceptors.isEmpty()) {
usersInterceptors.remove(username);
}
}
return answer;
}
/**
* Invokes all currently-installed interceptors on the specified packet.
* All global interceptors will be invoked as well as interceptors that
* are related to the address of the session that received or is sending
* the packet.
*
* Interceptors are executed before and after processing an incoming packet
* and sending a packet to a user. This means that interceptors are able to alter or
* reject packets before they are processed further. If possible, interceptors
* should perform their work in a short time so that overall performance is not
* compromised.
*
* @param packet the packet that has been read or is about to be sent.
* @param session the session that received the packet or that the packet
* will be sent to.
* @param read true indicates that the packet was read. When false, the packet
* is being sent to a user.
* @param processed true if the packet has already processed (incoming or outgoing).
* If the packet hasn't already been processed, this flag will be false.
* @throws PacketRejectedException if the packet should be prevented from being processed.
*/
public void invokeInterceptors(Packet packet, Session session, boolean read, boolean processed)
throws PacketRejectedException
{
// Invoke the global interceptors for this packet
invokeInterceptors( globalInterceptors, packet, session, read, processed );
// Invoke the interceptors that are related to the address of the session
if (usersInterceptors.isEmpty()) {
// Do nothing
return;
}
String username = session != null ? session.getAddress().getNode() : null;
if (username != null && server.isLocal(session.getAddress())) {
Collection userInterceptors = usersInterceptors.get(username);
invokeInterceptors( userInterceptors, packet, session, read, processed );
}
}
/**
* Invokes a collection of interceptors for the provided packet.
*
* @param interceptors The interceptors to be triggered (can be null, can be empty).
* @param packet the packet that has been read or is about to be sent.
* @param session the session that received the packet or that the packet
* will be sent to.
* @param read true indicates that the packet was read. When false, the packet
* is being sent to a user.
* @param processed true if the packet has already processed (incoming or outgoing).
* If the packet hasn't already been processed, this flag will be false.
* @throws PacketRejectedException if the packet should be prevented from being processed.
*/
protected static void invokeInterceptors( Collection interceptors, Packet packet, Session session, boolean read, boolean processed ) throws PacketRejectedException
{
if ( interceptors == null || interceptors.isEmpty() )
{
return;
}
for ( final PacketInterceptor interceptor : interceptors )
{
try
{
interceptor.interceptPacket( packet, session, read, processed );
}
catch ( PacketRejectedException e )
{
if ( processed )
{
Log.error( "Post interceptor cannot reject packet.", e );
}
else
{
// Throw this exception since we don't really want to catch it
throw e;
}
}
catch ( Throwable e )
{
Log.error( "Error in interceptor: " + interceptor + " while intercepting: " + packet, e );
}
}
}
}