/* * 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.Map; import java.util.Collection; import java.util.SortedSet; /** * Given an <code>EntryHandle</code> who's entry is making a * visibility transition this class will find all the * <code>TransitionWatcher</code>s who are interested in that * transition. The <code>TransitionWatcher</code>s are organized * into groups using <code>TemplateHandle</code>. Each * <code>TemplateHandle</code> aggregates a number of watchers * all interested in the same template. * * @see TransitionWatcher * @author Sun Microsystems, Inc. */ class TransitionWatchers { /** * A map from class names to <code>WatchersForTemplateClass</code> * objects */ final private Map holders = new java.util.HashMap(); /** The server we are working for */ final private OutriggerServerImpl server; /** * Create a new <code>TransitionWatchers</code> object * for the specified server. * @param server The server the new <code>TransitionWatchers</code> * object is working for. * @throws NullPointerException if <code>server</code> is * <code>null</code> */ TransitionWatchers(OutriggerServerImpl server) { if (server == null) throw new NullPointerException("server must be non-null"); this.server = server; } /** * 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. * <p> * This method is thread safe. The watcher added in this call is * guaranteed to be consulted by the next call to * <code>allMatches</code> that starts after this call completes even * if that call is made from another thread. Also, all of * of the assigned values in the calling thread's working * memory will be copied out to main memory as part of the * process of making the passed watcher visible to future * <code>allMatches</code> and <code>findTransitionWatcher</code> calls. * * @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) { // Get/create the appropriate WatchersForTemplateClass final String className = template.classFor(); WatchersForTemplateClass holder; synchronized (holders) { holder = (WatchersForTemplateClass) holders.get(className); if (holder == null) { holder = new WatchersForTemplateClass(this); holders.put(className, holder); } } // Add the watcher to the WatchersForTemplateClass holder.add(watcher, template); } /** * Return a <code>SortedSet</code> of all the * <code>TransitionWatcher</code> who's <code>isInterested</code> * methods return <code>true</code> when asked about the specified * visibility transition. * <p> * This method is thread safe. This call is guaranteed to check unremoved * watchers that were added by <code>add</code> calls that completed * before this call started, even if the calls were made from * different threads. Before the <code>isInterested</code> method * of the first watcher is called the working memory of this thread * will be flushed so any changes made to main memory before * this call started will be visible. * * @param transition A <code>EntryTransition</code> that * describes the transition and what * entry is transitioning. This method * will assume that <code>transition.getHandle</code> * returns a non-null value. * @param ordinal The ordinal associated with <code>transition</code>. * @return A new <code>SortedSet</code> of all the * <code>TransitionWatcher</code>s interested in the specified * visibility transition. If none are interested an empty * map will be returned. * @throws NullPointerException if <code>transition</code> is * <code>null</code>. */ SortedSet allMatches(EntryTransition transition, long ordinal) { final EntryRep rep = transition.getHandle().rep(); final SortedSet rslt = new java.util.TreeSet(); final String className = rep.classFor(); WatchersForTemplateClass holder; /* Collect all the watchers looking for the exact class of the * transitioned entry. Sync both to protect holder, and * to make sure we do at least one sync so we see any * watchers added before this call. */ synchronized (holders) { holder = (WatchersForTemplateClass)holders.get(className); } if (holder != null) holder.collectInterested(rslt, transition, ordinal); // Get all the templates that are super classes of className final String[] superclasses = rep.superclasses(); for (int i=0; i<superclasses.length; i++) { synchronized (holders) { holder = (WatchersForTemplateClass)holders.get(superclasses[i]); } if (holder != null) holder.collectInterested(rslt, transition, ordinal); } // Including those registered for the null template final String nullClass = EntryRep.matchAnyEntryRep().classFor(); synchronized(holders) { holder = (WatchersForTemplateClass)holders.get(nullClass); } if (holder!=null){ holder.collectInterested(rslt, transition, ordinal); } return rslt; } /** * Visit each <code>TransitionWatcher</code> and check to see if * it has expired, removing it if it has. Also reap the * <code>FastList</code>s. */ void reap() { /* This could take a while, instead of blocking all other * access to handles, clone the contents of handles and * iterate down the clone (we don't do this too often and * handles should never be that big so a shallow copy should * not be that bad, if it did get to be bad caching the * clone would probably work well since we don't add (and * never remove) elements that often.) */ final WatchersForTemplateClass content[]; synchronized (holders) { final Collection values = holders.values(); content = new WatchersForTemplateClass[values.size()]; values.toArray(content); } final long now = System.currentTimeMillis(); for (int i=0; i<content.length; i++) { content[i].reap(now); } } /** * Return the <code>OutriggerServerImpl</code> this * <code>TransitionWatchers</code> object is part of. * @return The <code>OutriggerServerImpl</code> this * <code>TransitionWatchers</code> is part of. */ OutriggerServerImpl getServer() { return server; } }