src/core/net/sf/basedb/util/extensions/Registry.java

Code
Comments
Other
Rev Date Author Line
4158 22 Feb 08 nicklas 1 /**
4198 28 Mar 08 nicklas 2   $Id:Registry.java 4187 2008-03-20 11:15:25Z nicklas $
4158 22 Feb 08 nicklas 3
4158 22 Feb 08 nicklas 4   Copyright (C) Authors contributing to this file.
4158 22 Feb 08 nicklas 5
4158 22 Feb 08 nicklas 6   This file is part of BASE - BioArray Software Environment.
4158 22 Feb 08 nicklas 7   Available at http://base.thep.lu.se/
4158 22 Feb 08 nicklas 8
4158 22 Feb 08 nicklas 9   BASE is free software; you can redistribute it and/or
4158 22 Feb 08 nicklas 10   modify it under the terms of the GNU General Public License
4479 05 Sep 08 jari 11   as published by the Free Software Foundation; either version 3
4158 22 Feb 08 nicklas 12   of the License, or (at your option) any later version.
4158 22 Feb 08 nicklas 13
4158 22 Feb 08 nicklas 14   BASE is distributed in the hope that it will be useful,
4158 22 Feb 08 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
4158 22 Feb 08 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4158 22 Feb 08 nicklas 17   GNU General Public License for more details.
4158 22 Feb 08 nicklas 18
4158 22 Feb 08 nicklas 19   You should have received a copy of the GNU General Public License
4515 11 Sep 08 jari 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
4158 22 Feb 08 nicklas 21 */
4158 22 Feb 08 nicklas 22 package net.sf.basedb.util.extensions;
4158 22 Feb 08 nicklas 23
4158 22 Feb 08 nicklas 24 import java.util.ArrayList;
4163 28 Feb 08 nicklas 25 import java.util.Collection;
4158 22 Feb 08 nicklas 26 import java.util.Collections;
4202 01 Apr 08 nicklas 27 import java.util.Comparator;
4158 22 Feb 08 nicklas 28 import java.util.HashMap;
7273 20 Jan 17 nicklas 29 import java.util.Iterator;
4163 28 Feb 08 nicklas 30 import java.util.LinkedList;
4158 22 Feb 08 nicklas 31 import java.util.List;
4158 22 Feb 08 nicklas 32 import java.util.Map;
4158 22 Feb 08 nicklas 33
4158 22 Feb 08 nicklas 34 import net.sf.basedb.core.InvalidUseOfNullException;
4163 28 Feb 08 nicklas 35 import net.sf.basedb.core.ItemNotFoundException;
4163 28 Feb 08 nicklas 36 import net.sf.basedb.core.plugin.About;
4320 29 May 08 nicklas 37 import net.sf.basedb.util.extensions.events.EventFilter;
4320 29 May 08 nicklas 38 import net.sf.basedb.util.extensions.events.EventHandler;
4320 29 May 08 nicklas 39 import net.sf.basedb.util.extensions.events.EventType;
4170 07 Mar 08 nicklas 40 import net.sf.basedb.util.extensions.xml.XmlLoader;
4158 22 Feb 08 nicklas 41
4158 22 Feb 08 nicklas 42 /**
4158 22 Feb 08 nicklas 43   A registry for keeping track of extensions points and 
4163 28 Feb 08 nicklas 44   installed extensions. Extension points and extensions can, for example,
4163 28 Feb 08 nicklas 45   be created programmatically using the {@link ExtensionPointBean}
4163 28 Feb 08 nicklas 46   and {@link ExtensionBean} implementations, or loaded from
4170 07 Mar 08 nicklas 47   an XML extension definition file with the {@link XmlLoader}
4163 28 Feb 08 nicklas 48   class. Applications may provide other means of creating and
4163 28 Feb 08 nicklas 49   registering extensions and extensions points.
4158 22 Feb 08 nicklas 50
4158 22 Feb 08 nicklas 51   @author nicklas
4158 22 Feb 08 nicklas 52   @version 2.7
4198 28 Mar 08 nicklas 53   @base.modified $Date:2008-03-20 12:15:25 +0100 (Thu, 20 Mar 2008) $
4158 22 Feb 08 nicklas 54 */
4158 22 Feb 08 nicklas 55 public class Registry
4158 22 Feb 08 nicklas 56 {
4158 22 Feb 08 nicklas 57
6444 09 Apr 14 nicklas 58   private static final org.slf4j.Logger log = 
6444 09 Apr 14 nicklas 59     org.slf4j.LoggerFactory.getLogger(Registry.class);
4322 30 May 08 nicklas 60
5760 26 Sep 11 nicklas 61   /**
5760 26 Sep 11 nicklas 62     Comparator that sort extension points according to their names.
5760 26 Sep 11 nicklas 63     If two names are equal, the sort is also done on the id.
5760 26 Sep 11 nicklas 64     @since 3.0
5760 26 Sep 11 nicklas 65   */
6875 20 Apr 15 nicklas 66   public static final Comparator<ExtensionPoint<?>> EXTENSIONPOINT_COMPARATOR = 
6875 20 Apr 15 nicklas 67     new Comparator<ExtensionPoint<?>>()
4202 01 Apr 08 nicklas 68     {
4202 01 Apr 08 nicklas 69       @Override
6875 20 Apr 15 nicklas 70       public int compare(ExtensionPoint<?> o1, ExtensionPoint<?> o2)
4202 01 Apr 08 nicklas 71       {
5760 26 Sep 11 nicklas 72         int result = o1.getName().compareTo(o2.getName());
5760 26 Sep 11 nicklas 73         if (result == 0) result = o1.getId().compareTo(o2.getId());
5760 26 Sep 11 nicklas 74         return result;
4202 01 Apr 08 nicklas 75       }
4202 01 Apr 08 nicklas 76     };
5760 26 Sep 11 nicklas 77
5760 26 Sep 11 nicklas 78   /**
5760 26 Sep 11 nicklas 79     Comparator that sort extensions according to their names.
5760 26 Sep 11 nicklas 80     If two names are equal, the sort is also done on the id.
5760 26 Sep 11 nicklas 81     @since 3.0
5760 26 Sep 11 nicklas 82   */
6875 20 Apr 15 nicklas 83   public static final Comparator<Extension<?>> EXTENSION_COMPARATOR = 
6875 20 Apr 15 nicklas 84     new Comparator<Extension<?>>()
5760 26 Sep 11 nicklas 85     {
5760 26 Sep 11 nicklas 86       @Override
6875 20 Apr 15 nicklas 87       public int compare(Extension<?> o1, Extension<?> o2)
5760 26 Sep 11 nicklas 88       {
5760 26 Sep 11 nicklas 89         String name1 = o1.getAbout() == null ? null : o1.getAbout().getName();
5760 26 Sep 11 nicklas 90         String name2 = o2.getAbout() == null ? null : o2.getAbout().getName();
5760 26 Sep 11 nicklas 91         int result = name1 != null && name2 != null ? name1.compareTo(name2) : 0;
5760 26 Sep 11 nicklas 92         if (result == 0) result = o1.getId().compareTo(o2.getId());
5760 26 Sep 11 nicklas 93         return result;
5760 26 Sep 11 nicklas 94       }
5760 26 Sep 11 nicklas 95     };
5760 26 Sep 11 nicklas 96
6602 17 Nov 14 nicklas 97   /**
6602 17 Nov 14 nicklas 98     Comparator that sort extensions according to their ids.
6602 17 Nov 14 nicklas 99     @since 3.4
6602 17 Nov 14 nicklas 100   */
6875 20 Apr 15 nicklas 101   public static final Comparator<ExtensionPoint<?>> EXTENSIONPOINT_ID_COMPARATOR = 
6875 20 Apr 15 nicklas 102     new Comparator<ExtensionPoint<?>>()
6602 17 Nov 14 nicklas 103     {
6602 17 Nov 14 nicklas 104       @Override
6875 20 Apr 15 nicklas 105       public int compare(ExtensionPoint<?> o1, ExtensionPoint<?> o2)
6602 17 Nov 14 nicklas 106       {
6602 17 Nov 14 nicklas 107         return o1.getId().compareTo(o2.getId());
6602 17 Nov 14 nicklas 108       }
6602 17 Nov 14 nicklas 109     };
6602 17 Nov 14 nicklas 110
5760 26 Sep 11 nicklas 111     
6602 17 Nov 14 nicklas 112   /**
6602 17 Nov 14 nicklas 113     Comparator that sort extensions according to their ids.
6602 17 Nov 14 nicklas 114     @since 3.4
6602 17 Nov 14 nicklas 115   */
6875 20 Apr 15 nicklas 116   public static final Comparator<Extension<?>> EXTENSION_ID_COMPARATOR = 
6875 20 Apr 15 nicklas 117     new Comparator<Extension<?>>()
6602 17 Nov 14 nicklas 118     {
6602 17 Nov 14 nicklas 119       @Override
6875 20 Apr 15 nicklas 120       public int compare(Extension<?> o1, Extension<?> o2)
6602 17 Nov 14 nicklas 121       {
6602 17 Nov 14 nicklas 122         return o1.getId().compareTo(o2.getId());
6602 17 Nov 14 nicklas 123       }
6602 17 Nov 14 nicklas 124     };
6602 17 Nov 14 nicklas 125
4163 28 Feb 08 nicklas 126   private final Map<String, RegisteredExtensionPoint<?>> extensionPoints;
4163 28 Feb 08 nicklas 127   private final Map<String, RegisteredExtension<?>> extensions;
4198 28 Mar 08 nicklas 128   private Map<AttributeKey, Object> attributes;
7273 20 Jan 17 nicklas 129   private Map<EventHandler, RegisteredEventHandler> eventHandlers;
5487 15 Nov 10 nicklas 130   private ErrorHandlerFactory<Action> defaultErrorHandlerFactory;
4198 28 Mar 08 nicklas 131
4158 22 Feb 08 nicklas 132   /**
4163 28 Feb 08 nicklas 133     Create a new empty registry.
4158 22 Feb 08 nicklas 134   */
4158 22 Feb 08 nicklas 135   public Registry()
4158 22 Feb 08 nicklas 136   {
4163 28 Feb 08 nicklas 137     extensionPoints = new HashMap<String, RegisteredExtensionPoint<?>>();
4163 28 Feb 08 nicklas 138     extensions = new HashMap<String, RegisteredExtension<?>>();
5487 15 Nov 10 nicklas 139     defaultErrorHandlerFactory = new LoggingErrorHandlerFactory();
4158 22 Feb 08 nicklas 140   }
4158 22 Feb 08 nicklas 141   
4208 07 Apr 08 nicklas 142   /**
5487 15 Nov 10 nicklas 143     Set the default error handler factory.
5487 15 Nov 10 nicklas 144     @param defaultErrorHandlerFactory Null is not allowed
5487 15 Nov 10 nicklas 145     @since 2.17
5487 15 Nov 10 nicklas 146   */
5487 15 Nov 10 nicklas 147   public void setDefaultErrorHandlerFactory(ErrorHandlerFactory<Action> defaultErrorHandlerFactory)
5487 15 Nov 10 nicklas 148   {
5487 15 Nov 10 nicklas 149     if (defaultErrorHandlerFactory == null) 
5487 15 Nov 10 nicklas 150     {
5487 15 Nov 10 nicklas 151       throw new InvalidUseOfNullException("defaultErrorHandlerFactory");
5487 15 Nov 10 nicklas 152     }
5487 15 Nov 10 nicklas 153     this.defaultErrorHandlerFactory = defaultErrorHandlerFactory;
5487 15 Nov 10 nicklas 154   }
5487 15 Nov 10 nicklas 155   
5487 15 Nov 10 nicklas 156   /**
5487 15 Nov 10 nicklas 157     Get the default error handler factory.
5487 15 Nov 10 nicklas 158     @since 2.17
5487 15 Nov 10 nicklas 159   */
5487 15 Nov 10 nicklas 160   public ErrorHandlerFactory<Action> getDefaultErrorHandlerFactory()
5487 15 Nov 10 nicklas 161   {
5487 15 Nov 10 nicklas 162     return defaultErrorHandlerFactory;
5487 15 Nov 10 nicklas 163   }
5487 15 Nov 10 nicklas 164   
5487 15 Nov 10 nicklas 165   /**
4208 07 Apr 08 nicklas 166     Get the value of a extra attribute for a registered extension
4208 07 Apr 08 nicklas 167     or extension point.
4208 07 Apr 08 nicklas 168     @param id The ID of a registered extension or extension point
4208 07 Apr 08 nicklas 169     @param name The name of the attribute
4208 07 Apr 08 nicklas 170     @return The attribute value or null if no value has been set
4208 07 Apr 08 nicklas 171   */
4208 07 Apr 08 nicklas 172   public Object getAttribute(String id, String name)
4198 28 Mar 08 nicklas 173   {
4208 07 Apr 08 nicklas 174     if (id == null || name == null || attributes == null) return null;
4208 07 Apr 08 nicklas 175     AttributeKey key = new AttributeKey(id, name);
4198 28 Mar 08 nicklas 176     return attributes.get(key);
4198 28 Mar 08 nicklas 177   }
4198 28 Mar 08 nicklas 178   
4208 07 Apr 08 nicklas 179   /**
4208 07 Apr 08 nicklas 180     Set an extra attribute on a registered extension or extension point.
4208 07 Apr 08 nicklas 181     @param id The ID of a registered extension or extension point
4208 07 Apr 08 nicklas 182     @param name The name of the attribute
4208 07 Apr 08 nicklas 183     @param value The attribute value. A null value removes the attribute.
4208 07 Apr 08 nicklas 184   */
4208 07 Apr 08 nicklas 185   public void setAttribute(String id, String name, Object value)
4198 28 Mar 08 nicklas 186   {
4208 07 Apr 08 nicklas 187     if (id == null || name == null) return;
4208 07 Apr 08 nicklas 188     AttributeKey key = new AttributeKey(id, name);
4198 28 Mar 08 nicklas 189     if (attributes == null) attributes = new HashMap<AttributeKey, Object>();
4198 28 Mar 08 nicklas 190     if (value == null)
4198 28 Mar 08 nicklas 191     {
4198 28 Mar 08 nicklas 192       attributes.remove(key);
4198 28 Mar 08 nicklas 193     }
4198 28 Mar 08 nicklas 194     else
4198 28 Mar 08 nicklas 195     {
4198 28 Mar 08 nicklas 196       attributes.put(key, value);
4198 28 Mar 08 nicklas 197     }
4198 28 Mar 08 nicklas 198   }
4198 28 Mar 08 nicklas 199   
4158 22 Feb 08 nicklas 200   /**
4320 29 May 08 nicklas 201     Register an event handler for responding to events happening to 
4320 29 May 08 nicklas 202     extension points and extensions in the registry. The registry itself
4320 29 May 08 nicklas 203     sends the events listed below. Other events may be sent externally
4320 29 May 08 nicklas 204     by calling {@link #handleEvent(EventType, ExtensionPoint, Extension)}.
4320 29 May 08 nicklas 205     
4320 29 May 08 nicklas 206     <ul>
4320 29 May 08 nicklas 207     <li>{@link EventType#AFTER_REGISTRATION}
4320 29 May 08 nicklas 208     <li>{@link EventType#BEFORE_UPDATE}
4320 29 May 08 nicklas 209     <li>{@link EventType#AFTER_UPDATE}
4320 29 May 08 nicklas 210     <li>{@link EventType#BEFORE_UNREGISTRATION}
6881 21 Apr 15 nicklas 211     </ul>
4320 29 May 08 nicklas 212     
4320 29 May 08 nicklas 213     @param eventHandler The handler that should be called
4320 29 May 08 nicklas 214     @param filter A filter that determines which events that should be
4320 29 May 08 nicklas 215       sent to the handler, or null to send all events
7273 20 Jan 17 nicklas 216     @param classLoader The class loader that "owns" the event handler. The class 
7273 20 Jan 17 nicklas 217       loader is requried to be able to automatically unregister event handlers 
7273 20 Jan 17 nicklas 218       when an extension is uninstalled or updated. If null, automatic unloading 
7273 20 Jan 17 nicklas 219       is disabled (beware of memory leaks!).
7273 20 Jan 17 nicklas 220     @since 3.10
4320 29 May 08 nicklas 221   */
7273 20 Jan 17 nicklas 222   public synchronized void registerEventHandler(EventHandler eventHandler, EventFilter filter, ClassLoader classLoader)
4320 29 May 08 nicklas 223   {
7273 20 Jan 17 nicklas 224     if (eventHandler == null) return;
7273 20 Jan 17 nicklas 225     if (eventHandlers == null) eventHandlers = new HashMap<EventHandler, RegisteredEventHandler>();
7273 20 Jan 17 nicklas 226     eventHandlers.put(eventHandler, new RegisteredEventHandler(eventHandler, filter, classLoader));
4320 29 May 08 nicklas 227   }
4320 29 May 08 nicklas 228   
4320 29 May 08 nicklas 229   /**
4320 29 May 08 nicklas 230     Unregisters an event handler.
4320 29 May 08 nicklas 231     @param eventHandler The event handler
4320 29 May 08 nicklas 232     @since 2.8
4320 29 May 08 nicklas 233   */
7273 20 Jan 17 nicklas 234   public synchronized void unregisterEventHandler(EventHandler eventHandler)
4320 29 May 08 nicklas 235   {
7273 20 Jan 17 nicklas 236     if (eventHandlers == null || eventHandler == null) return;
4320 29 May 08 nicklas 237     eventHandlers.remove(eventHandler);
4320 29 May 08 nicklas 238   }
4320 29 May 08 nicklas 239   
4320 29 May 08 nicklas 240   /**
7273 20 Jan 17 nicklas 241     Unregister all event handlers that was loaded by
7273 20 Jan 17 nicklas 242     the given class loader. This method should be called when
7273 20 Jan 17 nicklas 243     an extension file is being uninstalled or updated since the
7273 20 Jan 17 nicklas 244     old registered event handlers can then no longer be used
7273 20 Jan 17 nicklas 245     and it is really complicated for an extension that register
7273 20 Jan 17 nicklas 246     event handler to detect a re-installation property. It is 
7273 20 Jan 17 nicklas 247     better to try to handle this at the core level.
7273 20 Jan 17 nicklas 248
7273 20 Jan 17 nicklas 249     @param classLoader The class loader that is responsible for
7273 20 Jan 17 nicklas 250       the extension file that is about to be uninstalled or 
7273 20 Jan 17 nicklas 251       updated
7273 20 Jan 17 nicklas 252     @since 3.10
7273 20 Jan 17 nicklas 253   */
7273 20 Jan 17 nicklas 254   public synchronized void unregisterEventHandlers(ClassLoader classLoader)
7273 20 Jan 17 nicklas 255   {
7273 20 Jan 17 nicklas 256     if (eventHandlers == null || classLoader == null) return;
7273 20 Jan 17 nicklas 257     Iterator<RegisteredEventHandler> it = eventHandlers.values().iterator();
7273 20 Jan 17 nicklas 258     while (it.hasNext())
7273 20 Jan 17 nicklas 259     {
7273 20 Jan 17 nicklas 260       RegisteredEventHandler reg = it.next();
7273 20 Jan 17 nicklas 261       if (classLoader.equals(reg.loader))
7273 20 Jan 17 nicklas 262       {
7273 20 Jan 17 nicklas 263         it.remove();
7273 20 Jan 17 nicklas 264       }
7273 20 Jan 17 nicklas 265     }
7273 20 Jan 17 nicklas 266   }
7273 20 Jan 17 nicklas 267   
7273 20 Jan 17 nicklas 268   /**
4320 29 May 08 nicklas 269     Send an event to all event handlers.
4320 29 May 08 nicklas 270     
4320 29 May 08 nicklas 271     @param eventType The event type
4320 29 May 08 nicklas 272     @param extensionPoint The extension point the event is about
4320 29 May 08 nicklas 273     @param extension The extension the event is about, or null
4320 29 May 08 nicklas 274     @since 2.8
4320 29 May 08 nicklas 275   */
7273 20 Jan 17 nicklas 276   public synchronized void handleEvent(EventType eventType, ExtensionPoint<?> extensionPoint, Extension<?> extension)
4320 29 May 08 nicklas 277   {
4320 29 May 08 nicklas 278     if (eventHandlers == null) return;
7273 20 Jan 17 nicklas 279     // Make copy since events may trigger registering of other event handlers
7273 20 Jan 17 nicklas 280     // causing ConcurrentModificationException
7273 20 Jan 17 nicklas 281     Iterator<RegisteredEventHandler> it = new ArrayList<RegisteredEventHandler>(eventHandlers.values()).iterator();
7273 20 Jan 17 nicklas 282     while (it.hasNext())
4320 29 May 08 nicklas 283     {
7273 20 Jan 17 nicklas 284       RegisteredEventHandler reg = it.next();
7273 20 Jan 17 nicklas 285       EventFilter filter = reg.filter;
7273 20 Jan 17 nicklas 286
4320 29 May 08 nicklas 287       if (filter == null || filter.shouldSend(eventType, extensionPoint, extension))
4320 29 May 08 nicklas 288       {
4320 29 May 08 nicklas 289         try
4320 29 May 08 nicklas 290         {
7273 20 Jan 17 nicklas 291           reg.handler.handleEvent(eventType, extensionPoint, extension);
4320 29 May 08 nicklas 292         }
4322 30 May 08 nicklas 293         catch (Throwable t)
4320 29 May 08 nicklas 294         {
7273 20 Jan 17 nicklas 295           log.error("Error when sending event '" + eventType + "' to extension point '" + 
4322 30 May 08 nicklas 296             extensionPoint + "' and extension '" + extension + "'", t);
4320 29 May 08 nicklas 297         }
4320 29 May 08 nicklas 298       }
4320 29 May 08 nicklas 299     }
4320 29 May 08 nicklas 300   }
4320 29 May 08 nicklas 301   
4320 29 May 08 nicklas 302   /**
4158 22 Feb 08 nicklas 303     Checks if an extension point is registered or not.
4158 22 Feb 08 nicklas 304     @param id The ID of the extension point
4163 28 Feb 08 nicklas 305     @return TRUE if an extension point with the given ID is registered,
4158 22 Feb 08 nicklas 306       FALSE otherwise
4158 22 Feb 08 nicklas 307   */
4158 22 Feb 08 nicklas 308   public boolean extensionPointIsRegistered(String id)
4158 22 Feb 08 nicklas 309   {
4158 22 Feb 08 nicklas 310     return extensionPoints.containsKey(id);
4158 22 Feb 08 nicklas 311   }
4158 22 Feb 08 nicklas 312   
4158 22 Feb 08 nicklas 313   /**
4158 22 Feb 08 nicklas 314     Register an extension point. If the extension point already exists,
4163 28 Feb 08 nicklas 315     the description and renderer factory is updated. The action class
4163 28 Feb 08 nicklas 316     can't be changed for a registered extension point. The registry keeps
4163 28 Feb 08 nicklas 317     it's own internal representation of the extension point. Changes to
4163 28 Feb 08 nicklas 318     the object passed as a parameter to this method will not be reflected
4163 28 Feb 08 nicklas 319     in the registry.
4163 28 Feb 08 nicklas 320     
4163 28 Feb 08 nicklas 321     @param extensionPoint The extension point to register
6030 28 Mar 12 nicklas 322     @param classLoader The class loader that is responsible for loading classes
6030 28 Mar 12 nicklas 323       for the extension point, or null if the default class loader should be used
4163 28 Feb 08 nicklas 324     @throws InvalidUseOfNullException If the extension point is null, or if the ID 
4163 28 Feb 08 nicklas 325       or actionClass is null
4163 28 Feb 08 nicklas 326     @throws ClassCastException If the action class doesn't implement the
4163 28 Feb 08 nicklas 327       {@link Action} interface
6030 28 Mar 12 nicklas 328     @since 3.2
4158 22 Feb 08 nicklas 329   */
4163 28 Feb 08 nicklas 330   @SuppressWarnings("unchecked")
4198 28 Mar 08 nicklas 331   public synchronized <A extends Action> void 
6030 28 Mar 12 nicklas 332     registerExtensionPoint(ExtensionPoint<A> extensionPoint, ClassLoader classLoader)
4158 22 Feb 08 nicklas 333   {
4163 28 Feb 08 nicklas 334     if (extensionPoint == null) throw new InvalidUseOfNullException("extensionPoint");
4163 28 Feb 08 nicklas 335
4198 28 Mar 08 nicklas 336     String id = extensionPoint.getId();
4198 28 Mar 08 nicklas 337     if (id == null) 
4163 28 Feb 08 nicklas 338     {
4198 28 Mar 08 nicklas 339       throw new InvalidUseOfNullException("extensionPoint.id of " + extensionPoint);
4163 28 Feb 08 nicklas 340     }
4233 17 Apr 08 nicklas 341     Class<A> actionClass = extensionPoint.getActionClass();
4233 17 Apr 08 nicklas 342     if (actionClass == null) 
4163 28 Feb 08 nicklas 343     {
4198 28 Mar 08 nicklas 344       throw new InvalidUseOfNullException("Action class of extensionPoint[id=" + id + "]");
4163 28 Feb 08 nicklas 345     }
4233 17 Apr 08 nicklas 346     if (!Action.class.isAssignableFrom(actionClass))
4163 28 Feb 08 nicklas 347     {
4233 17 Apr 08 nicklas 348       throw new ClassCastException("Action class '" + actionClass.getName() + 
4198 28 Mar 08 nicklas 349         "' of extensionPoint[id=" + id + "] doesn't implement the 'Action' class");
4163 28 Feb 08 nicklas 350     }
4163 28 Feb 08 nicklas 351     
4163 28 Feb 08 nicklas 352     RegisteredExtensionPoint<A> rep = 
4163 28 Feb 08 nicklas 353       (RegisteredExtensionPoint<A>)extensionPoints.get(extensionPoint.getId());
4163 28 Feb 08 nicklas 354     if (rep == null)
4163 28 Feb 08 nicklas 355     {
4163 28 Feb 08 nicklas 356       // Create a new registered entry
6030 28 Mar 12 nicklas 357       rep = new RegisteredExtensionPoint<A>(extensionPoint, classLoader);
4163 28 Feb 08 nicklas 358       extensionPoints.put(extensionPoint.getId(), rep);
4320 29 May 08 nicklas 359       handleEvent(EventType.AFTER_REGISTRATION, rep, null);
4163 28 Feb 08 nicklas 360     }
4163 28 Feb 08 nicklas 361     else
4163 28 Feb 08 nicklas 362     {
4163 28 Feb 08 nicklas 363       // Update the existing registration
4320 29 May 08 nicklas 364       handleEvent(EventType.BEFORE_UPDATE, rep, null);
6030 28 Mar 12 nicklas 365       rep.update(extensionPoint, classLoader);
4320 29 May 08 nicklas 366       handleEvent(EventType.AFTER_UPDATE, rep, null);
4163 28 Feb 08 nicklas 367     }
4158 22 Feb 08 nicklas 368   }
4158 22 Feb 08 nicklas 369   
4158 22 Feb 08 nicklas 370   /**
4158 22 Feb 08 nicklas 371     Unregister an extension point. If the extension point doesn't exists,
4158 22 Feb 08 nicklas 372     nothing is done. This method will also unregister all extensions
4158 22 Feb 08 nicklas 373     that extends the given extension point.
4158 22 Feb 08 nicklas 374     
4158 22 Feb 08 nicklas 375     @param id The ID of the extension point to unregister
4158 22 Feb 08 nicklas 376     @throws InvalidUseOfNullException If the ID is null
4158 22 Feb 08 nicklas 377   */
4158 22 Feb 08 nicklas 378   public synchronized void unregisterExtensionPoint(String id)
4158 22 Feb 08 nicklas 379   {
4158 22 Feb 08 nicklas 380     if (id == null) throw new InvalidUseOfNullException("id");
4320 29 May 08 nicklas 381     RegisteredExtensionPoint<?> rep = extensionPoints.get(id);
4320 29 May 08 nicklas 382     if (rep != null)
4320 29 May 08 nicklas 383     {
4320 29 May 08 nicklas 384       handleEvent(EventType.BEFORE_UNREGISTRATION, rep, null);
5607 15 Apr 11 nicklas 385       for (RegisteredExtension<?> rext : rep.getExtensions())
5607 15 Apr 11 nicklas 386       {
5607 15 Apr 11 nicklas 387         handleEvent(EventType.BEFORE_UNREGISTRATION, rep, rext);
5607 15 Apr 11 nicklas 388         extensions.remove(rext.getId());
5607 15 Apr 11 nicklas 389       }
4320 29 May 08 nicklas 390       extensionPoints.remove(id);
4320 29 May 08 nicklas 391     }
4158 22 Feb 08 nicklas 392   }
4158 22 Feb 08 nicklas 393   
4158 22 Feb 08 nicklas 394   /**
4158 22 Feb 08 nicklas 395     Get the extension point with a given ID.
4158 22 Feb 08 nicklas 396     @param id The ID of the extension point
4158 22 Feb 08 nicklas 397     @return An {@link ExtensionPoint} object or null if that 
4158 22 Feb 08 nicklas 398       extension point doesn't exists
4158 22 Feb 08 nicklas 399   */
4158 22 Feb 08 nicklas 400   public ExtensionPoint<?> getExtensionPoint(String id)
4158 22 Feb 08 nicklas 401   {
4158 22 Feb 08 nicklas 402     return extensionPoints.get(id);
4158 22 Feb 08 nicklas 403   }
4158 22 Feb 08 nicklas 404   
4158 22 Feb 08 nicklas 405   /**
5599 31 Mar 11 nicklas 406     Get a list with all registered extension points.
5599 31 Mar 11 nicklas 407     The returned list is a copy of the registered extension points
5599 31 Mar 11 nicklas 408     at the time of this call and will not reflect changes
5599 31 Mar 11 nicklas 409     made to the registry after this call has returned.
4163 28 Feb 08 nicklas 410     
5599 31 Mar 11 nicklas 411     @return A list
5599 31 Mar 11 nicklas 412     @since 3.0 (Returned an Iterator in BASE 2.x)
4158 22 Feb 08 nicklas 413   */
5599 31 Mar 11 nicklas 414   public synchronized List<ExtensionPoint<?>> getExtensionPoints()
4158 22 Feb 08 nicklas 415   {
4168 04 Mar 08 nicklas 416     List<ExtensionPoint<?>> copy = 
4168 04 Mar 08 nicklas 417       new ArrayList<ExtensionPoint<?>>(extensionPoints.values());
5599 31 Mar 11 nicklas 418     return copy;
4158 22 Feb 08 nicklas 419   }
4158 22 Feb 08 nicklas 420   
4163 28 Feb 08 nicklas 421   /**
4163 28 Feb 08 nicklas 422     Checks if an extension is registered or not.
4163 28 Feb 08 nicklas 423     @param id The ID of the extension
4163 28 Feb 08 nicklas 424     @return TRUE if an extension with the given ID is registered,
4163 28 Feb 08 nicklas 425       FALSE otherwise
4163 28 Feb 08 nicklas 426   */
4163 28 Feb 08 nicklas 427   public boolean extensionIsRegistered(String id)
4158 22 Feb 08 nicklas 428   {
4163 28 Feb 08 nicklas 429     return extensions.containsKey(id);
4163 28 Feb 08 nicklas 430   }
4163 28 Feb 08 nicklas 431   
4163 28 Feb 08 nicklas 432   /**
4618 30 Oct 08 nicklas 433     Get information about the last error that happened
4618 30 Oct 08 nicklas 434     when rendering an extension point.
4618 30 Oct 08 nicklas 435     @param id The id of the extension point
4618 30 Oct 08 nicklas 436     @return The error, or null if no error information is available
4618 30 Oct 08 nicklas 437     @since 2.9
4618 30 Oct 08 nicklas 438   */
4618 30 Oct 08 nicklas 439   public Throwable getLastExtensionPointError(String id)
4618 30 Oct 08 nicklas 440   {
4618 30 Oct 08 nicklas 441     RegisteredExtensionPoint<?> rep = extensionPoints.get(id);
4618 30 Oct 08 nicklas 442     return rep == null ? null : rep.getLastError();
4618 30 Oct 08 nicklas 443   }
6030 28 Mar 12 nicklas 444
6030 28 Mar 12 nicklas 445   /**
4163 28 Feb 08 nicklas 446     Register an extension. If the extension is already registered,
4163 28 Feb 08 nicklas 447     the description, position, action factory and renderer factory
4163 28 Feb 08 nicklas 448     is updated. The registry keeps it's own internal representation of 
4163 28 Feb 08 nicklas 449     the extension. Changes made to the object passed as a parameter to this 
4163 28 Feb 08 nicklas 450     method will not be reflected in the registry.
4163 28 Feb 08 nicklas 451     
4163 28 Feb 08 nicklas 452     @param extension The extension to register
6030 28 Mar 12 nicklas 453     @param classLoader The class loader that is responsible for loading classes
6030 28 Mar 12 nicklas 454       for the extension, or null if the default class loader should be used
4163 28 Feb 08 nicklas 455     @throws InvalidUseOfNullException If the extension is null, or if
4163 28 Feb 08 nicklas 456       the ID or action factory is null
6030 28 Mar 12 nicklas 457     @since 3.2
4163 28 Feb 08 nicklas 458   */
4163 28 Feb 08 nicklas 459   @SuppressWarnings("unchecked")
6030 28 Mar 12 nicklas 460   public synchronized <A extends Action> void registerExtension(Extension<A> extension, ClassLoader classLoader)
4163 28 Feb 08 nicklas 461   {
4163 28 Feb 08 nicklas 462     if (extension == null) 
4163 28 Feb 08 nicklas 463     {
4163 28 Feb 08 nicklas 464       throw new InvalidUseOfNullException("extension");
4163 28 Feb 08 nicklas 465     }
4198 28 Mar 08 nicklas 466     String id = extension.getId();
4198 28 Mar 08 nicklas 467     if (id == null) 
4163 28 Feb 08 nicklas 468     {
4198 28 Mar 08 nicklas 469       throw new InvalidUseOfNullException("extension.id of " + extension);
4163 28 Feb 08 nicklas 470     }
4233 17 Apr 08 nicklas 471     ActionFactory<?> actionFactory = extension.getActionFactory();
4233 17 Apr 08 nicklas 472     if (actionFactory == null) 
4163 28 Feb 08 nicklas 473     {
4233 17 Apr 08 nicklas 474       throw new InvalidUseOfNullException("Action factory for extension '" + id + "' is null.");
4163 28 Feb 08 nicklas 475     }
4163 28 Feb 08 nicklas 476
4158 22 Feb 08 nicklas 477     String extensionPointId = extension.getExtends();
4163 28 Feb 08 nicklas 478     RegisteredExtensionPoint<A> rep = 
4163 28 Feb 08 nicklas 479       (RegisteredExtensionPoint<A>)extensionPoints.get(extensionPointId);
4163 28 Feb 08 nicklas 480     if (rep == null)
4158 22 Feb 08 nicklas 481     {
4163 28 Feb 08 nicklas 482       throw new ItemNotFoundException("ExtensionPoint[id=" + extensionPointId + "]");
4158 22 Feb 08 nicklas 483     }
4163 28 Feb 08 nicklas 484     
4163 28 Feb 08 nicklas 485     RegisteredExtension<A> rext = (RegisteredExtension<A>)extensions.get(extension.getId());
4875 02 Apr 09 nicklas 486     if (rext != null && !rext.getId().equals(extensionPointId))
4875 02 Apr 09 nicklas 487     {
4875 02 Apr 09 nicklas 488       // This extension was previously registered under another extension point
4875 02 Apr 09 nicklas 489       // Unregister it and re-register it as a new extension
4875 02 Apr 09 nicklas 490       unregisterExtension(id);
4875 02 Apr 09 nicklas 491       rext = null;
4875 02 Apr 09 nicklas 492     }
4163 28 Feb 08 nicklas 493     if (rext == null)
4163 28 Feb 08 nicklas 494     {
4163 28 Feb 08 nicklas 495       // Create a new registry entry
6030 28 Mar 12 nicklas 496       rext = new RegisteredExtension<A>(extension, rep, classLoader);
4163 28 Feb 08 nicklas 497       rep.addExtension(rext);
4163 28 Feb 08 nicklas 498       extensions.put(extension.getId(), rext);
4320 29 May 08 nicklas 499       handleEvent(EventType.AFTER_REGISTRATION, rep, rext);
4163 28 Feb 08 nicklas 500     }
4163 28 Feb 08 nicklas 501     else
4163 28 Feb 08 nicklas 502     {
4163 28 Feb 08 nicklas 503       // Update the existing entry
4320 29 May 08 nicklas 504       handleEvent(EventType.BEFORE_UPDATE, rep, rext);
6030 28 Mar 12 nicklas 505       rext.update(extension, classLoader);
4320 29 May 08 nicklas 506       handleEvent(EventType.AFTER_UPDATE, rep, rext);
4163 28 Feb 08 nicklas 507     }
4158 22 Feb 08 nicklas 508   }
4158 22 Feb 08 nicklas 509   
4163 28 Feb 08 nicklas 510   /**
4163 28 Feb 08 nicklas 511     Unregister an extension. If the extension point doesn't exists,
4163 28 Feb 08 nicklas 512     nothing is done.
4163 28 Feb 08 nicklas 513     
4163 28 Feb 08 nicklas 514     @param id The ID of the extension to unregister
4163 28 Feb 08 nicklas 515     @throws InvalidUseOfNullException If the ID is null
4163 28 Feb 08 nicklas 516   */
4163 28 Feb 08 nicklas 517   public synchronized void unregisterExtension(String id)
4158 22 Feb 08 nicklas 518   {
4163 28 Feb 08 nicklas 519     if (id == null) throw new InvalidUseOfNullException("id");
4320 29 May 08 nicklas 520     RegisteredExtension<?> rext = extensions.get(id);
4163 28 Feb 08 nicklas 521     if (rext != null)
4158 22 Feb 08 nicklas 522     {
4163 28 Feb 08 nicklas 523       RegisteredExtensionPoint<?> rep = extensionPoints.get(rext.getExtends());
4320 29 May 08 nicklas 524       handleEvent(EventType.BEFORE_UNREGISTRATION, rep, rext);
4320 29 May 08 nicklas 525       extensions.remove(id);
4320 29 May 08 nicklas 526       if (rep != null) rep.removeExtension(id);
4158 22 Feb 08 nicklas 527     }
4163 28 Feb 08 nicklas 528   }
4163 28 Feb 08 nicklas 529   
4163 28 Feb 08 nicklas 530   /**
4163 28 Feb 08 nicklas 531     Get the extension with a given ID.
4163 28 Feb 08 nicklas 532     @param id The ID of the extension point
4163 28 Feb 08 nicklas 533     @return An {@link Extension} object or null if that 
4168 04 Mar 08 nicklas 534       extension doesn't exists
4163 28 Feb 08 nicklas 535   */
4163 28 Feb 08 nicklas 536   public Extension<?> getExtension(String id)
4163 28 Feb 08 nicklas 537   {
4163 28 Feb 08 nicklas 538     return extensions.get(id);
4163 28 Feb 08 nicklas 539   }
4163 28 Feb 08 nicklas 540   
4163 28 Feb 08 nicklas 541   /**
4618 30 Oct 08 nicklas 542     Get information about the last error that happened
4618 30 Oct 08 nicklas 543     when rendering an extension.
4618 30 Oct 08 nicklas 544     @param id The id of the extension
4618 30 Oct 08 nicklas 545     @return The error, or null if no error information is available
4618 30 Oct 08 nicklas 546     @since 2.9
4618 30 Oct 08 nicklas 547   */
4618 30 Oct 08 nicklas 548   public Throwable getLastExtensionError(String id)
4618 30 Oct 08 nicklas 549   {
4618 30 Oct 08 nicklas 550     RegisteredExtension<?> ext = extensions.get(id);
4618 30 Oct 08 nicklas 551     return ext == null ? null : ext.getLastError();
4618 30 Oct 08 nicklas 552   }
4618 30 Oct 08 nicklas 553
4618 30 Oct 08 nicklas 554   
4618 30 Oct 08 nicklas 555   /**
5599 31 Mar 11 nicklas 556     Get a list with all registered extensions.
5599 31 Mar 11 nicklas 557     The returned list is a copy of the registered extensions
5599 31 Mar 11 nicklas 558     at the time of this call and will not reflect changes
5599 31 Mar 11 nicklas 559     made to the registry after this call has returned.
5599 31 Mar 11 nicklas 560
5599 31 Mar 11 nicklas 561     @return A list
5599 31 Mar 11 nicklas 562     @since 3.0 (Returned an Iterator in BASE 2.x)
4163 28 Feb 08 nicklas 563   */
5599 31 Mar 11 nicklas 564   public synchronized List<Extension<?>> getExtensions()
4163 28 Feb 08 nicklas 565   {
4168 04 Mar 08 nicklas 566     List<Extension<?>> copy = 
4168 04 Mar 08 nicklas 567       new ArrayList<Extension<?>>(extensions.values());
5599 31 Mar 11 nicklas 568     return copy;
4163 28 Feb 08 nicklas 569   }
4163 28 Feb 08 nicklas 570   
4163 28 Feb 08 nicklas 571   /**
5599 31 Mar 11 nicklas 572     Get a list with all registered extensions
4207 04 Apr 08 nicklas 573     for a given extension point. If the extension point is not found
5599 31 Mar 11 nicklas 574     an empty list is returned. 
5599 31 Mar 11 nicklas 575     The returned list is a copy of the registered extension points
5599 31 Mar 11 nicklas 576     at the time of this call and will not reflect changes
5599 31 Mar 11 nicklas 577     made to the registry after this call has returned.
4163 28 Feb 08 nicklas 578     
4163 28 Feb 08 nicklas 579     @param id The ID of the extension point
5599 31 Mar 11 nicklas 580     @return A list
5599 31 Mar 11 nicklas 581     @since 3.0 (Returned an Iterator in BASE 2.x)
4163 28 Feb 08 nicklas 582   */
5599 31 Mar 11 nicklas 583   public synchronized List<Extension<?>> getExtensions(String id)
4163 28 Feb 08 nicklas 584   {
4163 28 Feb 08 nicklas 585     RegisteredExtensionPoint<?> rep = extensionPoints.get(id);
4163 28 Feb 08 nicklas 586     if (rep == null)
4163 28 Feb 08 nicklas 587     {
5599 31 Mar 11 nicklas 588       return Collections.emptyList();
4163 28 Feb 08 nicklas 589     }
4163 28 Feb 08 nicklas 590     else
4163 28 Feb 08 nicklas 591     {
4163 28 Feb 08 nicklas 592       // Create a copy, or the iterator will fail if new
4163 28 Feb 08 nicklas 593       // extension points are registered by another thread
4168 04 Mar 08 nicklas 594       List<Extension<?>> copy = 
4168 04 Mar 08 nicklas 595         new ArrayList<Extension<?>>(rep.getExtensions());
5599 31 Mar 11 nicklas 596       return copy;
4163 28 Feb 08 nicklas 597     }
4163 28 Feb 08 nicklas 598   }
4163 28 Feb 08 nicklas 599   
4163 28 Feb 08 nicklas 600   /**
4163 28 Feb 08 nicklas 601     Use extensions from one or more extension points. This method will 
4163 28 Feb 08 nicklas 602     return an invoker object that allows the use and rendering of extensions
4163 28 Feb 08 nicklas 603     for one or more extension points. The context object should have been
4163 28 Feb 08 nicklas 604     initialised with information about the currently logged in user and,
4163 28 Feb 08 nicklas 605     depending on the application, some information about what it about to 
4163 28 Feb 08 nicklas 606     happen. For example, that we are going to display a list of samples.
4170 07 Mar 08 nicklas 607     
4163 28 Feb 08 nicklas 608     <p>
4163 28 Feb 08 nicklas 609     Each extension that has been registered with the extension points will
4163 28 Feb 08 nicklas 610     get a chance to check the context object and to further initialise it
4163 28 Feb 08 nicklas 611     with extension-dependent information. This is a task for the 
4207 04 Apr 08 nicklas 612     {@link ActionFactory#prepareContext(InvokationContext)} method. If this method 
4170 07 Mar 08 nicklas 613     returns false the extension will not be included in the invoker. Extensions
4163 28 Feb 08 nicklas 614     may for example use this to check if the logged in user has enough permissions
4163 28 Feb 08 nicklas 615     to be able to use the extension.
4163 28 Feb 08 nicklas 616     
4163 28 Feb 08 nicklas 617     <p>
4170 07 Mar 08 nicklas 618     If the extension points and/or extensions also provide renderer factories,
4207 04 Apr 08 nicklas 619     the {@link RendererFactory#prepareContext(InvokationContext)} is called.
4170 07 Mar 08 nicklas 620     For renderer factories that are attached to extension points the method
4170 07 Mar 08 nicklas 621     is only called if at least one enabled extension exists. If the method is
4170 07 Mar 08 nicklas 622     called, it is only called once with a null argument for the extension.
4170 07 Mar 08 nicklas 623     Renderer factories that are attached to extensions are called once for each
4198 28 Mar 08 nicklas 624     enabled extension, but only if the extension point allows renderer overriding.
4170 07 Mar 08 nicklas 625     See {@link ExtensionPoint#allowRendererOverride()}.
4170 07 Mar 08 nicklas 626     
4170 07 Mar 08 nicklas 627     <p>
4163 28 Feb 08 nicklas 628     The returned invoker will not reflect changes made to the registry by the 
4163 28 Feb 08 nicklas 629     same or other threads after this call has returned. Each use/invokation of
4163 28 Feb 08 nicklas 630     an extension point should call this method to get a new invoker object.
4163 28 Feb 08 nicklas 631     
4207 04 Apr 08 nicklas 632     @param clientContext Information about the current context
4170 07 Mar 08 nicklas 633      @param filter A filter object that can be used to filter out
4168 04 Mar 08 nicklas 634       disabled extensions and sort the extensions in a particular order.
4168 04 Mar 08 nicklas 635       If this value is null, no extensions are filtered out and they 
4168 04 Mar 08 nicklas 636       are sorted according to their {@link Extension#getIndex()} value
4198 28 Mar 08 nicklas 637      @param extensionPointIds An array of extension point ID:s to get
4163 28 Feb 08 nicklas 638       extension for. In most cases the extension points should
4163 28 Feb 08 nicklas 639       require the same action class but this is not required
4163 28 Feb 08 nicklas 640       if the extension point renderer can handle more than one action
4163 28 Feb 08 nicklas 641       type. Extension points that are not found are ignored.
4163 28 Feb 08 nicklas 642   */
6875 20 Apr 15 nicklas 643   @SuppressWarnings({ "unchecked", "rawtypes" })
7605 26 Feb 19 nicklas 644   public <A extends Action> ExtensionsInvoker<A> useExtensions(ClientContext clientContext, ExtensionsFilter filter, 
4198 28 Mar 08 nicklas 645     String... extensionPointIds)
4163 28 Feb 08 nicklas 646   {
4168 04 Mar 08 nicklas 647     if (filter == null) filter = DEFAULT_FILTER;
4207 04 Apr 08 nicklas 648
7605 26 Feb 19 nicklas 649     List<ExtensionContext<A>> contexts = new LinkedList<ExtensionContext<A>>();
4198 28 Mar 08 nicklas 650     for (String id : extensionPointIds)
4163 28 Feb 08 nicklas 651     {
5014 25 Jun 09 martin 652       if (id == null)
5014 25 Jun 09 martin 653       {
5014 25 Jun 09 martin 654         /* #### CONTINUE-STATEMENT #### */
5014 25 Jun 09 martin 655         continue;
5014 25 Jun 09 martin 656       }
4870 01 Apr 09 nicklas 657       
4198 28 Mar 08 nicklas 658       // Find a registered extension point for each ID
4168 04 Mar 08 nicklas 659       RegisteredExtensionPoint<Action> rep = 
4198 28 Mar 08 nicklas 660         (RegisteredExtensionPoint<Action>)extensionPoints.get(id);
4207 04 Apr 08 nicklas 661       
4207 04 Apr 08 nicklas 662       // Is there an enabled extension point?
5014 25 Jun 09 martin 663       if (rep == null || !filter.isEnabled(rep))
5014 25 Jun 09 martin 664       {
5482 10 Nov 10 nicklas 665         if (rep == null)
5482 10 Nov 10 nicklas 666         {
5482 10 Nov 10 nicklas 667           // Trying to use an unedefined extension point should log a warning
5482 10 Nov 10 nicklas 668           log.warn("Undefined extension point: " + id, new RuntimeException());
5482 10 Nov 10 nicklas 669         }
5014 25 Jun 09 martin 670         /* #### CONTINUE-STATEMENT #### */
5014 25 Jun 09 martin 671         continue;
5014 25 Jun 09 martin 672       }
4207 04 Apr 08 nicklas 673
4207 04 Apr 08 nicklas 674       // YES! ...
8045 03 Jun 22 nicklas 675       if (clientContext != null) clientContext.setCurrentExtensionPoint(rep);
5486 12 Nov 10 nicklas 676       ErrorHandlerFactory ehf = rep.getErrorHandlerFactory();
5486 12 Nov 10 nicklas 677       ExtensionPointContext<Action> mainContext = new ExtensionPointContext<Action>(this, 
5487 15 Nov 10 nicklas 678           clientContext, rep, ehf == null ? defaultErrorHandlerFactory : ehf);
4207 04 Apr 08 nicklas 679       boolean allowRenderOverride = rep.allowRendererOverride();
4207 04 Apr 08 nicklas 680       int enabledExtensions = 0;
4207 04 Apr 08 nicklas 681       
4207 04 Apr 08 nicklas 682       // ... find the extensions for it
4207 04 Apr 08 nicklas 683       for (RegisteredExtension<Action> ext : rep.getExtensions())
4163 28 Feb 08 nicklas 684       {
4207 04 Apr 08 nicklas 685         // Check with the filter if the extension is enabled
5014 25 Jun 09 martin 686         if (!filter.isEnabled(ext))
5014 25 Jun 09 martin 687         {
5014 25 Jun 09 martin 688           /* #### CONTINUE-STATEMENT #### */
5014 25 Jun 09 martin 689           continue;
5014 25 Jun 09 martin 690         }
4207 04 Apr 08 nicklas 691
4207 04 Apr 08 nicklas 692         // Create invokation context for the extension
8045 03 Jun 22 nicklas 693         if (clientContext != null) clientContext.setCurrentExtension(ext);
7605 26 Feb 19 nicklas 694         ExtensionContext<A> context = 
7605 26 Feb 19 nicklas 695           new ExtensionContext(mainContext, ext);
4207 04 Apr 08 nicklas 696         
4207 04 Apr 08 nicklas 697         // Check with the action factory as well
5014 25 Jun 09 martin 698         if (!context.prepareActionFactory()) 
5014 25 Jun 09 martin 699         {
5014 25 Jun 09 martin 700           /* #### CONTINUE-STATEMENT #### */
5014 25 Jun 09 martin 701           continue;
5014 25 Jun 09 martin 702         }
4207 04 Apr 08 nicklas 703
4207 04 Apr 08 nicklas 704         // Yippi, this extension is enabled!!!
4207 04 Apr 08 nicklas 705         if (allowRenderOverride) context.prepareRendererFactory();
4207 04 Apr 08 nicklas 706         contexts.add(context);
4207 04 Apr 08 nicklas 707         enabledExtensions++;
4163 28 Feb 08 nicklas 708       }
4207 04 Apr 08 nicklas 709       
4207 04 Apr 08 nicklas 710       // Prepare the renderer factory for the extension point
4207 04 Apr 08 nicklas 711       // if there is at least one enabled extension
4207 04 Apr 08 nicklas 712       if (enabledExtensions > 0) mainContext.prepareRendererFactory();
4163 28 Feb 08 nicklas 713     }
4207 04 Apr 08 nicklas 714     
4198 28 Mar 08 nicklas 715     // Sort the extensions
4207 04 Apr 08 nicklas 716     filter.sort(contexts);
8083 20 Oct 22 nicklas 717     return new ExtensionsInvoker<A>(clientContext, contexts);
4163 28 Feb 08 nicklas 718   }
4163 28 Feb 08 nicklas 719   
4163 28 Feb 08 nicklas 720   /**
4168 04 Mar 08 nicklas 721     Default filter implementation for 
4207 04 Apr 08 nicklas 722     {@link #useExtensions(ClientContext, ExtensionsFilter, String...)}
4168 04 Mar 08 nicklas 723   */
4168 04 Mar 08 nicklas 724   private static final ExtensionsFilter DEFAULT_FILTER = new DefaultFilter();
4202 01 Apr 08 nicklas 725   
4163 28 Feb 08 nicklas 726   /**
4163 28 Feb 08 nicklas 727     Internal representation of an extension point.
4163 28 Feb 08 nicklas 728   */
4163 28 Feb 08 nicklas 729   static class RegisteredExtensionPoint<A extends Action>
4163 28 Feb 08 nicklas 730     implements ExtensionPoint<A>
4163 28 Feb 08 nicklas 731   {
4158 22 Feb 08 nicklas 732
4163 28 Feb 08 nicklas 733     private final String id;
7225 14 Nov 16 nicklas 734     private Class<A> actionClass;
4198 28 Mar 08 nicklas 735     private final Map<String, RegisteredExtension<A>> extensions;
4198 28 Mar 08 nicklas 736
4168 04 Mar 08 nicklas 737     private String name;
4163 28 Feb 08 nicklas 738     private String description;
4170 07 Mar 08 nicklas 739     private RendererFactory<? super A> rendererFactory;
4163 28 Feb 08 nicklas 740     private boolean allowRendererOverride;
5486 12 Nov 10 nicklas 741     private ErrorHandlerFactory<? super A> errorHandlerFactory;
6030 28 Mar 12 nicklas 742     private ClassLoader classLoader;
4163 28 Feb 08 nicklas 743     
4618 30 Oct 08 nicklas 744     private Throwable lastError;
4618 30 Oct 08 nicklas 745     private A lastErrorAction;
4618 30 Oct 08 nicklas 746     
4163 28 Feb 08 nicklas 747     /**
4163 28 Feb 08 nicklas 748       Create a new registered extension point by copying the
4163 28 Feb 08 nicklas 749       information from the parameter.
4163 28 Feb 08 nicklas 750     */
6030 28 Mar 12 nicklas 751     RegisteredExtensionPoint(ExtensionPoint<A> ep, ClassLoader classLoader)
4163 28 Feb 08 nicklas 752     {
4163 28 Feb 08 nicklas 753       this.id = ep.getId();
4163 28 Feb 08 nicklas 754       this.extensions = new HashMap<String, RegisteredExtension<A>>();
6030 28 Mar 12 nicklas 755       update(ep, classLoader);
4163 28 Feb 08 nicklas 756     }
4163 28 Feb 08 nicklas 757     
4163 28 Feb 08 nicklas 758     /*
4163 28 Feb 08 nicklas 759       From the ExtensionPoint interface
4163 28 Feb 08 nicklas 760       ---------------------------------
4163 28 Feb 08 nicklas 761     */
4163 28 Feb 08 nicklas 762     @Override
4163 28 Feb 08 nicklas 763     public String getId() 
4163 28 Feb 08 nicklas 764     {
4163 28 Feb 08 nicklas 765       return id;
4163 28 Feb 08 nicklas 766     }    
4163 28 Feb 08 nicklas 767
4163 28 Feb 08 nicklas 768     @Override
4168 04 Mar 08 nicklas 769     public String getName() 
4168 04 Mar 08 nicklas 770     {
4168 04 Mar 08 nicklas 771       return name;
4168 04 Mar 08 nicklas 772     }
4168 04 Mar 08 nicklas 773
4168 04 Mar 08 nicklas 774     @Override
4163 28 Feb 08 nicklas 775     public String getDescription() 
4163 28 Feb 08 nicklas 776     {
4163 28 Feb 08 nicklas 777       return description;
4163 28 Feb 08 nicklas 778     }
4163 28 Feb 08 nicklas 779       
4163 28 Feb 08 nicklas 780     @Override
4163 28 Feb 08 nicklas 781     public Class<A> getActionClass()
4163 28 Feb 08 nicklas 782     {
4163 28 Feb 08 nicklas 783       return actionClass;
4163 28 Feb 08 nicklas 784     }
4163 28 Feb 08 nicklas 785     
4163 28 Feb 08 nicklas 786     @Override
4170 07 Mar 08 nicklas 787     public RendererFactory<? super A> getRendererFactory()
4163 28 Feb 08 nicklas 788     {
4163 28 Feb 08 nicklas 789       return rendererFactory;
4163 28 Feb 08 nicklas 790     }
4163 28 Feb 08 nicklas 791     
4163 28 Feb 08 nicklas 792     @Override
4163 28 Feb 08 nicklas 793     public boolean allowRendererOverride() 
4163 28 Feb 08 nicklas 794     {
4163 28 Feb 08 nicklas 795       return allowRendererOverride;
4163 28 Feb 08 nicklas 796     }
5486 12 Nov 10 nicklas 797     
5486 12 Nov 10 nicklas 798     @Override
5486 12 Nov 10 nicklas 799     public ErrorHandlerFactory<? super A> getErrorHandlerFactory()
5486 12 Nov 10 nicklas 800     {
5486 12 Nov 10 nicklas 801       return errorHandlerFactory;
5486 12 Nov 10 nicklas 802     }    
4163 28 Feb 08 nicklas 803     // ---------------------------------
4163 28 Feb 08 nicklas 804     
4163 28 Feb 08 nicklas 805     @Override
4163 28 Feb 08 nicklas 806     public String toString()
4163 28 Feb 08 nicklas 807     {
4168 04 Mar 08 nicklas 808       return "ExtensionPoint[id="+ id +"; name=" + name + "]";
4163 28 Feb 08 nicklas 809     }
4163 28 Feb 08 nicklas 810     
4163 28 Feb 08 nicklas 811     /**
4163 28 Feb 08 nicklas 812       Update the registered information.
4163 28 Feb 08 nicklas 813     */
6030 28 Mar 12 nicklas 814     void update(ExtensionPoint<A> ep, ClassLoader classLoader)
4163 28 Feb 08 nicklas 815     {
7224 14 Nov 16 nicklas 816       if (log.isDebugEnabled())
7224 14 Nov 16 nicklas 817       {
7224 14 Nov 16 nicklas 818         log.debug("Update registry: " + ep + 
7224 14 Nov 16 nicklas 819           "; old classloader="+this.classLoader + "; new classLoader="+classLoader);
7224 14 Nov 16 nicklas 820       }
7225 14 Nov 16 nicklas 821       this.actionClass = ep.getActionClass();
6030 28 Mar 12 nicklas 822       this.classLoader = classLoader;
4168 04 Mar 08 nicklas 823       this.name = ep.getName();
4163 28 Feb 08 nicklas 824       this.description = ep.getDescription();
4163 28 Feb 08 nicklas 825       this.rendererFactory = ep.getRendererFactory();
4163 28 Feb 08 nicklas 826       this.allowRendererOverride = ep.allowRendererOverride();
5486 12 Nov 10 nicklas 827       this.errorHandlerFactory = ep.getErrorHandlerFactory();
4163 28 Feb 08 nicklas 828     }
4163 28 Feb 08 nicklas 829     
4163 28 Feb 08 nicklas 830     /**
4163 28 Feb 08 nicklas 831        Add an extension to this extension point.
4163 28 Feb 08 nicklas 832     */
4163 28 Feb 08 nicklas 833     void addExtension(RegisteredExtension<A> extension)
4163 28 Feb 08 nicklas 834     {
4163 28 Feb 08 nicklas 835       this.extensions.put(extension.getId(), extension);
4163 28 Feb 08 nicklas 836     }
4163 28 Feb 08 nicklas 837     
4163 28 Feb 08 nicklas 838     /**
4163 28 Feb 08 nicklas 839       Remove the extension with a given ID.
4163 28 Feb 08 nicklas 840     */
4163 28 Feb 08 nicklas 841     void removeExtension(String id)
4163 28 Feb 08 nicklas 842     {
4163 28 Feb 08 nicklas 843       this.extensions.remove(id);
4163 28 Feb 08 nicklas 844     }
4163 28 Feb 08 nicklas 845     
4163 28 Feb 08 nicklas 846     /**
4163 28 Feb 08 nicklas 847       Get all extensions registered with this extension point.
4163 28 Feb 08 nicklas 848     */
4163 28 Feb 08 nicklas 849     Collection<RegisteredExtension<A>> getExtensions()
4163 28 Feb 08 nicklas 850     {
4163 28 Feb 08 nicklas 851       return this.extensions.values();
4618 30 Oct 08 nicklas 852     }
4618 30 Oct 08 nicklas 853     
6030 28 Mar 12 nicklas 854     /**
6030 28 Mar 12 nicklas 855       @since 3.2
6030 28 Mar 12 nicklas 856     */
6030 28 Mar 12 nicklas 857     ClassLoader getClassLoader()
6030 28 Mar 12 nicklas 858     {
6030 28 Mar 12 nicklas 859       return classLoader;
6030 28 Mar 12 nicklas 860     }
6030 28 Mar 12 nicklas 861     
4618 30 Oct 08 nicklas 862     synchronized void setError(A action, Throwable t)
4618 30 Oct 08 nicklas 863     {
4618 30 Oct 08 nicklas 864       this.lastErrorAction = action;
4618 30 Oct 08 nicklas 865       this.lastError = t;
4618 30 Oct 08 nicklas 866     }
4618 30 Oct 08 nicklas 867     
4618 30 Oct 08 nicklas 868     synchronized void clearError()
4618 30 Oct 08 nicklas 869     {
4618 30 Oct 08 nicklas 870       this.lastError = null;
4618 30 Oct 08 nicklas 871       this.lastErrorAction = null;
4618 30 Oct 08 nicklas 872     }
4618 30 Oct 08 nicklas 873     
4618 30 Oct 08 nicklas 874     Throwable getLastError()
4618 30 Oct 08 nicklas 875     {
4618 30 Oct 08 nicklas 876       return lastError;
4618 30 Oct 08 nicklas 877     }
4158 22 Feb 08 nicklas 878   }
4168 04 Mar 08 nicklas 879     
4163 28 Feb 08 nicklas 880   /**
4163 28 Feb 08 nicklas 881     Internal representation of an extension.
4163 28 Feb 08 nicklas 882   */
4163 28 Feb 08 nicklas 883   static class RegisteredExtension<A extends Action>
4163 28 Feb 08 nicklas 884     implements Extension<A>
4163 28 Feb 08 nicklas 885   {
4163 28 Feb 08 nicklas 886
4170 07 Mar 08 nicklas 887     private final RegisteredExtensionPoint<? super A> rep;
4163 28 Feb 08 nicklas 888     private final String id;
4163 28 Feb 08 nicklas 889     private final String extensionPoint;
4163 28 Feb 08 nicklas 890     private RegisteredAbout about;
4163 28 Feb 08 nicklas 891     private float index;
4170 07 Mar 08 nicklas 892     private ActionFactory<? extends A> actionFactory;
4170 07 Mar 08 nicklas 893     private RendererFactory<? super A> rendererFactory;
6030 28 Mar 12 nicklas 894     private ClassLoader classLoader;
4163 28 Feb 08 nicklas 895
4618 30 Oct 08 nicklas 896     private Throwable lastError;
4618 30 Oct 08 nicklas 897     private A lastErrorAction;
4618 30 Oct 08 nicklas 898     
4163 28 Feb 08 nicklas 899     /**
4163 28 Feb 08 nicklas 900       Create a new registered extension by copying the
4163 28 Feb 08 nicklas 901       information from the parameter.
4163 28 Feb 08 nicklas 902     */
6030 28 Mar 12 nicklas 903     RegisteredExtension(Extension<A> extension, RegisteredExtensionPoint<? super A> rep, ClassLoader classLoader)
4163 28 Feb 08 nicklas 904     {
4163 28 Feb 08 nicklas 905       this.rep = rep;
4163 28 Feb 08 nicklas 906       this.id = extension.getId();
4163 28 Feb 08 nicklas 907       this.extensionPoint = extension.getExtends();
6030 28 Mar 12 nicklas 908       update(extension, classLoader);
4163 28 Feb 08 nicklas 909     }
4163 28 Feb 08 nicklas 910
4163 28 Feb 08 nicklas 911     /*
4163 28 Feb 08 nicklas 912       From the Extension interface
4163 28 Feb 08 nicklas 913       ---------------------------------
4163 28 Feb 08 nicklas 914     */
4163 28 Feb 08 nicklas 915     @Override
4163 28 Feb 08 nicklas 916     public String getId() 
4163 28 Feb 08 nicklas 917     {
4163 28 Feb 08 nicklas 918       return id;
4163 28 Feb 08 nicklas 919     }
4163 28 Feb 08 nicklas 920
4163 28 Feb 08 nicklas 921     @Override
4163 28 Feb 08 nicklas 922     public String getExtends() 
4163 28 Feb 08 nicklas 923     {
4163 28 Feb 08 nicklas 924       return extensionPoint;
4163 28 Feb 08 nicklas 925     }
4163 28 Feb 08 nicklas 926     
4163 28 Feb 08 nicklas 927     @Override
4163 28 Feb 08 nicklas 928     public float getIndex() 
4163 28 Feb 08 nicklas 929     {
4163 28 Feb 08 nicklas 930       return index;
4163 28 Feb 08 nicklas 931     }
4163 28 Feb 08 nicklas 932
4163 28 Feb 08 nicklas 933     @Override
4170 07 Mar 08 nicklas 934     public ActionFactory<? extends A> getActionFactory() 
4163 28 Feb 08 nicklas 935     {
4163 28 Feb 08 nicklas 936       return actionFactory;
4163 28 Feb 08 nicklas 937     }
4163 28 Feb 08 nicklas 938     
4163 28 Feb 08 nicklas 939     @Override
4170 07 Mar 08 nicklas 940     public RendererFactory<? super A> getRendererFactory() 
4163 28 Feb 08 nicklas 941     {
4163 28 Feb 08 nicklas 942       return rendererFactory;
4163 28 Feb 08 nicklas 943     }
4163 28 Feb 08 nicklas 944
4163 28 Feb 08 nicklas 945     @Override
4163 28 Feb 08 nicklas 946     public About getAbout() 
4163 28 Feb 08 nicklas 947     {
4163 28 Feb 08 nicklas 948       return about;
4163 28 Feb 08 nicklas 949     }
4163 28 Feb 08 nicklas 950     // ---------------------------------
4163 28 Feb 08 nicklas 951
4163 28 Feb 08 nicklas 952     @Override
4163 28 Feb 08 nicklas 953     public String toString()
4163 28 Feb 08 nicklas 954     {
4163 28 Feb 08 nicklas 955       return "Extension[id="+ id +"]";
4163 28 Feb 08 nicklas 956     }
4168 04 Mar 08 nicklas 957     
4163 28 Feb 08 nicklas 958     /**
4163 28 Feb 08 nicklas 959       Update the registered information.
4163 28 Feb 08 nicklas 960     */
6030 28 Mar 12 nicklas 961     void update(Extension<A> extension, ClassLoader classLoader)
4163 28 Feb 08 nicklas 962     {
7224 14 Nov 16 nicklas 963       if (log.isDebugEnabled())
7224 14 Nov 16 nicklas 964       {
7224 14 Nov 16 nicklas 965         log.debug("Update registry: " + extension + 
7224 14 Nov 16 nicklas 966           "; old classloader="+this.classLoader + "; new classLoader="+classLoader);
7224 14 Nov 16 nicklas 967       }
6030 28 Mar 12 nicklas 968       this.classLoader = classLoader;
4163 28 Feb 08 nicklas 969       this.index = extension.getIndex();
4163 28 Feb 08 nicklas 970       this.actionFactory = extension.getActionFactory();
4163 28 Feb 08 nicklas 971       this.rendererFactory = extension.getRendererFactory();
4163 28 Feb 08 nicklas 972       if (extension.getAbout() == null)
4163 28 Feb 08 nicklas 973       {
4163 28 Feb 08 nicklas 974         this.about = null;
4163 28 Feb 08 nicklas 975       }
4163 28 Feb 08 nicklas 976       else
4163 28 Feb 08 nicklas 977       {
4163 28 Feb 08 nicklas 978         if (this.about == null)
4163 28 Feb 08 nicklas 979         {
4163 28 Feb 08 nicklas 980           this.about = new RegisteredAbout(extension.getAbout());
4163 28 Feb 08 nicklas 981         }
4163 28 Feb 08 nicklas 982         else
4163 28 Feb 08 nicklas 983         {
4163 28 Feb 08 nicklas 984           this.about.update(extension.getAbout());
4163 28 Feb 08 nicklas 985         }
4163 28 Feb 08 nicklas 986       }
4163 28 Feb 08 nicklas 987     }
4163 28 Feb 08 nicklas 988     
4163 28 Feb 08 nicklas 989     /**
4163 28 Feb 08 nicklas 990       Get the extension point this extension is registered with.
4163 28 Feb 08 nicklas 991     */
4170 07 Mar 08 nicklas 992     RegisteredExtensionPoint<? super A> getExtensionPoint()
4163 28 Feb 08 nicklas 993     {
4163 28 Feb 08 nicklas 994       return rep;
4163 28 Feb 08 nicklas 995     }
4618 30 Oct 08 nicklas 996
6030 28 Mar 12 nicklas 997     /**
6030 28 Mar 12 nicklas 998       @since 3.2
6030 28 Mar 12 nicklas 999     */
6030 28 Mar 12 nicklas 1000     ClassLoader getClassLoader()
6030 28 Mar 12 nicklas 1001     {
6030 28 Mar 12 nicklas 1002       return classLoader;
6030 28 Mar 12 nicklas 1003     }
6030 28 Mar 12 nicklas 1004     
4618 30 Oct 08 nicklas 1005     synchronized void setError(A action, Throwable t)
4618 30 Oct 08 nicklas 1006     {
4618 30 Oct 08 nicklas 1007       this.lastErrorAction = action;
4618 30 Oct 08 nicklas 1008       this.lastError = t;
4618 30 Oct 08 nicklas 1009     }
4618 30 Oct 08 nicklas 1010     
4618 30 Oct 08 nicklas 1011     synchronized void clearError()
4618 30 Oct 08 nicklas 1012     {
4618 30 Oct 08 nicklas 1013       this.lastError = null;
4618 30 Oct 08 nicklas 1014       this.lastErrorAction = null;
4618 30 Oct 08 nicklas 1015     }
4618 30 Oct 08 nicklas 1016     
4618 30 Oct 08 nicklas 1017     Throwable getLastError()
4618 30 Oct 08 nicklas 1018     {
4618 30 Oct 08 nicklas 1019       return lastError;
4618 30 Oct 08 nicklas 1020     }
4168 04 Mar 08 nicklas 1021   }    
4168 04 Mar 08 nicklas 1022     
4163 28 Feb 08 nicklas 1023   static class RegisteredAbout
6497 26 Jun 14 nicklas 1024     implements About, ExtendedAbout
4163 28 Feb 08 nicklas 1025   {
4163 28 Feb 08 nicklas 1026
4163 28 Feb 08 nicklas 1027     private String name;
4163 28 Feb 08 nicklas 1028     private String description;
4163 28 Feb 08 nicklas 1029     private String version;
5607 15 Apr 11 nicklas 1030     private String minBaseVersion;
5607 15 Apr 11 nicklas 1031     private String maxBaseVersion;
4163 28 Feb 08 nicklas 1032     private String copyright;
4163 28 Feb 08 nicklas 1033     private String contact;
4163 28 Feb 08 nicklas 1034     private String email;
4163 28 Feb 08 nicklas 1035     private String url;
6497 26 Jun 14 nicklas 1036     private Map<String, String> attributes;
4163 28 Feb 08 nicklas 1037     
4163 28 Feb 08 nicklas 1038     /**
4163 28 Feb 08 nicklas 1039       Create a new registered about by copying the
4163 28 Feb 08 nicklas 1040       information from the parameter.
4163 28 Feb 08 nicklas 1041     */
4163 28 Feb 08 nicklas 1042     RegisteredAbout(About about)
4163 28 Feb 08 nicklas 1043     {
4163 28 Feb 08 nicklas 1044       update(about);
4163 28 Feb 08 nicklas 1045     }
4163 28 Feb 08 nicklas 1046     
4163 28 Feb 08 nicklas 1047     /*
4163 28 Feb 08 nicklas 1048       From the About interface
4163 28 Feb 08 nicklas 1049       ---------------------------------
4163 28 Feb 08 nicklas 1050     */
4163 28 Feb 08 nicklas 1051     @Override
4163 28 Feb 08 nicklas 1052     public String getContact()
4163 28 Feb 08 nicklas 1053     {
4163 28 Feb 08 nicklas 1054       return contact;
4163 28 Feb 08 nicklas 1055     }
4163 28 Feb 08 nicklas 1056     
4163 28 Feb 08 nicklas 1057     @Override
4163 28 Feb 08 nicklas 1058     public String getCopyright() 
4163 28 Feb 08 nicklas 1059     {
4163 28 Feb 08 nicklas 1060       return copyright;
4163 28 Feb 08 nicklas 1061     }
4163 28 Feb 08 nicklas 1062     
4163 28 Feb 08 nicklas 1063     @Override
4163 28 Feb 08 nicklas 1064     public String getDescription() 
4163 28 Feb 08 nicklas 1065     {
4163 28 Feb 08 nicklas 1066       return description;
4163 28 Feb 08 nicklas 1067     }
4163 28 Feb 08 nicklas 1068     
4163 28 Feb 08 nicklas 1069     @Override
4163 28 Feb 08 nicklas 1070     public String getEmail() 
4163 28 Feb 08 nicklas 1071     {
4163 28 Feb 08 nicklas 1072       return email;
4163 28 Feb 08 nicklas 1073     }
4163 28 Feb 08 nicklas 1074
4163 28 Feb 08 nicklas 1075     @Override
4163 28 Feb 08 nicklas 1076     public String getName() 
4163 28 Feb 08 nicklas 1077     {
4163 28 Feb 08 nicklas 1078       return name;
4163 28 Feb 08 nicklas 1079     }
4163 28 Feb 08 nicklas 1080
4163 28 Feb 08 nicklas 1081     @Override
4163 28 Feb 08 nicklas 1082     public String getUrl() 
4163 28 Feb 08 nicklas 1083     {
4163 28 Feb 08 nicklas 1084       return url;
4163 28 Feb 08 nicklas 1085     }
4163 28 Feb 08 nicklas 1086
4163 28 Feb 08 nicklas 1087     @Override
4163 28 Feb 08 nicklas 1088     public String getVersion() 
4163 28 Feb 08 nicklas 1089     {
4163 28 Feb 08 nicklas 1090       return version;
4163 28 Feb 08 nicklas 1091     }
5607 15 Apr 11 nicklas 1092     
5607 15 Apr 11 nicklas 1093     @Override
5607 15 Apr 11 nicklas 1094     public String getMinBaseVersion() 
5607 15 Apr 11 nicklas 1095     {
5607 15 Apr 11 nicklas 1096       return minBaseVersion;
5607 15 Apr 11 nicklas 1097     }
5607 15 Apr 11 nicklas 1098
5607 15 Apr 11 nicklas 1099     @Override
5607 15 Apr 11 nicklas 1100     public String getMaxBaseVersion() 
5607 15 Apr 11 nicklas 1101     {
5607 15 Apr 11 nicklas 1102       return maxBaseVersion;
5607 15 Apr 11 nicklas 1103     }
6497 26 Jun 14 nicklas 1104     
6497 26 Jun 14 nicklas 1105     @Override
6497 26 Jun 14 nicklas 1106     public String getAttribute(String name)
6497 26 Jun 14 nicklas 1107     {
6497 26 Jun 14 nicklas 1108       return attributes == null ? null : attributes.get(name);
6497 26 Jun 14 nicklas 1109     }
6497 26 Jun 14 nicklas 1110     
6497 26 Jun 14 nicklas 1111     @Override
6497 26 Jun 14 nicklas 1112     public Collection<String> getAttributeNames() 
6497 26 Jun 14 nicklas 1113     {
6497 26 Jun 14 nicklas 1114       return attributes == null ? null : attributes.keySet();
6497 26 Jun 14 nicklas 1115     }
4163 28 Feb 08 nicklas 1116     // ---------------------------------
4163 28 Feb 08 nicklas 1117
4163 28 Feb 08 nicklas 1118     /**
4163 28 Feb 08 nicklas 1119       Update the registered information.
4163 28 Feb 08 nicklas 1120     */
4163 28 Feb 08 nicklas 1121     void update(About about)
4163 28 Feb 08 nicklas 1122     {
4163 28 Feb 08 nicklas 1123       this.name = about.getName();
4163 28 Feb 08 nicklas 1124       this.description = about.getDescription();
4163 28 Feb 08 nicklas 1125       this.version = about.getVersion();
5607 15 Apr 11 nicklas 1126       this.minBaseVersion = about.getMinBaseVersion();
5607 15 Apr 11 nicklas 1127       this.maxBaseVersion = about.getMaxBaseVersion();
4163 28 Feb 08 nicklas 1128       this.contact = about.getContact();
4163 28 Feb 08 nicklas 1129       this.copyright = about.getCopyright();
4163 28 Feb 08 nicklas 1130       this.email = about.getEmail();
4163 28 Feb 08 nicklas 1131       this.url = about.getUrl();
6497 26 Jun 14 nicklas 1132       if (about instanceof ExtendedAbout)
6497 26 Jun 14 nicklas 1133       {
6497 26 Jun 14 nicklas 1134         ExtendedAbout xtAbout = (ExtendedAbout)about;
6497 26 Jun 14 nicklas 1135         Collection<String> names = xtAbout.getAttributeNames();
6497 26 Jun 14 nicklas 1136         if (names != null)
6497 26 Jun 14 nicklas 1137         {
6497 26 Jun 14 nicklas 1138           this.attributes = new HashMap<String, String>();
6497 26 Jun 14 nicklas 1139           for (String name : names)
6497 26 Jun 14 nicklas 1140           {
6497 26 Jun 14 nicklas 1141             attributes.put(name, xtAbout.getAttribute(name));
6497 26 Jun 14 nicklas 1142           }
6497 26 Jun 14 nicklas 1143         }
6497 26 Jun 14 nicklas 1144       }
6497 26 Jun 14 nicklas 1145       else
6497 26 Jun 14 nicklas 1146       {
6497 26 Jun 14 nicklas 1147         this.attributes = null;
6497 26 Jun 14 nicklas 1148       }
4163 28 Feb 08 nicklas 1149     }
4163 28 Feb 08 nicklas 1150   }
4163 28 Feb 08 nicklas 1151   
4208 07 Apr 08 nicklas 1152   /**
4208 07 Apr 08 nicklas 1153     Identifies attribute. The key is: 
4208 07 Apr 08 nicklas 1154     <code>
4208 07 Apr 08 nicklas 1155     id of extension + name of attribute
4208 07 Apr 08 nicklas 1156     </code>
4208 07 Apr 08 nicklas 1157   
4208 07 Apr 08 nicklas 1158     @author nicklas
4208 07 Apr 08 nicklas 1159     @version 2.7
4208 07 Apr 08 nicklas 1160     @base.modified $Date$
4208 07 Apr 08 nicklas 1161    */
4198 28 Mar 08 nicklas 1162   static class AttributeKey
4198 28 Mar 08 nicklas 1163   {
4208 07 Apr 08 nicklas 1164     private final String id;
4198 28 Mar 08 nicklas 1165     private final String name;
4208 07 Apr 08 nicklas 1166     AttributeKey(String id, String name)
4198 28 Mar 08 nicklas 1167     {
4208 07 Apr 08 nicklas 1168       this.id = id;
4198 28 Mar 08 nicklas 1169       this.name = name;
4198 28 Mar 08 nicklas 1170     }
4198 28 Mar 08 nicklas 1171     
4198 28 Mar 08 nicklas 1172     @Override
4198 28 Mar 08 nicklas 1173     public int hashCode()
4198 28 Mar 08 nicklas 1174     {
4208 07 Apr 08 nicklas 1175       return 13 * id.hashCode() + 5 * name.hashCode();
4198 28 Mar 08 nicklas 1176     }
4198 28 Mar 08 nicklas 1177     
4198 28 Mar 08 nicklas 1178     @Override
4198 28 Mar 08 nicklas 1179     public boolean equals(Object other)
4198 28 Mar 08 nicklas 1180     {
4198 28 Mar 08 nicklas 1181       if (this == other) return true;
4198 28 Mar 08 nicklas 1182       if (other == null || other.getClass() != this.getClass()) return false;
4198 28 Mar 08 nicklas 1183       AttributeKey ak = (AttributeKey)other;
4208 07 Apr 08 nicklas 1184       return this.id.equals(ak.id) && this.name.equals(ak.name);
4198 28 Mar 08 nicklas 1185     }
4198 28 Mar 08 nicklas 1186     
4198 28 Mar 08 nicklas 1187   }
4198 28 Mar 08 nicklas 1188   
7273 20 Jan 17 nicklas 1189   static class RegisteredEventHandler
7273 20 Jan 17 nicklas 1190   {
7273 20 Jan 17 nicklas 1191     final EventHandler handler;
7273 20 Jan 17 nicklas 1192     final EventFilter filter;
7273 20 Jan 17 nicklas 1193     final ClassLoader loader;
7273 20 Jan 17 nicklas 1194     
7273 20 Jan 17 nicklas 1195     RegisteredEventHandler(EventHandler handler, EventFilter filter, ClassLoader loader) 
7273 20 Jan 17 nicklas 1196     {
7273 20 Jan 17 nicklas 1197       this.handler = handler;
7273 20 Jan 17 nicklas 1198       this.filter = filter;
7273 20 Jan 17 nicklas 1199       this.loader = loader;
7273 20 Jan 17 nicklas 1200     }
7273 20 Jan 17 nicklas 1201   }
4158 22 Feb 08 nicklas 1202 }