blob: f8c1a6982e8f3dca8ef91d34ea9643c0ec7855cb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.tomcat.bayeux;
import java.util.LinkedList;
import org.apache.cometd.bayeux.Channel;
import org.apache.cometd.bayeux.Client;
import org.apache.cometd.bayeux.DataFilter;
import java.util.Collections;
import java.util.List;
import org.apache.cometd.bayeux.Message;
import java.util.Iterator;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
/**
*
* @version 1.0
*/
public class ChannelImpl implements Channel {
private static final Log log = LogFactory.getLog(ChannelImpl.class);
/**
* The unique id of this channel
*/
protected String id = null;
/**
* A list of the current subscribers
*/
protected LinkedList<Client> subscribers = new LinkedList<Client>();
/**
* A list of the current filters
*/
protected LinkedList<DataFilter> filters = new LinkedList<DataFilter>();
/**
* Is this channel persistent, default value is true
*/
protected boolean persistent = true;
/**
* Creates a new channel
* @param id String - the id of the channel, can not be null
*/
protected ChannelImpl(String id) {
assert id != null;
this.id = id;
}
/**
* returns the id of this channel
* @return String
*/
public String getId() {
return id;
}
/**
* Returns true if this channel matches the pattern to its id.
* The channel pattern can be a complete name like <code>/service/mychannel</code>
* or it can be a wild card pattern like <code>/service/app2/**</code>
* @param pattern String according to the Bayeux specification section 2.2.1 Channel Globbing, can not be null.
* @return boolean true if the id of this channel matches the pattern
*/
public boolean matches(String pattern) {
if (pattern == null)
throw new NullPointerException("Channel pattern must not be null.");
if (getId().equals(pattern))
return true;
int wildcardPos = pattern.indexOf("/*");
if (wildcardPos == -1)
return false;
boolean multiSegment = pattern.indexOf("**") != -1;
String leadSubstring = pattern.substring(0, wildcardPos);
if (leadSubstring == null)
return false;
if (multiSegment)
return getId().startsWith(leadSubstring);
else {
if (getId().length() <= wildcardPos + 2)
return false;
return !(getId().substring(wildcardPos + 2).contains("/"));
}
}
/**
* @return returns a non modifiable list of the subscribers for this channel.
*/
public List<Client> getSubscribers() {
return Collections.unmodifiableList(subscribers);
}
/**
* @return true if the Channel will persist without any subscription.
*/
public boolean isPersistent() {
return persistent;
}
public void publish(Message msg) {
publish(new Message[] {msg});
}
public void publish(Message[] msgs) {
if (msgs==null) return;
MessageImpl[] imsgs = new MessageImpl[msgs.length];
for (int i=0; msgs!=null && i<msgs.length; i++) {
Message data = msgs[i];
if (!(data instanceof MessageImpl))
throw new IllegalArgumentException("Invalid message class, you can only publish messages "+
"created through the Bayeux.newMessage() method");
if (log.isDebugEnabled()) {
log.debug("Publishing message:"+data+" to channel:"+this);
}
//clone it so that we can set this channel as a reference
MessageImpl msg = (MessageImpl)((MessageImpl)data).clone();
//this is the channel it was delivered through
msg.setChannel(this);
//pass through filters
for (Iterator<DataFilter> it = filters.iterator(); it.hasNext(); ) {
it.next().filter(msg);
}
imsgs[i] = msg;
}
//deliver it to the clients
for (Iterator<Client> it = subscribers.iterator(); it.hasNext(); ) {
ClientImpl c = (ClientImpl)it.next();
c.deliverInternal(this,imsgs);
}
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
}
public void subscribe(Client subscriber) {
if (!subscribers.contains((subscriber))) {
subscribers.addLast(subscriber);
((ClientImpl)subscriber).subscribed(this);
}
}
public Client unsubscribe(Client subscriber) {
if (subscribers.remove(subscriber)) {
((ClientImpl)subscriber).unsubscribed(this);
return subscriber;
} else
return null;
}
public void addFilter(DataFilter filter) {
if (!filters.contains(filter))
filters.addLast(filter);
}
public DataFilter removeFilter(DataFilter filter) {
if ( filters.remove(filter) ) return filter;
else return null;
}
public String toString() {
StringBuilder buf = new StringBuilder(super.toString());
buf.append("; channelId=").append(getId());
return buf.toString();
}
}