package rescuecore2.registry; import java.util.Map; import java.util.HashMap; import java.io.InputStream; import java.io.IOException; import rescuecore2.worldmodel.Entity; import rescuecore2.worldmodel.EntityID; import rescuecore2.worldmodel.Property; import rescuecore2.messages.Message; import rescuecore2.log.Logger; /** A class for managing the different types of entities, properties, messages and their associated factories. */ public final class Registry { /** The system-(or at least Classloader)-wide Registry. */ public static final Registry SYSTEM_REGISTRY = new Registry("System", null); private static final ThreadLocal<Registry> CURRENT_REGISTRY = new InheritableThreadLocal<Registry>() { @Override public Registry initialValue() { return SYSTEM_REGISTRY; } }; static { // Register the ControlMessageFactory SYSTEM_REGISTRY.registerMessageFactory(rescuecore2.messages.control.ControlMessageFactory.INSTANCE); } private final Map<String, EntityFactory> entityFactories; private final Map<String, PropertyFactory> propertyFactories; private final Map<String, MessageFactory> messageFactories; private final Registry parent; private final String name; /** Create a new Registry that uses the system registry as a parent. */ public Registry() { this(null, SYSTEM_REGISTRY); } /** Create a new Registry with a particular name that uses the system registry as a parent. @param name The name of this Registry. */ public Registry(String name) { this(name, SYSTEM_REGISTRY); } /** Create a new Registry with a particular parent. @param parent The parent Registry. */ public Registry(Registry parent) { this(null, parent); } /** Create a new Registry with a particular name and parent. @param name The name of this Registry. @param parent The parent Registry. */ public Registry(String name, Registry parent) { this.name = name; this.parent = parent; entityFactories = new HashMap<String, EntityFactory>(); propertyFactories = new HashMap<String, PropertyFactory>(); messageFactories = new HashMap<String, MessageFactory>(); } /** Get the current Registry for this thread. @return The current Registry for this thread. */ public static Registry getCurrentRegistry() { return CURRENT_REGISTRY.get(); } /** Set the current Registry for this thread. @param r The current Registry for this thread. */ public static void setCurrentRegistry(Registry r) { CURRENT_REGISTRY.set(r); } @Override public String toString() { return getName(); } /** Get the name of this registry. @return The name of this registry. */ public String getName() { if (name == null) { return super.toString(); } return name; } /** Register an entity factory. This will register all entity URNs that the factory knows about. @param factory The entity factory to register. */ public void registerEntityFactory(EntityFactory factory) { for (String urn : factory.getKnownEntityURNs()) { registerEntityFactory(urn, factory); } } /** Register an entity URN and assign an EntityFactory for constructing instances of this type. @param urn The urn to register. @param factory The factory that is responsible for constructing entity instances of this type. */ public void registerEntityFactory(String urn, EntityFactory factory) { synchronized (entityFactories) { EntityFactory old = entityFactories.get(urn); if (old != null && old != factory) { Logger.warn(getName() + ": entity " + urn + " is being clobbered by " + factory + ". Old factory: " + old); } entityFactories.put(urn, factory); } } /** Register a property factory. This will register all property URNs that the factory knows about. @param factory The property factory to register. */ public void registerPropertyFactory(PropertyFactory factory) { for (String urn : factory.getKnownPropertyURNs()) { registerPropertyFactory(urn, factory); } } /** Register a property URN and assign a PropertyFactory for constructing instances of this type. @param urn The urn to register. @param factory The factory that is responsible for constructing property instances of this type. */ public void registerPropertyFactory(String urn, PropertyFactory factory) { synchronized (propertyFactories) { PropertyFactory old = propertyFactories.get(urn); if (old != null && old != factory) { Logger.warn(getName() + ": property " + urn + " is being clobbered by " + factory + ". Old factory: " + old); } propertyFactories.put(urn, factory); } } /** Register a message factory. This will register all message URNs that the factory knows about. @param factory The message factory to register. */ public void registerMessageFactory(MessageFactory factory) { for (String urn : factory.getKnownMessageURNs()) { registerMessageFactory(urn, factory); } } /** Register a message URN and assign a MessageFactory for constructing instances of this type. @param urn The urn to register. @param factory The factory that is responsible for constructing message instances of this type. */ public void registerMessageFactory(String urn, MessageFactory factory) { synchronized (messageFactories) { MessageFactory old = messageFactories.get(urn); if (old != null && old != factory) { Logger.warn(getName() + ": message " + urn + " is being clobbered by " + factory + ". Old factory: " + old); } messageFactories.put(urn, factory); } } /** Create an entity from a urn. If the urn is not recognised then return null. This method will delegate to the {@link #registerEntityFactory(EntityFactory) previously registered} EntityFactory. @param urn The urn of the entity type to create. @param id The EntityID of the Entity that will be created. @return A new Entity object, or null if the urn is not recognised. */ public Entity createEntity(String urn, EntityID id) { EntityFactory factory = getEntityFactory(urn); if (factory == null) { Logger.warn(getName() + ": Entity " + urn + " not recognised."); return null; } return factory.makeEntity(urn, id); } /** Create a property from a urn. If the urn is not recognised then return null. This method will delegate to the {@link #registerPropertyFactory(PropertyFactory) previously registered} PropertyFactory. @param urn The urn of the property type to create. @return A new Property object, or null if the urn is not recognised. */ public Property createProperty(String urn) { PropertyFactory factory = getPropertyFactory(urn); if (factory == null) { Logger.warn(getName() + ": Property " + urn + " not recognised."); return null; } return factory.makeProperty(urn); } /** Create a message from a urn. If the urn is not recognised then return null. This method will delegate to the {@link #registerMessageFactory(MessageFactory) previously registered} MessageFactory. @param urn The urn of the message type to create. @param data An InputStream to read message data from. @return A new Message object, or null if the urn is not recognised. @throws IOException If there is a problem decoding the message. */ public Message createMessage(String urn, InputStream data) throws IOException { MessageFactory factory = getMessageFactory(urn); if (factory == null) { Logger.warn(getName() + ": Message " + urn + " not recognised."); return null; } return factory.makeMessage(urn, data); } /** Get the entity factory for a URN, delegating to the parent if required. @param urn The URN to look up. @return An EntityFactory, or null if the URN is not recognised. */ protected EntityFactory getEntityFactory(String urn) { EntityFactory result = null; synchronized (entityFactories) { result = entityFactories.get(urn); } if (result == null && parent != null) { result = parent.getEntityFactory(urn); } return result; } /** Get the property factory for a URN, delegating to the parent if required. @param urn The URN to look up. @return A PropertyFactory, or null if the URN is not recognised. */ protected PropertyFactory getPropertyFactory(String urn) { PropertyFactory result = null; synchronized (propertyFactories) { result = propertyFactories.get(urn); } if (result == null && parent != null) { result = parent.getPropertyFactory(urn); } return result; } /** Get the message factory for a URN, delegating to the parent if required. @param urn The URN to look up. @return A MessageFactory, or null if the URN is not recognised. */ protected MessageFactory getMessageFactory(String urn) { MessageFactory result = null; synchronized (messageFactories) { result = messageFactories.get(urn); } if (result == null && parent != null) { result = parent.getMessageFactory(urn); } return result; } }