/* * #%L * Gravia :: Runtime :: API * %% * Copyright (C) 2013 - 2014 JBoss by Red Hat * %% * Licensed 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. * #L% */ package org.jboss.gravia.runtime; import java.util.Collection; import java.util.Dictionary; import org.jboss.gravia.Constants; /** * A module's execution context within the Runtime. The context is used to * grant access to other methods so that this module can interact with the * Runtime. * * <p> * {@code ModuleContext} methods allow a module to: * <ul> * <li>Subscribe to events published by the Runtime. * <li>Register service objects with the Runtime service registry. * <li>Retrieve {@code ServiceReferences} from the Runtime service registry. * <li>Get and release service objects for a referenced service. * <li>Create {@code File} objects for files in a persistent storage area provided for the module by the Runtime. * </ul> * * <p> * A {@code ModuleContext} object will be created for a module when the module * is started. The {@code Module} object associated with a {@code ModuleContext} * object is called the <em>context module</em>. * * <p> * The {@code ModuleContext} object will be passed to the * {@link ModuleActivator#start(ModuleContext)} method during activation of the * context module. The same {@code ModuleContext} object will be passed to the * {@link ModuleActivator#stop(ModuleContext)} method when the context module is * stopped. A {@code ModuleContext} object is generally for the private use of * its associated module and is not meant to be shared with other modules in the * environment. * * <p> * The {@code ModuleContext} object is only valid during the execution of its * context module; that is, during the period from when the context module is in * the {@code STARTING}, {@code STOPPING}, and {@code ACTIVE} module states. If * the {@code ModuleContext} object is used subsequently, an * {@code IllegalStateException} must be thrown. The {@code ModuleContext} * object must never be reused after its context module is stopped. * * <p> * Two {@code ModuleContext} objects are equal if they both refer to the same * execution context of a module. The Runtime is the only entity that can * create {@code ModuleContext} objects and they are only valid within the * Runtime that created them. * * <p> * A {@link Module} can be {@link Module#adapt(Class) adapted} to its * {@code ModuleContext}. * * @author thomas.diesler@jboss.com * @since 27-Sep-2013 * * @ThreadSafe */ public interface ModuleContext { /** * Get the module associated with this context */ Module getModule(); /** * Creates a {@code Filter} object. This {@code Filter} object may be used * to match a {@code ServiceReference} object or a {@code Dictionary} * object. * * <p> * If the filter cannot be parsed, an {@link IllegalArgumentException} will be * thrown with a human readable message where the filter became unparsable. * * @param filter The filter string. * @return A {@code Filter} object encapsulating the filter string. */ Filter createFilter(String filter); /** * Adds the specified {@code ModuleListener} object to the context module's * list of listeners if not already present. ModuleListener objects are * notified when a module has a lifecycle state change. * * <p> * If the context module's list of listeners already contains a listener * {@code l} such that {@code (l==listener)}, this method does nothing. * * @param listener The {@code ModuleListener} to be added. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see ModuleEvent * @see ModuleListener */ void addModuleListener(ModuleListener listener); /** * Removes the specified {@code ModuleListener} object from the context * module's list of listeners. * * <p> * If {@code listener} is not contained in the context module's list of * listeners, this method does nothing. * * @param listener The {@code ModuleListener} object to be removed. * @throws IllegalStateException If this ModuleContext is no longer valid. */ void removeModuleListener(ModuleListener listener); /** * Adds the specified {@code ServiceListener} object with the specified * {@code filter} to the context module's list of listeners. See * {@link Filter} for a description of the filter syntax. * {@code ServiceListener} objects are notified when a service has a * lifecycle state change. * * <p> * If the context module's list of listeners already contains a listener * {@code l} such that {@code (l==listener)}, then this method replaces that * listener's filter (which may be {@code null}) with the specified one * (which may be {@code null}). * * <p> * The listener is called if the filter criteria is met. To filter based * upon the class of the service, the filter should reference the * {@link org.jboss.gravia.Constants#OBJECTCLASS} property. If {@code filter} is {@code null} * , all services are considered to match the filter. * * <p> * When using a {@code filter}, it is possible that the {@code ServiceEvent} * s for the complete lifecycle of a service will not be delivered to the * listener. For example, if the {@code filter} only matches when the * property {@code x} has the value {@code 1}, the listener will not be * called if the service is registered with the property {@code x} not set * to the value {@code 1}. Subsequently, when the service is modified * setting property {@code x} to the value {@code 1}, the filter will match * and the listener will be called with a {@code ServiceEvent} of type * {@code MODIFIED}. Thus, the listener will not be called with a * {@code ServiceEvent} of type {@code REGISTERED}. * * @param listener The {@code ServiceListener} object to be added. * @param filter The filter criteria. * @throws IllegalArgumentException If {@code filter} contains an invalid * filter string that cannot be parsed. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see ServiceEvent * @see ServiceListener */ void addServiceListener(ServiceListener listener, String filter); /** * Adds the specified {@code ServiceListener} object to the context module's * list of listeners. * * <p> * This method is the same as calling * {@code ModuleContext.addServiceListener(ServiceListener listener, * String filter)} with {@code filter} set to {@code null}. * * @param listener The {@code ServiceListener} object to be added. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see #addServiceListener(ServiceListener, String) */ void addServiceListener(ServiceListener listener); /** * Removes the specified {@code ServiceListener} object from the context * module's list of listeners. * * <p> * If {@code listener} is not contained in this context module's list of * listeners, this method does nothing. * * @param listener The {@code ServiceListener} to be removed. * @throws IllegalStateException If this ModuleContext is no longer valid. */ void removeServiceListener(ServiceListener listener); /** * Registers the specified service object with the specified properties * under the name of the specified class with the Runtime. * * <p> * This method is otherwise identical to * {@link #registerService(String, Object, Dictionary)} and is provided to * return a type safe {@code ServiceRegistration}. * * @param <S> Type of Service. * @param clazz The class under whose name the service can be located. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. * @return A {@code ServiceRegistration} object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see #registerService(String, Object, Dictionary) */ <S> ServiceRegistration<S> registerService(Class<S> clazz, S service, Dictionary<String, ?> properties); /** * Registers the specified service object with the specified properties * under the specified class name with the Runtime. * * <p> * This method is otherwise identical to * {@link #registerService(String[], Object, Dictionary)} and is provided as * a convenience when {@code service} will only be registered under a single * class name. Note that even in this case the value of the service's * {@link org.jboss.gravia.Constants#OBJECTCLASS} property will be an array of string, rather * than just a single string. * * @param className The class name under which the service can be located. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. * @return A {@code ServiceRegistration} object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see #registerService(String[], Object, Dictionary) */ ServiceRegistration<?> registerService(String className, Object service, Dictionary<String, ?> properties); /** * Registers the specified service object with the specified properties * under the specified class names into the Runtime. A * {@code ServiceRegistration} object is returned. The * {@code ServiceRegistration} object is for the private use of the module * registering the service and should not be shared with other modules. The * registering module is defined to be the context module. * * <p> * A module can register a service object that implements the * {@link ServiceFactory} interface to have more flexibility in providing * service objects to other modules. * * <p> * The following steps are required to register a service: * <ol> * <li>If {@code service} is not a {@code ServiceFactory}, an * {@code IllegalArgumentException} is thrown if {@code service} is not an * {@code instanceof} all the specified class names. * <li>The Runtime adds the following service properties to the service * properties from the specified {@code Dictionary} (which may be * {@code null}): <br/> * A property named {@link org.jboss.gravia.Constants#SERVICE_ID} identifying the * registration number of the service <br/> * A property named {@link org.jboss.gravia.Constants#OBJECTCLASS} containing all the * specified classes. <br/> * Properties with these names in the specified {@code Dictionary} will be * ignored. * <li>The service is added to the Runtime service registry and may now be * used by other modules. * <li>A service event of type {@link ServiceEvent#REGISTERED} is fired. * <li>A {@code ServiceRegistration} object for this registration is * returned. * </ol> * * @param classNames The class names under which the service can be located. * The class names in this array will be stored in the service's * properties under the key {@link org.jboss.gravia.Constants#OBJECTCLASS}. * @param service The service object or a {@code ServiceFactory} object. * @param properties The properties for this service. The keys in the * properties object must all be {@code String} objects. See * {@link Constants} for a list of standard service property keys. * Changes should not be made to this object after calling this * method. To update the service's properties the * {@link ServiceRegistration#setProperties(Dictionary)} method must * be called. The set of properties may be {@code null} if the * service has no properties. * @return A {@code ServiceRegistration} object for use by the module * registering the service to update the service's properties or to * unregister the service. * @throws IllegalArgumentException If one of the following is true: * <ul> * <li>{@code service} is {@code null}. <li>{@code service} is not a * {@code ServiceFactory} object and is not an instance of all the * named classes in {@code clazzes}. <li> {@code properties} * contains case variants of the same key name. * </ul> * @throws IllegalStateException If this ModuleContext is no longer valid. * @see ServiceRegistration * @see ServiceFactory */ ServiceRegistration<?> registerService(String[] classNames, Object service, Dictionary<String, ?> properties); /** * Returns a {@code ServiceReference} object for a service that implements * and was registered under the name of the specified class. * * <p> * The returned {@code ServiceReference} object is valid at the time of the * call to this method. However as the Runtime is a very dynamic * environment, services can be modified or unregistered at any time. * * <p> * This method is the same as calling * {@link #getServiceReferences(Class, String)} with a {@code null} filter * expression. It is provided as a convenience for when the caller is * interested in any service that implements the specified class. * <p> * If multiple such services exist, the service with the highest ranking (as * specified in its {@link org.jboss.gravia.Constants#SERVICE_RANKING} property) is returned. * <p> * If there is a tie in ranking, the service with the lowest service ID (as * specified in its {@link org.jboss.gravia.Constants#SERVICE_ID} property); that is, the * service that was registered first is returned. * * @param <S> Type of Service. * @param clazz The class under whose name the service was registered. Must * not be {@code null}. * @return A {@code ServiceReference} object, or {@code null} if no services * are registered which implement the specified class. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see #getServiceReferences(Class, String) */ <S> ServiceReference<S> getServiceReference(Class<S> clazz); /** * Returns a {@code ServiceReference} object for a service that implements * and was registered under the specified class. * * <p> * The returned {@code ServiceReference} object is valid at the time of the * call to this method. However as the Runtime is a very dynamic * environment, services can be modified or unregistered at any time. * * <p> * This method is the same as calling * {@link #getServiceReferences(String, String)} with a {@code null} filter * expression and then finding the reference with the highest priority. It * is provided as a convenience for when the caller is interested in any * service that implements the specified class. * <p> * If multiple such services exist, the service with the highest priority is * selected. This priority is defined as the service reference with the * highest ranking (as specified in its {@link org.jboss.gravia.Constants#SERVICE_RANKING} * property) is returned. * <p> * If there is a tie in ranking, the service with the lowest service ID (as * specified in its {@link org.jboss.gravia.Constants#SERVICE_ID} property); that is, the * service that was registered first is returned. * * @param className The class name with which the service was registered. * @return A {@code ServiceReference} object, or {@code null} if no services * are registered which implement the named class. * @throws IllegalStateException If this ModuleContext is no longer valid. * @see #getServiceReferences(String, String) */ ServiceReference<?> getServiceReference(String className); /** * Returns a collection of {@code ServiceReference} objects. The returned * collection of {@code ServiceReference} objects contains services that * were registered under the name of the specified class, match the * specified filter expression, and the packages for the class names under * which the services were registered match the context module's packages as * defined in {@link ServiceReference#isAssignableTo(Module, String)}. * * <p> * The collection is valid at the time of the call to this method. However * since the Runtime is a very dynamic environment, services can be * modified or unregistered at any time. * * <p> * The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link IllegalArgumentException} will be thrown with a human readable * message where the filter became unparsable. * * <p> * The result is a collection of {@code ServiceReference} objects for all * services that meet all of the following conditions: * <ul> * <li>The service must have been registered with the name of the specified * class. The complete list of class names with which a service was * registered is available from the service's {@link org.jboss.gravia.Constants#OBJECTCLASS * objectClass} property. * <li>If the specified {@code filter} is not {@code null}, the filter * expression must match the service. * <li>For each class name with which the service was registered, calling * {@link ServiceReference#isAssignableTo(Module, String)} with the context * module and the class name on the service's {@code ServiceReference} * object must return {@code true} * </ul> * * @param <S> Type of Service * @param clazz The class under whose name the service was registered. Must * not be {@code null}. * @param filter The filter expression or {@code null} for all services. * @return A collection of {@code ServiceReference} objects. May be empty if * no services are registered which satisfy the search. * @throws IllegalArgumentException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this ModuleContext is no longer valid. */ <S> Collection<ServiceReference<S>> getServiceReferences(Class<S> clazz, String filter); /** * Returns an array of {@code ServiceReference} objects. The returned array * of {@code ServiceReference} objects contains services that were * registered under the specified class, match the specified filter * expression, and the packages for the class names under which the services * were registered match the context module's packages as defined in * {@link ServiceReference#isAssignableTo(Module, String)}. * * <p> * The list is valid at the time of the call to this method. However since * the Runtime is a very dynamic environment, services can be modified or * unregistered at any time. * * <p> * The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link IllegalArgumentException} will be thrown with a human readable * message where the filter became unparsable. * * <p> * The result is an array of {@code ServiceReference} objects for all * services that meet all of the following conditions: * <ul> * <li>If the specified class name, {@code clazz}, is not {@code null}, the * service must have been registered with the specified class name. The * complete list of class names with which a service was registered is * available from the service's {@link org.jboss.gravia.Constants#OBJECTCLASS objectClass} * property. * <li>If the specified {@code filter} is not {@code null}, the filter * expression must match the service. * <li>For each class name with which the service was registered, calling * {@link ServiceReference#isAssignableTo(Module, String)} with the context * module and the class name on the service's {@code ServiceReference} * object must return {@code true} * </ul> * * @param className The class name with which the service was registered or * {@code null} for all services. * @param filter The filter expression or {@code null} for all services. * @return An array of {@code ServiceReference} objects or {@code null} if * no services are registered which satisfy the search. * @throws IllegalArgumentException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this ModuleContext is no longer valid. */ ServiceReference<?>[] getServiceReferences(String className, String filter); /** * Returns an array of {@code ServiceReference} objects. The returned array * of {@code ServiceReference} objects contains services that were * registered under the specified class and match the specified filter * expression. * * <p> * The list is valid at the time of the call to this method. However since * the Runtime is a very dynamic environment, services can be modified or * unregistered at any time. * * <p> * The specified {@code filter} expression is used to select the registered * services whose service properties contain keys and values which satisfy * the filter expression. See {@link Filter} for a description of the filter * syntax. If the specified {@code filter} is {@code null}, all registered * services are considered to match the filter. If the specified * {@code filter} expression cannot be parsed, an * {@link IllegalArgumentException} will be thrown with a human readable * message where the filter became unparsable. * * <p> * The result is an array of {@code ServiceReference} objects for all * services that meet all of the following conditions: * <ul> * <li>If the specified class name, {@code clazz}, is not {@code null}, the * service must have been registered with the specified class name. The * complete list of class names with which a service was registered is * available from the service's {@link org.jboss.gravia.Constants#OBJECTCLASS objectClass} * property. * <li>If the specified {@code filter} is not {@code null}, the filter * expression must match the service. * </ul> * * @param className The class name with which the service was registered or * {@code null} for all services. * @param filter The filter expression or {@code null} for all services. * @return An array of {@code ServiceReference} objects or {@code null} if * no services are registered which satisfy the search. * @throws IllegalArgumentException If the specified {@code filter} contains * an invalid filter expression that cannot be parsed. * @throws IllegalStateException If this ModuleContext is no longer valid. */ ServiceReference<?>[] getAllServiceReferences(String className, String filter); /** * Returns the service object referenced by the specified * {@code ServiceReference} object. * <p> * A module's use of a service is tracked by the module's use count of that * service. Each time a service's service object is returned by * {@link #getService(ServiceReference)} the context module's use count for * that service is incremented by one. Each time the service is released by * {@link #ungetService(ServiceReference)} the context module's use count * for that service is decremented by one. * <p> * When a module's use count for a service drops to zero, the module should * no longer use that service. * * <p> * This method will always return {@code null} when the service associated * with this {@code reference} has been unregistered. * * <p> * The following steps are required to get the service object: * <ol> * <li>If the service has been unregistered, {@code null} is returned. * <li>If the context module's use count for the service is currently zero * and the service was registered with an object implementing the * {@code ServiceFactory} interface, the * {@link ServiceFactory#getService(Module, ServiceRegistration)} method is * called to create a service object for the context module. If the service * object returned by the {@code ServiceFactory} object is {@code null}, not * an {@code instanceof} all the classes named when the service was * registered or the {@code ServiceFactory} object throws an exception or * will be recursively called for the context module, {@code null} is * returned. * <br> * This service object is cached by the Runtime. While the context * module's use count for the service is greater than zero, subsequent calls * to get the services's service object for the context module will return * the cached service object. * <li>The context module's use count for this service is incremented by * one. * <li>The service object for the service is returned. * </ol> * * @param <S> Type of Service. * @param reference A reference to the service. * @return A service object for the service associated with * {@code reference} or {@code null} if the service is not * registered, the service object returned by a * {@code ServiceFactory} does not implement the classes under which * it was registered or the {@code ServiceFactory} threw an * exception. * @throws IllegalStateException If this ModuleContext is no longer valid. * @throws IllegalArgumentException If the specified * {@code ServiceReference} was not created by the same framework * instance as this {@code ModuleContext}. * @see #ungetService(ServiceReference) * @see ServiceFactory */ <S> S getService(ServiceReference<S> reference); /** * Releases the service object referenced by the specified * {@code ServiceReference} object. If the context module's use count for * the service is zero, this method returns {@code false}. Otherwise, the * context module's use count for the service is decremented by one. * * <p> * The service's service object should no longer be used and all references * to it should be destroyed when a module's use count for the service drops * to zero. * * <p> * The following steps are required to unget the service object: * <ol> * <li>If the context module's use count for the service is zero or the * service has been unregistered, {@code false} is returned. * <li>The context module's use count for this service is decremented by * one. * <li>If the context module's use count for the service is currently zero * and the service was registered with a {@code ServiceFactory} object, the * {@link ServiceFactory#ungetService(Module, ServiceRegistration, Object)} * method is called to release the service object for the context module. * <li>{@code true} is returned. * </ol> * * @param reference A reference to the service to be released. * @return {@code false} if the context module's use count for the service * is zero or if the service has been unregistered; {@code true} * otherwise. * @throws IllegalStateException If this ModuleContext is no longer valid. * @throws IllegalArgumentException If the specified * {@code ServiceReference} was not created by the same framework * instance as this {@code ModuleContext}. * @see #getService(ServiceReference) * @see ServiceFactory */ boolean ungetService(ServiceReference<?> reference); }