granitic: github.com/graniticio/granitic/ioc Index | Files

package ioc

import "github.com/graniticio/granitic/ioc"

Package ioc provides an Inversion of Control component container and lifecycle hooks.

This package provides the types that define and support Granitic component container, which allows your application's objects and Granitic's framework facilities to follow the inversion of control (IoC) pattern by having their lifecycle and dependencies managed for them. An in-depth discussion of Granitic IoC can be found at http://granitic.io/1.0/ref/ioc but a description of the core concepts follows.

Components

A component is defined by Granitic as an instance of a Go struct with a name that is unique within an application. Each component in your application requires a entry in the components section of your application's component definition file like:

{
  "components": {
    "componentName": {
  	  "type": "package.structType"
    }
  }
}

e.g:

{
  "components": {
    "createRecordLogic": {
  	  "type": "inventory.CreateRecordLogic"
    }
  }
}

For complete information on defining components, refer to http://granitic.io/1.0/ref/components

Granitic's documentation will use the term component and component instance interchangeably. For example, 'component field' means 'a field on the instance of the Go struct associated with that component'.

The container

When Granitic starts, it will create an instance of ioc.ComponentContainer - a structure that holds references to each of the components in your application. It is responsible for injecting dependencies and configuration into your components (see below) and managing lifecycle events (also see below). The container is also referred to as the component container or IoC container.

Framework components

For each Granitic facility that you enable in your application, one or more framework components will be created and added to the container. A framework component is exactly the same as any other component - an instance of a struct with a name. Depending on the complexity of the facility, multiple components may be created.

A very simple name-spacing is used to separate the names of framework components from application components - framework components' names all start with the string grnc

You are strongly encouraged to make sure your application components' names do not start with this string.

Dependencies and configuration

As part of its definition, your components can request that other components are injected into its fields. Your definition can also include configuration (actual values to be set when the component is instantiated) or configuration promises (values to be injected once all sources of configuration have been merged together).

{
  "components": {
    "createRecordLogic": {
  	  "type": "inventory.CreateRecordLogic",
  	  "MaxTracks": 20,
  	  "ArtistMustExist": "conf:record.disableAutoArtist",
  	  "DAO": "ref:inventoryDAO"
    }
  }
}

In the above example, the field CreateRecordLogic.MaxTracks is set to 20 when the struct is instantiated, ArtistMustExist is set to the config element 'record.disableAutoArtist' and DAO is set to a reference to another component's instance. Note that c: and r: can be used as shorthand for config: and ref: See http://granitic.io/1.0/ref/components for more information

Any error such as type mismatches or missing configuration will cause an error that will halt application startup.

Component templates

A template mechanism exists to allow multiple components that share a type, dependencies or configuration items to only have those elements defined once. This is especially useful for web service handlers. See http://granitic.io/1.0/ref/components#templates for more details.

Binding

Unlike JVM/CLR languages, Go has no runtime 'instance-for-type-name' mechanism for creating instances of a struct. As a result, unlike JVM/CLR IoC containers you may have used, the container does not instantiate the actual instances of the Go structs behind application components. Instead a 'binding' proces is used - refer to the pacakage documentation for the grnc-bind tool for more information.

Container lifecycle

The process of starting the container transitions through a number of distinct phase. It is possible for your code to be explicitly invoked during some of these phases by implementing one more lifecycle interfaces.

Populate    Application and framework components are stored in the container.

Configure   Configuration and dependencies are resolved and injected into components.

Decorate    Components implementing the ioc.ComponentDecorator are given access to all other components
            to potentially modify.

Start       Components implementing the ioc.Startable interface are invoked.

Access	    Components implementing ioc.AccessibilityBlocker and ioc.Accessible are interacted with.

Ready       Granitic application is running.

When the container is ready, a log message similar to

grncInit Ready (startup time 6.28ms)

will be logged.

There are several other possible lifecycle phases after the container is ready:

Suspend     Components implementing ioc.Suspendable  have their Suspend method invoked.

Resume      Components implementing ioc.Suspendable have their Resume method invoked.

Stop        Components implementing ioc.Stoppable are allowed to stop gracefully before the application exits.

Decorators

Decorators are special components implementing ioc.ComponentDecorator. Their main purpose is to inject dynamically created objects into other components (such as Loggers). Decorators are destroyed after the Decorate phase of container startup.

Stopping

Components that need to perform some shutdown process before an application exits should implement the Stoppable interface. See the GoDoc for ioc.Stoppable below for more detail.

Container settings

The file $GRANITIC_HOME/resource/facility-config/system.json contains configuration, that can be overridden in your application's configuration file, affecting startup, garbage collection and shutdown behaviour of the container.

More information can be found at http://granitic.io/1.0/ref/system-settings

Gaining access to the container

If your application component needs direct access to the container it should implement the ioc.ContainerAccessor. A reference to the container will be injected into your component during the decorate phase.

External interaction with the container

If your application enables the RuntimeCtl facility, you can interact with the container and its components by using the grnc-ctl command line utility. See the package documentation for grnc-ctl for more information.

Index

Package Files

component.go container.go decorator.go lifecycle.go

Constants

const (
    StoppedState = iota
    StoppingState
    StartingState
    AwaitingAccessState
    RunningState
    SuspendingState
    SuspendedState
    ResumingState
)
const (
    None = iota
    CanStart
    CanStop
    CanSuspend
    CanBlockStart
    CanBeAccessed
)

type AccessibilityBlocker Uses

type AccessibilityBlocker interface {

    // BlockAccess returns true if the component wants to prevent the application from becoming ready and accessible. An
    // optional error message can be returned explaining why.
    BlockAccess() (bool, error)
}

Implemented by components that MUST be ready before an application can be made accessible. For example, a component connecting to a critical external system might implement AccessibilityBlocker to prevent an HTTP server making an API available until a connection to the critical system is established.

See http://granitic.io/1.0/ref/system-settings for information about the number of times BlockAccess is called, and how the interval between these calls can be adjusted for your application.

type Accessible Uses

type Accessible interface {
    // AllowAccess is called by the container as the final stage of making an application ready.
    AllowAccess() error
}

Implemented by components that require a final phase of initialisation to make themselves outside of the application. Typically implemented by HTTP servers and message queue listeners to start listening on TCP ports.

type ByName Uses

type ByName struct{ Components }

func (ByName) Less Uses

func (s ByName) Less(i, j int) bool

type Component Uses

type Component struct {
    // A pointer to a struct
    Instance interface{}

    // A name for this component that is unique within your application
    Name string
}

A Component is an instance of a struct with a name that is unique within your application.

func NewComponent Uses

func NewComponent(name string, instance interface{}) *Component

NewComponent creates a new Component with the supplied name and instance

type ComponentByNameFinder Uses

type ComponentByNameFinder interface {
    // ComponentByName returns the Component with the supplied name, or nil if it does not exist.
    ComponentByName(string) *Component
}

Implemented by components that need to be able to find other components by name.

type ComponentContainer Uses

type ComponentContainer struct {
    FrameworkLogger logging.Logger

    Lifecycle *LifecycleManager
    // contains filtered or unexported fields
}

The Granitic IoC container. See the GoDoc for the ioc package for more information on how to interact with the container.

Most applications should never need to interact with the container programmatically.

func NewComponentContainer Uses

func NewComponentContainer(logm *logging.ComponentLoggerManager, ca *config.ConfigAccessor, sys *instance.System) *ComponentContainer

Create a new instance of a Granitic IoC container.

func (*ComponentContainer) AddModifier Uses

func (cc *ComponentContainer) AddModifier(comp string, field string, dep string)

AddModifier is used to override a dependency on a component (normally a built-in Granitic component) during the configure phase of container startup.

func (*ComponentContainer) AddModifiers Uses

func (cc *ComponentContainer) AddModifiers(mods map[string]map[string]string)

AddModifiers is used to override a dependency on set of components (normally built-in Granitic components) during the configure phase of container startup.

func (*ComponentContainer) AddProto Uses

func (cc *ComponentContainer) AddProto(proto *ProtoComponent)

AddProto registers an instantiated but un-configured proto-component.

func (*ComponentContainer) AddProtos Uses

func (cc *ComponentContainer) AddProtos(protos []*ProtoComponent)

AddProto regsiters a collection of proto-components (see AddProto)

func (*ComponentContainer) AllComponents Uses

func (cc *ComponentContainer) AllComponents() []*Component

AllComponents returns all of the components hosted by the container.

func (*ComponentContainer) ByLifecycleSupport Uses

func (cc *ComponentContainer) ByLifecycleSupport(ls LifecycleSupport) []*Component

ByLifecycleSupport returns all components hosted by the container that have specific support for a lifecycle event (i.e. implement the associated lifecycle interface

func (*ComponentContainer) ComponentByName Uses

func (cc *ComponentContainer) ComponentByName(name string) *Component

See ComponentByNameFinder.ComponentByName

func (*ComponentContainer) ModifierExists Uses

func (cc *ComponentContainer) ModifierExists(comp string, field string) bool

ModifierExists checks to see if a modifier (see AddModifier) has previously been registered for a field on a component.

func (*ComponentContainer) Modifiers Uses

func (cc *ComponentContainer) Modifiers(comp string) map[string]string

Modifiers returns all registered modifiers (see AddModifier)

func (*ComponentContainer) ModifiersExist Uses

func (cc *ComponentContainer) ModifiersExist(comp string) bool

ModifiersExist returns true if any modifiers (see AddModifier) have been registered.

func (*ComponentContainer) Populate Uses

func (cc *ComponentContainer) Populate() error

Populate converts all registered proto-components into components and populates them with configuration and dependencies.

func (*ComponentContainer) ProtoComponents Uses

func (cc *ComponentContainer) ProtoComponents() map[string]*ProtoComponent

ProtoComponents returns all components that have been registered by the container but have not yet all their dependencies resolved. If called after the container is 'Accessible' an empty slice will be returned.

func (*ComponentContainer) ProtoComponentsByType Uses

func (cc *ComponentContainer) ProtoComponentsByType(tm TypeMatcher) []*ProtoComponent

ProtoComponentsByType returns any ProtoComponents whose Component.Instance field matches the against the supplied TypeMatcher function. If called after the container is 'Accessible' an empty slice will be returned.

func (*ComponentContainer) WrapAndAddProto Uses

func (cc *ComponentContainer) WrapAndAddProto(name string, instance interface{})

WrapAndAddProto registers an instance and name as an un-configured proto-component.

type ComponentDecorator Uses

type ComponentDecorator interface {
    // OfInterest should return true if the ComponentDecorator decides that the supplied component needs to be decorated.
    OfInterest(subject *Component) bool

    // DecorateComponent modifies the subject component.
    DecorateComponent(subject *Component, container *ComponentContainer)
}

ComponentDecorator is implemented by special temporary components that only exist while the IoC container is being populated.

A ComponentDecorator's job is to examine another component (the subject) to see if it is suitable for modification by the ComponentDecorator. Typically this will involve the ComponentDecorator injecting another object into the subject if the component implements a particular interface or has a writable field of a particular name or type.

A number of built-in decorators exist to accomplish tasks like automatically adding Loggers to components with a particular field.

type ComponentNamer Uses

type ComponentNamer interface {
    // ComponentName returns the name of the component
    ComponentName() string

    // SetComponentName injects the component's name
    SetComponentName(name string)
}

Implemented by components where the component's instance needs to be aware of its own component name.

type ComponentState Uses

type ComponentState int

What state (stopped, running) or transition between states (stopping, starting) a component is currently in.

type Components Uses

type Components []*Component

Type definition for a slice of components to allow sorting.

func (Components) Len Uses

func (s Components) Len() int

func (Components) Swap Uses

func (s Components) Swap(i, j int)

type ContainerAccessor Uses

type ContainerAccessor interface {
    // Container accepts a reference to the Granitic IoC container.
    Container(container *ComponentContainer)
}

An interface implemented by any component that wants direct access to the IoC container.

type ContainerDecorator Uses

type ContainerDecorator struct {
    // contains filtered or unexported fields
}

ContainerDecorator injects a reference to the IoC container into any component implementing the ContainerAccessor interface.

func (*ContainerDecorator) DecorateComponent Uses

func (cd *ContainerDecorator) DecorateComponent(subject *Component, cc *ComponentContainer)

DecorateComponent injects a reference to the IoC container to a component that has alredy been determined to implement ContainerAccessor.

func (*ContainerDecorator) OfInterest Uses

func (cd *ContainerDecorator) OfInterest(subject *Component) bool

OfInterest returns true if the subject component implements ContainerAccessor

type LifecycleManager Uses

type LifecycleManager struct {
    FrameworkLogger logging.Logger
    // contains filtered or unexported fields
}

Provides an interface to the components to allow lifecycle methods/events to be applied to all components or a subset of the components.

func (*LifecycleManager) ResumeComponents Uses

func (lm *LifecycleManager) ResumeComponents(comps []*Component) error

SuspendComponents invokes Resume on all of the supplied components that implement Suspendable

func (*LifecycleManager) Start Uses

func (lm *LifecycleManager) Start(startable []*Component) error

Start starts the supplied components, waits for any access-blocking components to be ready, then makes all components accessible. See GoDoc for Startable, AccessibilityBlocker and Accessible for more details.

func (*LifecycleManager) StartAll Uses

func (lm *LifecycleManager) StartAll() error

StartAll finds all Startable and Accessible components runs the Start/Block/Accessible cycle.

func (*LifecycleManager) StopAll Uses

func (lm *LifecycleManager) StopAll() error

StopAll finds all components implementing Stoppable and passes them to Stop

func (*LifecycleManager) StopComponents Uses

func (lm *LifecycleManager) StopComponents(comps []*Component) error

StopComponents invokes PrepareToStop on all components then waits for them to be ready to stop by calling ReadyToStop on each component. If one or more components are not ready, they are given x chances to become ready with y milliseconds between each check. See http://granitic.io/1.0/ref/system-settings

If all components are ready, or if x has been exceeded, Stop is called on all components.

func (*LifecycleManager) SuspendComponents Uses

func (lm *LifecycleManager) SuspendComponents(comps []*Component) error

SuspendComponents invokes Suspend on all of the supplied components that implement Suspendable

type LifecycleSupport Uses

type LifecycleSupport int

Enumeration able used to categorise types by the lifecycle events they can react to.

type ProtoComponent Uses

type ProtoComponent struct {
    // The name of a component and the component instance (a pointer to an instantiated struct).
    Component *Component

    // A map of fields on the component instance and the names of other components that should be injected into those fields.
    Dependencies map[string]string

    // A map of fields on the component instance and the config-path that will contain the configuration that shoud be inject into the field.
    ConfigPromises map[string]string
}

A ProtoComponent is a partially configured component that will be hosted in the Granitic IoC container once it is fully configured. Typically ProtoComponents are created using the grnc-bind tool.

func CreateProtoComponent Uses

func CreateProtoComponent(componentInstance interface{}, componentName string) *ProtoComponent

CreateProtoComponent creates a new ProtoComponent.

func (*ProtoComponent) AddConfigPromise Uses

func (pc *ProtoComponent) AddConfigPromise(fieldName, configPath string)

AddDependency requests that the container injects the config value at the specified path into the specified field during the configure phase of container startup.

func (*ProtoComponent) AddDependency Uses

func (pc *ProtoComponent) AddDependency(fieldName, componentName string)

AddDependency requests that the container injects another component into the specified field during the configure phase of container startup

type ProtoComponents Uses

type ProtoComponents struct {
    // ProtoComponents to be finalised and stored in the IoC container.
    Components []*ProtoComponent

    // FrameworkDependencies are instructions to inject components into built-in Granitic components to alter their behaviour.
    // The structure is map[
    FrameworkDependencies map[string]map[string]string

    //A Base64 encoded version of the JSON files found in resource/facility-confg
    FrameworkConfig *string
}

A wrapping structure for a list of ProtoComponents and FrameworkDependencies that is required when starting Granitic. A ProtoComponents structure is built by the grnc-bind tool.

func NewProtoComponents Uses

func NewProtoComponents(pc []*ProtoComponent, fd map[string]map[string]string, ser *string) *ProtoComponents

NewProtoComponents creates a wrapping structure for a list of ProtoComponents

func (*ProtoComponents) Clear Uses

func (pc *ProtoComponents) Clear()

Clear removes the reference to the ProtoComponent objects held in this object, encouraging garbage collection.

type Startable Uses

type Startable interface {
    // StartComponent performs initialisation and may start listeners/servers.
    StartComponent() error
}

Implemented by components that need to perform some initialisation before they are ready to run or use.

Components that provide services outside of the application (like HTTP servers or queue listeners) should consider implementing Accessible in addition to Startable.

type Stoppable Uses

type Stoppable interface {
    // PrepareToStop gives notice to the component that the application is about to halt. The implementation of this method
    // should cause the component to block any new requests for work.
    PrepareToStop()

    // ReadyToStop is called by the container to query whether or not the component is ready to shutdown. A component might
    // return false if it is still processing or running a job. If the component returns false, it may optionally return
    // an error to explain why it is not ready.
    ReadyToStop() (bool, error)

    // Stop is an instruction by the container to immediately terminate any running processes and release any resources.
    // If the component is unable to do so, it may return an error, but the application will still stop.
    Stop() error
}

Implemented by components that need to be given the opportunity to release resources or perform shutdown activities before an application is halted.

See http://granitic.io/1.0/ref/system-settings for information about the number of times ReadyToStop is called, and how the interval between these calls, can be adjusted for your application.

type Suspendable Uses

type Suspendable interface {
    // Suspend causes the component to stop performing its primary function until Resume is called.
    Suspend() error

    // Resume causes the component to resume its primary function.
    Resume() error
}

Implemented by components that are able to temporarily halt and then resume their activity at some later point in time.

type TypeMatcher Uses

type TypeMatcher func(i interface{}) bool

TypeMatcher implementations return true if the supplied interface is (or implements) an expected type

Package ioc imports 10 packages (graph) and is imported by 17 packages. Updated 2018-09-06. Refresh now. Tools for package owners.