/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * 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 uk.q3c.krail.core.services;
import com.google.common.collect.ImmutableList;
import uk.q3c.util.CycleDetectedException;
import javax.annotation.Nonnull;
import java.util.List;
/**
* Provides a model of Services and dependencies between them. Dependencies types are specified by {@link Dependency.Type}.<br><br>
* The model holds a classGraph and an instanceGraph.<br><br>
* The developer defines dependencies at class level, using Guice (see {@link AbstractServiceModule}) or {@link Dependency} annotations. When a Service
* instance is created by Guice, it is also held by the model in the instance graph, and the model ensures that instances of required dependencies are also
* available or created.
* If a dependency is created which causes a loop (Service A depends on B which depends on A), a {@link CycleDetectedException} is thrown
* <p>
* Created by David Sowerby on 24/10/15.
*/
public interface ServicesModel {
/**
* The {@code dependant} service always depends on {@code dependency}. Thus:<ol><li>if {@code dependency} does not
* start,{@code dependant} cannot start</li><li>if {@code dependency} stops or fails after {@code dependant} has
* started,{@code dependency} stops or fails </li></ol>
*
* @param dependant the Service which depends on {@code dependency}. Will be added to the graph if not already
* added.
* @param dependency the Service on which {@code dependant} depends. Will be added to the graph if not already
* added.
* @throws CycleDetectedException if a loop is created by forming this dependency
*/
void alwaysDependsOn(@Nonnull ServiceKey dependant, @Nonnull ServiceKey dependency);
/**
* The {@code dependant} service depends on {@code dependency}, but only in order to start - for example, {@code
* dependency} may just provide some configuration data in order for {@code dependant} to start. Thus:<ol><li>if
* {@code dependency} does not start,{@code dependant} cannot start</li><li>if {@code dependency} stops or fails
* after {@code dependant} has started,{@code dependency} will continue</li></ol>
*
* @param dependant the Service which depends on {@code dependency}. Will be added to the graph if not already
* added.
* @param dependency the Service on which {@code dependant} depends. Will be added to the graph if not already
* added.
* @throws CycleDetectedException if a loop is created by forming this dependency
*/
void requiresOnlyAtStart(@Nonnull ServiceKey dependant, @Nonnull ServiceKey dependency);
/**
* The {@code dependant} service will attempt to use {@code dependency} if it is available, but will start and
* continue to run without it. Thus:<ol><li>if {@code dependency} does not start,{@code dependant} will still
* start. Note, however, that {@code dependant} will wait until {@code dependency} has either started or failed
* before commencing its own start process.</li><li>if {@code dependency} stops or fails after {@code dependant} has
* started,{@code dependency} will continue</li></ol>
*
* @param dependant the Service which depends on {@code dependency}. Will be added to the graph if not already
* added.
* @param dependency the Service on which {@code dependant} depends. Will be added to the graph if not already
* added.
* @throws CycleDetectedException if a loop is created by forming this dependency
*/
void optionallyUses(@Nonnull ServiceKey dependant, @Nonnull ServiceKey dependency);
/**
* Adds a ServiceKey. Returns true if {@code serviceKey} is added, false if not added (because {@code serviceKey} is already in the graph)
*
* @param serviceKey the ServiceKey to add
*/
boolean addService(@Nonnull ServiceKey serviceKey);
/**
* Adds a service instance, and creates instances of dependencies using the class graph as a 'template'. Returns true if {@code service} is added, false
* if not added (because {@code service} is already in the graph).
*
* @param service the Service to add
*/
boolean addService(@Nonnull Service service);
/**
* Returns true if {@code Service} is contained in the model
*
* @param service the service to check for
*/
boolean contains(Service service);
/**
* Returns true if the {@code serviceKey} is contained within the model. There may not yet be a Service instance associated with the class.
*
* @param serviceKey the ServiceKey to look for
* @return Returns true if the {@code serviceKey} is registered. There may however not be a Service associated with
* the key yet.
*/
boolean contains(ServiceKey serviceKey);
/**
* returns an immutable list of currently contained service instances
*
* @return an immutable list of currently contained service instances
*/
ImmutableList<Service> registeredServiceInstances();
/**
* Stops all services. Usually only used during shutdown
*/
void stopAllServices();
/**
* Returns a list of {@link DependencyInstanceDefinition}s describing the dependencies and their relationship with {@code service}. If you only want the
* services (and not the dependency information), {@link #findInstanceDependencies} is a bit more efficient.
*
* @param service the service for which to obtain dependencies
* @return list of {@link DependencyInstanceDefinition}s describing the dependencies and their relationship with {@code service}
*/
List<DependencyInstanceDefinition> findInstanceDependencyDefinitions(@Nonnull Service service);
ServicesInstanceGraph getInstanceGraph();
ServicesClassGraph getClassGraph();
ImmutableList<ServiceKey> registeredServices();
/**
* Returns a list of immediate dependencies for {@code service}. If you also want the dependency type as well, use
* {@link #findInstanceDependencyDefinitions}
*
* @param service the service for which the dependencies are required
* @return a list of immediate dependencies for {@code service}
*/
List<Service> findInstanceDependencies(Service service);
/**
* Returns a list of immediate dependencies for {@code service}, which are of the type specified by {@code selection} If you also want the dependency type
* as well, use {@link #findInstanceDependencyDefinitions}
*
* @param service the service for which the dependencies are required
* @return a list of immediate dependencies for {@code service}
*/
List<Service> findInstanceDependencies(@Nonnull Service service, @Nonnull ServicesGraph.Selection selection);
}