/* * 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.outrigger; import java.util.Set; /** * Holds a collection of <code>TemplateHandle</code>s who's templates * are all of exactly the same class. Unless otherwise noted all * methods are thread safe. This method provides the linkage between * <code>TemplateHandle</code>s and <code>TransitionWatchers</code> * and for the most part is not visible to the clients of either. */ class WatchersForTemplateClass { /** All the templates we know about */ private final FastList contents = new FastList(); /** The object we are inside of */ private final TransitionWatchers owner; /** * Create a new <code>WatchersForTemplateClass</code> object * associated with the specified <code>TransitionWatchers</code> object. * @param owner The <code>TransitionWatchers</code> that * this object will be a part of. * @throws NullPointerException if <code>owner</code> is * <code>null</code>. */ WatchersForTemplateClass(TransitionWatchers owner) { if (owner == null) throw new NullPointerException("owner must be non-null"); this.owner = owner; } /** * Add a <code>TransitionWatcher</code> to the list * of watchers looking for visibility transitions in * entries that match the specified template. Associates * a <code>TemplateHandle</code> using * <code>TransitionWatcher.setTemplateHandle</code> method. * * @param watcher The <code>TransitionWatcher</code> being added. * @param template The <code>EntryRep</code> that represents * the template of interest. * @throws NullPointerException if either argument is * <code>null</code>. */ void add(TransitionWatcher watcher, EntryRep template) { /* We try to find an existing handle, but it is ok * if we have more than one with the same template. It * is bad if we add the watcher to a removed handle. */ TemplateHandle handle = (TemplateHandle)contents.head(); for (; handle != null; handle = (TemplateHandle)handle.next()) { if (template.equals(handle.rep())) { synchronized (handle) { if (!handle.removed()) { /* Found one, add and break. Call * addTemplateHandle() before adding to handle * so if the handle calls the watcher it will * be in a complete state. Add inside the * lock so handle can't be removed. */ if (watcher.addTemplateHandle(handle)) { handle.addTransitionWatcher(watcher); } // else the watcher was removed, don't add to handle return; // found a handle and added the watcher } } } } /* If we are here we could not find a handle with the right * template, create one, add the watcher to it, and it * to contents. */ handle = new TemplateHandle(template, this); /* We need the sync both to prevent concurrent modification * of handle (since we add it to contents first), and to * make sure other threads see the changes we are about to make. */ synchronized (handle) { /* First add handle to contents so handle is fully initialized * before we start to pass it around use */ contents.add(handle); if (watcher.addTemplateHandle(handle)) { handle.addTransitionWatcher(watcher); } else { // watcher is already dead, undo adding handle contents.remove(handle); } } } /** * Iterate over the watchers associated with * this object calling <code>isInterested</code> on each * and if it returns <code>true</code> adding the watcher to the * passed set. * * @param set The set to accumulate interested watchers * into. * @param transition The transition being processed. * @param ordinal The ordinal associated with <code>transition</code>. * @throws NullPointerException if either argument is <code>null</code>. */ void collectInterested(Set set, EntryTransition transition, long ordinal) { final EntryHandle entryHandle = transition.getHandle(); final EntryRep rep = entryHandle.rep(); final long entryHash = entryHandle.hash(); final int repNumFields = rep.numFields(); /* Look at each of handles, check to see if they match * the changed entry and if they do ask them to * put the appropriate watchers in the set. */ for (TemplateHandle handle = (TemplateHandle)contents.head(); handle != null; handle = (TemplateHandle)handle.next()) { // See the if handle mask is incompatible EntryHandleTmplDesc desc = handle.descFor(repNumFields); if ((entryHash & desc.mask) != desc.hash) continue; if (handle.matches(rep)) { if (handle.removed()) //no sync, ok if we check a removed one continue; handle.collectInterested(set, transition, ordinal); } } } /** * Return the <code>OutriggerServerImpl</code> this * handle is part of. * @return The <code>OutriggerServerImpl</code> this * handle is part of. */ OutriggerServerImpl getServer() { return owner.getServer(); } /** * Visit each <code>TransitionWatcher</code> and check to see if * it has expired, removing it if it has. Also reaps the * <code>FastList</code> associated with this object. * @param now an estimate of the current time expressed as * milliseconds since the beginning of the epoch. */ void reap(long now) { // First remove empty handles for (TemplateHandle handle = (TemplateHandle)contents.head(); handle != null; handle = (TemplateHandle)handle.next()) { // Dump any expired watchers. handle.reap(now); /* Need to lock on the handle so no one will * add a watcher between the check for empty and * when it gets marked removed. */ synchronized (handle) { if (handle.isEmpty()) { contents.remove(handle); continue; } } } /* This provides the FastList with an opportunity to actually * excise the items identified as "removed" from the list. */ contents.reap(); } }