/*
* Copyright (C) 2015 Red Hat, Inc. and/or its affiliates.
*
* 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.
*/
package org.jboss.errai.ioc.client.container;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Optional;
import org.jboss.errai.ioc.client.Container;
import org.jboss.errai.ioc.client.api.ContextualTypeProvider;
import org.jboss.errai.ioc.client.api.ScopeContext;
/**
* A {@link Context} is responsible for managing the creation and destruction of
* beans for a given set of scopes.
*
* For the most part a {@link Context} is classified by the behaviour of calling
* {@link #getInstance(String)}. For example the {@link DependentScopeContext}
* returns a new instance everytime {@link #getInstance(String)} is invoked,
* whereas the {@link ApplicationScopedContext} returns the same instance for
* every invocation.
*
* At runtime the {@link Container} all factories with their respective
* {@link Context} via {@link #registerFactory(Factory)} before any beans are
* created.
*
* Application code should not interact directly with a {@link Context}, but
* should instead use the {@link ClientBeanManager} for programmatic creation of
* beans.
*
* @see ScopeContext
* @author Max Barkley <mbarkley@redhat.com>
*/
public interface Context {
/**
* This method will only be called once at runtime, when an application is
* bootstrapping, before any bean instances are created.
*
* @param contextManager
* A reference to the application's {@link ContextManager}.
*/
void setContextManager(ContextManager contextManager);
/**
* @return A reference to the {@link ContextManager} that was given as a
* parameter of {@link #setContextManager(ContextManager)}.
*/
ContextManager getContextManager();
/**
* When an application is boostrapping, this method is called for every
* {@link Factory} this {@link Context} is responsible for. This happens
* before any bean instances are created.
*
* Once a {@link Factory} is registered, it's beans should be available
* through calls to {@link #getInstance(String)} with the respective
* {@link FactoryHandle#getFactoryName() name}.
*
* @param factory
* A {@link Factory} that this {@link Context} is respon
*/
<T> void registerFactory(Factory<T> factory);
/**
* Gets and instance of a bean from a {@link Factory} with the given name
* (that was previously {@link #registerFactory(Factory) registered}).
*
* @param factoryName
* The {@link FactoryHandle#getFactoryName() name} of the for the
* desired bean instance.
* @return An instance of a bean from the {@link Factory} with the given
* {@link FactoryHandle#getFactoryName() name}. This instance may or
* may not be {@link Proxy proxied}.
*/
<T> T getInstance(String factoryName);
/**
* Destroys a bean instance if it is {@link #isManaged(Object) managed} by
* this {@link Context}. For unmanaged beans, this is a noop.
*
* @param instance
* A bean instance to be destroyed, if {@link #isManaged(Object)
* managed} by this {@link Context}.
*/
void destroyInstance(Object instance);
/**
* When a call to {@link #getInstance(String)} returns a {@link Proxy}, the
* proxy will eventually need to be populated. This is done in generated code
* by the {@link ProxyHelper} via a call to this method.
*
* @param factoryName
* The {@link FactoryHandle#getFactoryName() name} of a factory from
* which the returned bean instance is created.
* @return An instance of a bean that must not be a {@link Proxy}.
*/
<T> T getActiveNonProxiedInstance(String factoryName);
/**
* @return A representative annotation for this {@link Context}. This is only
* used for logging and error reporting.
*/
Class<? extends Annotation> getScope();
/**
* @param scope
* A scope annotation type.
* @return True iff this context implementation handles the given scope.
*/
boolean handlesScope(Class<? extends Annotation> scope);
/**
* This method is called when a {@link ProxyHelper} attempts to populate a
* proxy. It is not called when a {@link Proxy} already contains a proxied
* instance. Therefore, when a {@link Context} becomes inactive it is its
* responsibility to {@link ProxyHelper#clearInstance() clear instances} from
* {@link Proxy proxies}.
*
* For simple contexts such as {@link ApplicationScopedContext} and
* {@link DependentScopeContext}, this method will always return true. This
* method exists to allow for future scopes of higher complexity.
*
* @return True iff this {@link Context} is currently active.
*/
boolean isActive();
/**
* @return Get all of the {@link Factory factories} that have been
* {@link #registerFactory(Factory) registered} with this context.
*/
Collection<Factory<?>> getAllFactories();
/**
* Regardless of the behaviour of {@link #getInstance(String)} this method
* must return a previously non-existent bean instance (to support
* {@link SyncBeanDef#newInstance()}.
*
* @param factoryName
* The {@link FactoryHandle#getFactoryName() name} of a factory from
* which the returned bean instance is created.
* @return A new bean instance that may or may not be a {@link Proxy}.
*/
<T> T getNewInstance(String factoryName);
/**
* This method should return true if a given reference is a direct bean
* instance or a {@link Proxy}, provided the bean is from a {@link Factory}
* registered with this context.
*
* @param ref
* An object reference that may or may not be a {@link Proxy}.
* @return True iff this object is managed by this {@link Context}.
*/
boolean isManaged(Object ref);
/**
* Used for adding {@link DestructionCallback destruction callbacks}
* programmatically at runtime. These callbacks should be invoked before a
* call to {@link #destroyInstance(Object)} returns.
*
* @param instance
* An instance managed by this context. This may or may not be a
* {@link Proxy}.
* @param callback
* A callback to be invoked when {@link #destroyInstance(Object)} is
* called for the given instance.
* @return True iff the callback was successfully registered. Should return
* false if the given instance is not managed by this context.
*/
boolean addDestructionCallback(Object instance, DestructionCallback<?> callback);
/**
* {@link Factory Factories} can store properties associated with instances
* they've created. This method allows factories from other contexts to access
* these stored values.
*
* @param instance
* The bean instance for which the desired property (if it exists) is
* associated. May or may not be a {@link Proxy}.
* @param propertyName
* The name of a property associated with an instance.
* @param type
* For convenince. The returned value will be cast to this type.
* @return If this instance is not managed by this context return {@code null}
* . Otherwise, return the result of
* {@link Factory#getReferenceAs(Object, String, Class)} for the
* {@link Factory} that created this bean instance.
*/
<P> P getInstanceProperty(Object instance, String propertyName, Class<P> type);
/**
* Some contexts support contextual instances (from a {@link ContextualTypeProvider}).
* This method provides access to that aspect of the context, if supported.
*
* @return An option containing this context if contextual instances are supported,
* or else an empty option.
*/
Optional<HasContextualInstanceSupport> withContextualInstanceSupport();
}