All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.netty.channel.group.DefaultChannelGroup Maven / Gradle / Ivy

There is a newer version: 5.0.0.Alpha2
Show newest version
/*
 * Copyright 2013 The Netty Project
 *
 * The Netty Project 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 io.netty.channel.group;

import io.netty.buffer.BufUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.FileRegion;
import io.netty.channel.ServerChannel;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.FailedFuture;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ImmediateEventExecutor;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.SucceededFuture;
import io.netty.util.internal.PlatformDependent;

import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * The default {@link ChannelGroup} implementation.
 */
public class DefaultChannelGroup extends AbstractSet implements ChannelGroup {

    private static final AtomicInteger nextId = new AtomicInteger();
    private static final ImmediateEventExecutor DEFAULT_EXECUTOR = new ImmediateEventExecutor();
    private final String name;
    private final EventExecutor executor;
    private final ConcurrentMap serverChannels = PlatformDependent.newConcurrentHashMap();
    private final ConcurrentMap nonServerChannels = PlatformDependent.newConcurrentHashMap();
    private final ChannelFutureListener remover = new ChannelFutureListener() {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception {
            remove(future.channel());
        }
    };

    /**
     * Creates a new group with a generated name.
     */
    public DefaultChannelGroup() {
        this("group-0x" + Integer.toHexString(nextId.incrementAndGet()));
    }

    /**
     * Creates a new group with a generated name amd the provided {@link EventExecutor} to notify the
     * {@link ChannelGroupFuture}s.
     */
    public DefaultChannelGroup(EventExecutor executor) {
        this("group-0x" + Integer.toHexString(nextId.incrementAndGet()), executor);
    }

    /**
     * Creates a new group with the specified {@code name}.  Please note that
     * different groups can have the same name, which means no duplicate check
     * is done against group names.
     */
    public DefaultChannelGroup(String name) {
        this(name, DEFAULT_EXECUTOR);
    }

    /**
     * Creates a new group with the specified {@code name} and {@link EventExecutor} to notify the
     * {@link ChannelGroupFuture}s.  Please note that different groups can have the same name, which means no
     * duplicate check is done against group names.
     */
    public DefaultChannelGroup(String name, EventExecutor executor) {
        if (name == null) {
            throw new NullPointerException("name");
        }
        this.name = name;
        this.executor = executor;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public boolean isEmpty() {
        return nonServerChannels.isEmpty() && serverChannels.isEmpty();
    }

    @Override
    public int size() {
        return nonServerChannels.size() + serverChannels.size();
    }

    @Override
    public Channel find(Integer id) {
        Channel c = nonServerChannels.get(id);
        if (c != null) {
            return c;
        } else {
            return serverChannels.get(id);
        }
    }

    @Override
    public boolean contains(Object o) {
        if (o instanceof Integer) {
            return nonServerChannels.containsKey(o) || serverChannels.containsKey(o);
        } else if (o instanceof Channel) {
            Channel c = (Channel) o;
            if (o instanceof ServerChannel) {
                return serverChannels.containsKey(c.id());
            } else {
                return nonServerChannels.containsKey(c.id());
            }
        } else {
            return false;
        }
    }

    @Override
    public boolean add(Channel channel) {
        ConcurrentMap map =
            channel instanceof ServerChannel? serverChannels : nonServerChannels;

        boolean added = map.putIfAbsent(channel.id(), channel) == null;
        if (added) {
            channel.closeFuture().addListener(remover);
        }
        return added;
    }

    @Override
    public boolean remove(Object o) {
        Channel c = null;
        if (o instanceof Integer) {
            c = nonServerChannels.remove(o);
            if (c == null) {
                c = serverChannels.remove(o);
            }
        } else if (o instanceof Channel) {
            c = (Channel) o;
            if (c instanceof ServerChannel) {
                c = serverChannels.remove(c.id());
            } else {
                c = nonServerChannels.remove(c.id());
            }
        }

        if (c == null) {
            return false;
        }

        c.closeFuture().removeListener(remover);
        return true;
    }

    @Override
    public void clear() {
        nonServerChannels.clear();
        serverChannels.clear();
    }

    @Override
    public Iterator iterator() {
        return new CombinedIterator(
                serverChannels.values().iterator(),
                nonServerChannels.values().iterator());
    }

    @Override
    public Object[] toArray() {
        Collection channels = new ArrayList(size());
        channels.addAll(serverChannels.values());
        channels.addAll(nonServerChannels.values());
        return channels.toArray();
    }

    @Override
    public  T[] toArray(T[] a) {
        Collection channels = new ArrayList(size());
        channels.addAll(serverChannels.values());
        channels.addAll(nonServerChannels.values());
        return channels.toArray(a);
    }

    @Override
    public ChannelGroupFuture close() {
        Map futures =
            new LinkedHashMap(size());

        for (Channel c: serverChannels.values()) {
            futures.put(c.id(), c.close().awaitUninterruptibly());
        }
        for (Channel c: nonServerChannels.values()) {
            futures.put(c.id(), c.close());
        }

        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public ChannelGroupFuture disconnect() {
        Map futures =
            new LinkedHashMap(size());

        for (Channel c: serverChannels.values()) {
            futures.put(c.id(), c.disconnect());
        }
        for (Channel c: nonServerChannels.values()) {
            futures.put(c.id(), c.disconnect());
        }

        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public ChannelGroupFuture write(Object message) {
        if (message == null) {
            throw new NullPointerException("message");
        }

        Map futures = new LinkedHashMap(size());
        for (Channel c: nonServerChannels.values()) {
            BufUtil.retain(message);
            futures.put(c.id(), c.write(message));
        }

        BufUtil.release(message);
        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public ChannelGroupFuture sendFile(FileRegion region) {
        if (region == null) {
            throw new NullPointerException("region");
        }

        Map futures = new LinkedHashMap(size());
        for (Channel c: nonServerChannels.values()) {
            BufUtil.retain(region);
            futures.put(c.id(), c.sendFile(region));
        }

        BufUtil.release(region);
        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public ChannelGroupFuture flush() {
        Map futures = new LinkedHashMap(size());
        for (Channel c: nonServerChannels.values()) {
            futures.put(c.id(), c.flush());
        }

        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public ChannelGroupFuture deregister() {
        Map futures =
                new LinkedHashMap(size());

        for (Channel c: serverChannels.values()) {
            futures.put(c.id(), c.deregister());
        }
        for (Channel c: nonServerChannels.values()) {
            futures.put(c.id(), c.deregister());
        }

        return new DefaultChannelGroupFuture(this, futures, executor);
    }

    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }

    @Override
    public boolean equals(Object o) {
        return this == o;
    }

    @Override
    public int compareTo(ChannelGroup o) {
        int v = name().compareTo(o.name());
        if (v != 0) {
            return v;
        }

        return System.identityHashCode(this) - System.identityHashCode(o);
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() +
               "(name: " + name() + ", size: " + size() + ')';
    }

    private static final class ImmediateEventExecutor implements EventExecutor {
        private final Future successedFuture = new SucceededFuture(this);
        @Override
        public EventExecutor next() {
            return this;
        }

        @Override
        public EventExecutorGroup parent() {
            return null;
        }

        @Override
        public boolean inEventLoop() {
            return true;
        }

        @Override
        public boolean inEventLoop(Thread thread) {
            return true;
        }

        @Override
        public void shutdown() {
        }

        @Override
        public boolean isShutdown() {
            return false;
        }

        @Override
        public boolean isTerminated() {
            return false;
        }

        @Override
        public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
            return false;
        }

        @Override
        public Promise newPromise() {
            return new DefaultPromise(this);
        }

        @Override
        public Future newSucceededFuture() {
            return successedFuture;
        }

        @Override
        public Future newFailedFuture(Throwable cause) {
            return new FailedFuture(this, cause);
        }

        @Override
        public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) {
            throw new UnsupportedOperationException();
        }

        @Override
        public  ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
            throw new UnsupportedOperationException();
        }

        @Override
        public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay,
                                                      long period, TimeUnit unit) {
            throw new UnsupportedOperationException();
        }

        @Override
        public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay,
                                                         long delay, TimeUnit unit) {
            throw new UnsupportedOperationException();
        }

        @Override
        public List shutdownNow() {
            return Collections.emptyList();
        }

        @Override
        public  java.util.concurrent.Future submit(Callable task) {
            if (task == null) {
                throw new NullPointerException("task");
            }
            FutureTask future = new FutureTask(task);
            future.run();
            return future;
        }

        @Override
        public  java.util.concurrent.Future submit(Runnable task, T result) {
            if (task == null) {
                throw new NullPointerException("task");
            }
            FutureTask future = new FutureTask(task, result);
            future.run();
            return future;
        }

        @SuppressWarnings("unchecked")
        @Override
        public java.util.concurrent.Future submit(Runnable task) {
            if (task == null) {
                throw new NullPointerException("task");
            }
            FutureTask future = new FutureTask(task, null);
            future.run();
            return future;
        }

        @Override
        public  List> invokeAll(Collection> tasks) {
            if (tasks == null) {
                throw new NullPointerException("tasks");
            }
            List> futures = new ArrayList>();
            for (Callable task: tasks) {
                futures.add(submit(task));
            }
            return futures;
        }

        @Override
        public  List> invokeAll(Collection> tasks,
                                                                  long timeout, TimeUnit unit) {
            if (tasks == null) {
                throw new NullPointerException("tasks");
            }

            List> futures = new ArrayList>();
            for (Callable task: tasks) {
                futures.add(submit(task));
            }
            return futures;
        }

        @Override
        public  T invokeAny(Collection> tasks)
                throws InterruptedException, ExecutionException {
            if (tasks == null) {
                throw new NullPointerException("tasks");
            }
            if (tasks.isEmpty()) {
                throw new IllegalArgumentException("tasks must be non empty");
            }
            return invokeAll(tasks).get(0).get();
        }

        @Override
        public  T invokeAny(Collection> tasks, long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException {
            if (tasks == null) {
                throw new NullPointerException("tasks");
            }
            if (tasks.isEmpty()) {
                throw new IllegalArgumentException("tasks must be non empty");
            }
            return invokeAll(tasks).get(0).get();
        }

        @Override
        public void execute(Runnable command) {
            if (command == null) {
                throw new NullPointerException("command");
            }
            command.run();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy