/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Emil Ong
*/
package com.caucho.bayeux;
import java.util.*;
class ChannelTree {
private final String _segment;
private final HashMap<String,ChannelTree> _children =
new HashMap<String,ChannelTree>();
private final ArrayList<BayeuxClient> _subscribers =
new ArrayList<BayeuxClient>();
public ChannelTree()
{
this("");
}
private ChannelTree(String segment)
{
_segment = segment;
}
/**
* Add a subscriber to this tree. Intended only to be called on the
* root of the tree. (i.e. the tree with segment "")
**/
public boolean subscribe(String channel, BayeuxClient subscriber)
{
String[] segments = channel.split("\\/");
return subscribe(segments, 1, subscriber);
}
protected boolean subscribe(String[] segments, int i, BayeuxClient subscriber)
{
if (segments.length >= i) {
synchronized(_subscribers) {
_subscribers.add(subscriber);
}
return true;
}
String segment = segments[i];
synchronized(_children) {
if ("*".equals(segments[i])) {
// "*" must be a trailing wildcard
if (i != segments.length - 1)
return false;
for (ChannelTree child : _children.values())
child.subscribe(segments, i + 1, subscriber);
}
else if ("**".equals(segments[i])) {
// "**" must be a trailing wildcard
if (i != segments.length - 1)
return false;
// minor hack here: not incrementing will force
// propagation through all subchildren
for (ChannelTree child : _children.values())
child.subscribe(segments, i, subscriber);
}
else {
ChannelTree child = _children.get(segment);
if (child == null) {
child = new ChannelTree(segment);
_children.put(segment, child);
}
child.subscribe(segments, i + 1, subscriber);
}
}
return true;
}
/**
* Publish a message to this tree. Intended only to be called on the
* root of the tree. (i.e. the tree with segment "")
**/
public boolean publish(String channel, Object object)
{
String[] segments = channel.split("\\/");
return publish(segments, 1, object);
}
protected boolean publish(String[] segments, int i, Object object)
{
if (segments.length >= i) {
synchronized(_subscribers) {
for (int j = 0; j < _subscribers.size(); j++)
_subscribers.get(j).publish(object);
}
return true;
}
String segment = segments[i];
synchronized(_children) {
if ("*".equals(segments[i])) {
// "*" must be a trailing wildcard
if (i != segments.length - 1)
return false;
for (ChannelTree child : _children.values())
child.publish(segments, i + 1, object);
}
else if ("**".equals(segments[i])) {
// "**" must be a trailing wildcard
if (i != segments.length - 1)
return false;
// minor hack here: not incrementing will force
// propagation through all subchildren
for (ChannelTree child : _children.values())
child.publish(segments, i, object);
}
else {
ChannelTree child = null;
child = _children.get(segment);
// no child means nobody to publish to
if (child == null)
return false;
child.publish(segments, i + 1, object);
}
}
return true;
}
}