/* * 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 com.sun.jini.jeri.internal.http; import com.sun.jini.thread.Executor; import com.sun.jini.thread.GetThreadPoolAction; import java.util.Iterator; import java.util.LinkedList; import java.util.Random; import net.jini.io.context.AcknowledgmentSource; /** * Class for managing server-side functions shared among multiple connections, * such as acknowledgment notification. * * @author Sun Microsystems, Inc. * */ public class HttpServerManager { private static final Executor userThreadPool = (Executor) java.security.AccessController.doPrivileged( new GetThreadPoolAction(true)); private final AckListenerMap ackListeners; private final Object cookieLock = new Object(); private long nextCookie = new Random().nextLong(); /** * Creates new HttpServerManager which invalidates transport * acknowledgments after the given timeout. */ public HttpServerManager(long ackTimeout) { ackListeners = new AckListenerMap(ackTimeout); } /** * Returns unique cookie string. */ String newCookie() { synchronized (cookieLock) { return Long.toString(Math.abs(nextCookie++), 16); } } /** * Registers listener waiting for given cookie. */ void addAckListener(String cookie, AcknowledgmentSource.Listener listener) { if (cookie == null || listener == null) { throw new NullPointerException(); } synchronized (ackListeners) { LinkedList list = (LinkedList) ackListeners.get(cookie); if (list == null) { list = new LinkedList(); ackListeners.put(cookie, list); } list.add(listener); } } /** * Notifies all listeners waiting for given cookie with received == true. * Notifications are performed in a separate thread. */ void notifyAckListeners(String cookie) { if (cookie == null) { throw new NullPointerException(); } final LinkedList list = (LinkedList) ackListeners.remove(cookie); if (list != null) { userThreadPool.execute(new Runnable() { public void run() { doAckNotifications(list, true); } }, "Ack notifier"); } } /** * Notifies list of AcknowledgmentSource.Listeners. */ private static void doAckNotifications(LinkedList list, boolean recvd) { for (Iterator i = list.iterator(); i.hasNext(); ) { AcknowledgmentSource.Listener al = (AcknowledgmentSource.Listener) i.next(); try { al.acknowledgmentReceived(recvd); } catch (Throwable th) {} } } /** * Map for tracking registered AcknowledgmentSource.Listeners. */ private static class AckListenerMap extends TimedMap { AckListenerMap(long timeout) { super(userThreadPool, timeout); } void evicted(Object key, Object value) { doAckNotifications((LinkedList) value, false); } } }