diff --git a/bom/pom.xml b/bom/pom.xml
index 2be055d04e5..dedb883fd78 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -1402,6 +1402,11 @@
helidon-pico-types${helidon.version}
+
+ io.helidon.pico
+ helidon-pico-spi
+ ${helidon.version}
+
diff --git a/pico/pom.xml b/pico/pom.xml
index d6288a5990e..83d3301b3b7 100644
--- a/pico/pom.xml
+++ b/pico/pom.xml
@@ -46,7 +46,7 @@
api
-
+ spitypesbuilder
diff --git a/pico/spi/pom.xml b/pico/spi/pom.xml
new file mode 100644
index 00000000000..087137b270d
--- /dev/null
+++ b/pico/spi/pom.xml
@@ -0,0 +1,110 @@
+
+
+
+
+ io.helidon.pico
+ helidon-pico-project
+ 4.0.0-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ helidon-pico-spi
+ Helidon Pico SPI
+
+
+
+ true
+
+
+
+
+ io.helidon.pico
+ helidon-pico-types
+
+
+ io.helidon.common
+ helidon-common
+
+
+ jakarta.inject
+ jakarta.inject-api
+ compile
+
+
+ io.helidon.pico
+ helidon-pico-api
+ provided
+
+
+ io.helidon.pico.builder
+ helidon-pico-builder-api
+ provided
+
+
+ jakarta.annotation
+ jakarta.annotation-api
+ provided
+
+
+ javax.inject
+ javax.inject
+ ${javax.injection.version}
+ provided
+ true
+
+
+ javax.annotation
+ javax.annotation-api
+ provided
+ true
+
+
+ org.hamcrest
+ hamcrest-all
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.helidon.pico.builder
+ helidon-pico-builder-processor
+ ${helidon.version}
+
+
+
+
+
+
+
+
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLog.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLog.java
new file mode 100644
index 00000000000..b3905268210
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLog.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+
+/**
+ * Tracks the transformations of {@link ServiceProvider}'s {@link ActivationStatus} in lifecycle activity (i.e., activation startup
+ * and deactivation shutdown).
+ *
+ * @see Activator
+ * @see DeActivator
+ */
+public interface ActivationLog {
+
+ /**
+ * Expected to be called during service creation and activation to capture the activation log transcripts.
+ *
+ * @param entry the log entry to record
+ * @return the activation log entry
+ */
+ ActivationLogEntry> recordActivationEvent(ActivationLogEntry> entry);
+
+ /**
+ * Optionally provide a means to query the activation log.
+ *
+ * @return the optional query API of log activation records
+ */
+ default Optional toQuery() {
+ return Optional.empty();
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogEntry.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogEntry.java
new file mode 100644
index 00000000000..719d30f7aad
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogEntry.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.time.OffsetDateTime;
+import java.util.Optional;
+
+import io.helidon.pico.builder.api.Builder;
+
+/**
+ * Log entry for lifecycle related events (i.e., activation startup and deactivation shutdown).
+ *
+ * @see io.helidon.pico.spi.ActivationLog
+ * @see io.helidon.pico.spi.Activator
+ * @see io.helidon.pico.spi.DeActivator
+ * @param the service type
+ */
+@Builder
+interface ActivationLogEntry {
+
+ /**
+ * The activation event.
+ */
+ enum Event {
+
+ /**
+ * Starting.
+ */
+ STARTING,
+
+ /**
+ * Finished.
+ */
+ FINISHED
+ }
+
+ /**
+ * The managing service provider.
+ *
+ * @return the managing service provider
+ */
+ ServiceProvider serviceProvider();
+
+ /**
+ * The event.
+ *
+ * @return the event
+ */
+ Event event();
+
+ /**
+ * The starting activation phase.
+ *
+ * @return the starting activation phase
+ */
+ ActivationPhase startingActivationPhase();
+
+ /**
+ * The eventual/desired/target activation phase.
+ *
+ * @return the eventual/desired/target activation phase
+ */
+ ActivationPhase targetActivationPhase();
+
+ /**
+ * The finishing phase at the time of this event / log entry.
+ *
+ * @return the actual finishing phase
+ */
+ ActivationPhase finishingActivationPhase();
+
+ /**
+ * The finishing activation status at the time of this event / log entry.
+ *
+ * @return the activation status
+ */
+ ActivationStatus finishingStatus();
+
+ /**
+ * The time this event was generated.
+ *
+ * @return the time of the event
+ */
+ OffsetDateTime time();
+
+ /**
+ * Any observed error during activation.
+ *
+ * @return any observed error
+ */
+ Optional error();
+
+ /**
+ * The thread id that the event occurred on.
+ *
+ * @return the thread id
+ */
+ Long getThreadId();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogQuery.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogQuery.java
new file mode 100644
index 00000000000..fe9ef4f233c
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationLogQuery.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.List;
+
+/**
+ * Provide a means to query the activation log.
+ *
+ * @see ActivationLog
+ */
+public interface ActivationLogQuery {
+
+ /**
+ * Clears the activation log.
+ */
+ void clear();
+
+ /**
+ * The full transcript of all services phase transitions being managed.
+ *
+ * @return the activation log if log capture is enabled
+ */
+ List> fullActivationLog();
+
+ /**
+ * A filtered list only including service providers.
+ *
+ * @param serviceProviders the filter
+ * @return the filtered activation log if log capture is enabled
+ */
+ List> serviceProviderActivationLog(ServiceProvider>... serviceProviders);
+
+ /**
+ * A filtered list only including service providers.
+ *
+ * @param serviceTypeNames the filter
+ * @return the filtered activation log if log capture is enabled
+ */
+ List> serviceProviderActivationLog(String... serviceTypeNames);
+
+ /**
+ * A filtered list only including service providers.
+ *
+ * @param instances the filter
+ * @return the filtered activation log if log capture is enabled
+ */
+ List> managedServiceActivationLog(Object... instances);
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationPhase.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationPhase.java
new file mode 100644
index 00000000000..115affaad8d
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationPhase.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+/**
+ * Forms a progression of full activation and deactivation.
+ */
+public enum ActivationPhase {
+
+ /**
+ * Starting state before anything happens activation-wise.
+ */
+ INIT(0, false),
+
+ /**
+ * Planned to be activated.
+ */
+ PENDING(1, true),
+
+ /**
+ * Starting to be activated.
+ */
+ ACTIVATION_STARTING(2, true),
+
+ /**
+ * Gathering dependencies.
+ */
+ GATHERING_DEPENDENCIES(3, true),
+
+ /**
+ * Constructing.
+ */
+ CONSTRUCTING(4, true),
+
+ /**
+ * Injecting (fields then methods).
+ */
+ INJECTING(5, true),
+
+ /**
+ * Calling any post construct method.
+ */
+ POST_CONSTRUCTING(6, true),
+
+ /**
+ * Finishing post construct method.
+ */
+ ACTIVATION_FINISHING(7, true),
+
+ /**
+ * Service is active.
+ */
+ ACTIVE(8, true),
+
+ /**
+ * About to call pre-destroy.
+ */
+ PRE_DESTROYING(9, false),
+
+ /**
+ * Destroyed (after calling any pre-destroy).
+ */
+ DESTROYED(10, false);
+
+ /**
+ * The sequence of activation or deactivation.
+ */
+ private final int sequence;
+
+ /**
+ * True if this phase is eligible for deactivation/shutdown.
+ */
+ private final boolean eligibleForDeactivation;
+
+ /**
+ * The sequence of activation or deactivation.
+ *
+ * @return the sequence
+ */
+ public int sequence() {
+ return sequence;
+ }
+
+ /**
+ * Determines whether this phase passes the gate for whether deactivation (PreDestroy) can be called.
+ *
+ * @return true if this phase is eligible to be included in shutdown processing.
+ *
+ * @see PicoServices#shutdown()
+ */
+ public boolean eligibleForDeactivation() {
+ return eligibleForDeactivation;
+ }
+
+ ActivationPhase(int value, boolean eligibleForDeactivation) {
+ this.sequence = value;
+ this.eligibleForDeactivation = eligibleForDeactivation;
+ }
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationResult.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationResult.java
new file mode 100644
index 00000000000..2bb8098d8cc
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationResult.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.Future;
+
+import io.helidon.pico.builder.api.Builder;
+
+/**
+ * Represents the result of a service activation or deactivation.
+ *
+ * @see Activator
+ * @see DeActivator
+ *
+ * @param The type of the associated activator
+ */
+@Builder
+public interface ActivationResult {
+
+ /**
+ * The service provider undergoing activation or deactivation.
+ *
+ * @return the service provider generating the result
+ */
+ ServiceProvider serviceProvider();
+
+ /**
+ * Optionally, given by the implementation provider to indicate the future completion when the provider's
+ * {@link ActivationStatus} is {@link ActivationStatus#WARNING_SUCCESS_BUT_NOT_READY}.
+ *
+ * @return the future result, assuming how activation can be async in nature
+ */
+ Optional>> finishedActivationResult();
+
+ /**
+ * The activation phase that was found at onset of the phase transition.
+ *
+ * @return the starting phase
+ */
+ ActivationPhase startingActivationPhase();
+
+ /**
+ * The activation phase that was requested at the onset of the phase transition.
+ *
+ * @return the target, desired, ultimate phase requested
+ */
+ ActivationPhase ultimateTargetActivationPhase();
+
+ /**
+ * The activation phase we finished successfully on.
+ *
+ * @return the actual finishing phase
+ */
+ ActivationPhase finishingActivationPhase();
+
+ /**
+ * How did the activation finish.
+ *
+ * @return the finishing status
+ */
+ ActivationStatus finishingStatus();
+
+ /**
+ * The containing activation log that tracked this result.
+ *
+ * @return the activation log
+ */
+ Optional activationLog();
+
+ /**
+ * The services registry that was used.
+ *
+ * @return the services registry
+ */
+ Optional services();
+
+ /**
+ * Any vendor/provider implementation specific codes.
+ *
+ * @return the status code, 0 being the normal/default value
+ */
+ int statusCode();
+
+ /**
+ * Any vendor/provider implementation specific description.
+ *
+ * @return a developer friendly description (useful if an error occurs)
+ */
+ Optional statusDescription();
+
+ /**
+ * Any throwable/exceptions that were observed during activation.
+ *
+ * @return the captured error
+ */
+ Optional error();
+
+ /**
+ * Returns true if this result is finished.
+ *
+ * @return true if finished
+ */
+ default boolean finished() {
+ Future> f = finishedActivationResult().orElse(null);
+ return (Objects.isNull(f) || f.isDone());
+ }
+
+ /**
+ * Returns true if this result is successful.
+ *
+ * @return true if successful
+ */
+ default boolean success() {
+ return success(finishingStatus());
+ }
+
+ /**
+ * Returns true if the provided result status was successful (i.e., not {@link io.helidon.pico.spi.ActivationStatus#FAILURE}).
+ *
+ * @param status the activation result status
+ * @return true if successful
+ */
+ static boolean success(ActivationStatus status) {
+ return (ActivationStatus.FAILURE != status);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ActivationStatus.java b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationStatus.java
new file mode 100644
index 00000000000..f50fb3b4796
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ActivationStatus.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+/**
+ * The activation status. This status applies to the {@link io.helidon.pico.spi.ActivationLogEntry} record.
+ *
+ * @see Activator
+ */
+public enum ActivationStatus {
+
+ /**
+ * The service has been activated and is fully ready to receive requests.
+ */
+ SUCCESS,
+
+ /**
+ * The service has been activated but is still being started asynchronously, and is not fully ready yet to receive requests.
+ * Important note: This is NOT health related. Health is orthogonal to service bindings/activation and readiness.
+ */
+ WARNING_SUCCESS_BUT_NOT_READY,
+
+ /**
+ * A general warning during lifecycle.
+ */
+ WARNING_GENERAL,
+
+ /**
+ * Failed to activate to the given phase.
+ */
+ FAILURE
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Activator.java b/pico/spi/src/main/java/io/helidon/pico/spi/Activator.java
new file mode 100644
index 00000000000..ab5b7d8037a
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Activator.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * Activators are responsible for lifecycle creation and lazy activation of service providers. They are responsible for taking the
+ * {@link ServiceProvider}'s manage service instance from {@link ActivationPhase#PENDING}
+ * through {@link ActivationPhase#POST_CONSTRUCTING} (i.e., including any
+ * {@link PostConstructMethod} invocations, etc.), and finally into
+ * {@link ActivationPhase#ACTIVE} status. In Helidon's Pico reference implementation that additionally means this occurs avoiding
+ * the use of reflection at runtime.
+ *
+ * Assumption:
+ *
+ *
Each {@link ServiceProvider} managing its backing service will have an activator strategy conforming to the DI
+ * specification.
+ *
Each services activation is expected to be non-blocking, but may in fact require deferred blocking activities to become
+ * fully ready for runtime operation.
+ *
+ * Activation includes:
+ *
+ *
Management of the service's {@link ActivationPhase}.
+ *
Control over creation (i.e., invoke the ctor non-reflectively).
+ *
Control over gathering the service requisite dependencies (ctor, field, setters) and optional activation of those.
+ *
Invocation of any {@link PostConstructMethod}.
+ *
Responsible to logging to the {@link ActivationLog} - see {@link PicoServices#activationLog()}.
+ *
+ *
+ * @param the managed service type being activated
+ * @see DeActivator
+ */
+@Contract
+public interface Activator {
+
+ /**
+ * Activate a managed service/provider.
+ *
+ * @param targetServiceProvider the target service provider
+ * @param ipInfoCtx the optional injection point context
+ * @param ultimateTargetPhase the desired target phase for activation
+ * @param throwOnFailure should the provider throw if an error is observed, alternatively will return a result with an
+ * error inside
+ * @return the result of the activation
+ */
+ ActivationResult activate(ServiceProvider targetServiceProvider,
+ InjectionPointInfo ipInfoCtx,
+ ActivationPhase ultimateTargetPhase,
+ boolean throwOnFailure);
+
+ /**
+ * Activate a managed service/provider.
+ *
+ * @param targetServiceProvider the target service provider
+ * @param ipInfoCtx the optional injection point context
+ * @param ultimateTargetPhase the desired target phase for activation
+ * @return the result of the activation
+ */
+ default ActivationResult activate(ServiceProvider targetServiceProvider,
+ InjectionPointInfo ipInfoCtx,
+ ActivationPhase ultimateTargetPhase) {
+ return activate(targetServiceProvider, ipInfoCtx, ultimateTargetPhase, true);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Application.java b/pico/spi/src/main/java/io/helidon/pico/spi/Application.java
new file mode 100644
index 00000000000..40e10989739
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Application.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * An Application instance, if available at runtime, will be expected to provide a blueprint for all service provider's injection
+ * points.
+ *
+ * Note: instances of this type are not eligible for injection.
+ *
+ * @see io.helidon.pico.spi.Module
+ */
+@Contract
+public interface Application extends Named {
+
+ /**
+ * Called by the provider implementation at bootstrapping time to bind all injection plans to each and every service provider.
+ *
+ * @param binder the binder used to register the service provider injection plans
+ */
+ void configure(ServiceInjectionPlanBinder binder);
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/DeActivator.java b/pico/spi/src/main/java/io/helidon/pico/spi/DeActivator.java
new file mode 100644
index 00000000000..609597da8f0
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/DeActivator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * DeActivators are responsible for lifecycle, transitioning a {@link ServiceProvider}'s from its current phase through any
+ * {@link jakarta.annotation.PreDestroy} method invocations, and into the
+ * {@link ActivationPhase#DESTROYED} phase. These are inverse agents of {@link Activator}.
+ *
+ * @param the type to deactivate
+ * @see io.helidon.pico.spi.Activator
+ */
+@Contract
+public interface DeActivator {
+
+ /**
+ * Deactivate a managed service. This will trigger any {@link jakarta.annotation.PreDestroy} method on the
+ * underlying service type instance.
+ *
+ * @param targetServiceProvider the service provider responsible for calling deactivate
+ * @param throwOnFailure indicates whether the provider should throw if an error is observed
+ * @return the result
+ */
+ ActivationResult deactivate(ServiceProvider targetServiceProvider,
+ boolean throwOnFailure);
+
+ /**
+ * Deactivate a managed service. This will trigger any {@link jakarta.annotation.PreDestroy} method on the
+ * underlying service type instance.
+ *
+ * @param targetServiceProvider the service provider responsible for calling deactivate
+ * @return the result
+ */
+ default ActivationResult deactivate(ServiceProvider targetServiceProvider) {
+ return deactivate(targetServiceProvider, true);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/DefaultQualifierAndValue.java b/pico/spi/src/main/java/io/helidon/pico/spi/DefaultQualifierAndValue.java
new file mode 100644
index 00000000000..9d1d42dc5ab
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/DefaultQualifierAndValue.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.Objects;
+
+import io.helidon.pico.types.AnnotationAndValue;
+import io.helidon.pico.types.DefaultAnnotationAndValue;
+import io.helidon.pico.types.DefaultTypeName;
+import io.helidon.pico.types.TypeName;
+
+import jakarta.inject.Named;
+
+/**
+ * Describes a {@link jakarta.inject.Qualifier} type annotation associated with a service being provided or dependant upon.
+ * In the Helidon Pico framework these are generally determined at compile time to avoid any use of reflection in runtime.
+ */
+public class DefaultQualifierAndValue extends DefaultAnnotationAndValue
+ implements QualifierAndValue, Comparable {
+
+ /**
+ * Represents a {@link jakarta.inject.Named} type name with no value.
+ */
+ public static final TypeName NAMED = DefaultTypeName.create(Named.class);
+
+ /**
+ * Represents a wildcard {@link #NAMED} qualifier.
+ */
+ public static final QualifierAndValue WILDCARD_NAMED = DefaultQualifierAndValue.createNamed("*");
+
+ /**
+ * Ctor.
+ *
+ * @param b the builder
+ * @see #builder()
+ */
+ protected DefaultQualifierAndValue(Builder b) {
+ super(b);
+ }
+
+ /**
+ * Creates a {@link jakarta.inject.Named} qualifier.
+ *
+ * @param name the name
+ * @return named qualifier
+ */
+ public static DefaultQualifierAndValue createNamed(String name) {
+ return (DefaultQualifierAndValue) builder().typeName(NAMED).value(name).build();
+ }
+
+ /**
+ * Creates a qualifier from an annotation.
+ *
+ * @param qualifierType the qualifier type
+ * @return qualifier
+ */
+ public static DefaultQualifierAndValue create(Class extends Annotation> qualifierType) {
+ return (DefaultQualifierAndValue) builder().typeName(DefaultTypeName.create(qualifierType)).build();
+ }
+
+ /**
+ * Creates a qualifier.
+ *
+ * @param qualifierType the qualifier type
+ * @param val the value
+ * @return qualifier
+ */
+ public static DefaultQualifierAndValue create(Class extends Annotation> qualifierType, String val) {
+ return (DefaultQualifierAndValue) builder().typeName(DefaultTypeName.create(qualifierType)).value(val).build();
+ }
+
+ /**
+ * Creates a qualifier.
+ *
+ * @param qualifierTypeName the qualifier
+ * @param val the value
+ * @return qualifier
+ */
+ public static DefaultQualifierAndValue create(String qualifierTypeName, String val) {
+ return create(DefaultTypeName.createFromTypeName(qualifierTypeName), val);
+ }
+
+ /**
+ * Creates a qualifier.
+ *
+ * @param qualifierType the qualifier
+ * @param val the value
+ * @return qualifier
+ */
+ public static DefaultQualifierAndValue create(TypeName qualifierType, String val) {
+ return (DefaultQualifierAndValue) builder()
+ .typeName(qualifierType)
+ .value(val)
+ .build();
+ }
+
+ /**
+ * Converts from a named contextual qualifier (e.g., {@link jakarta.inject.Named}).
+ *
+ * @param qualifierTypeName the qualifier
+ * @param values the values
+ * @return qualifier
+ */
+ public static DefaultQualifierAndValue create(TypeName qualifierTypeName, Map values) {
+ return (DefaultQualifierAndValue) builder()
+ .typeName(qualifierTypeName)
+ .values(values)
+ .build();
+ }
+
+ /**
+ * Converts from an {@link io.helidon.pico.types.AnnotationAndValue} to a {@link io.helidon.pico.spi.QualifierAndValue}.
+ *
+ * @param annotationAndValue the annotation and value
+ * @return the qualifier and value equivalent
+ */
+ public static QualifierAndValue convert(AnnotationAndValue annotationAndValue) {
+ if (annotationAndValue instanceof QualifierAndValue) {
+ return (QualifierAndValue) annotationAndValue;
+ }
+
+ DefaultAnnotationAndValue from = (DefaultAnnotationAndValue) annotationAndValue;
+ if (Objects.nonNull(annotationAndValue.values()) && !annotationAndValue.values().isEmpty()) {
+ return create(annotationAndValue.typeName(), from.values());
+ }
+
+ return create(annotationAndValue.typeName(), annotationAndValue.value().orElse(null));
+ }
+
+ @Override
+ public int compareTo(AnnotationAndValue other) {
+ return typeName().compareTo(other.typeName());
+ }
+
+
+ /**
+ * Creates a builder for {@link io.helidon.pico.spi.QualifierAndValue}.
+ *
+ * @return a fluent builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+
+ /**
+ * The fluent builder.
+ */
+ public static class Builder extends DefaultAnnotationAndValue.Builder {
+ /**
+ * Ctor.
+ */
+ protected Builder() {
+ }
+
+ /**
+ * Build the instance.
+ *
+ * @return the built instance
+ */
+ @Override
+ public DefaultQualifierAndValue build() {
+ return new DefaultQualifierAndValue(this);
+ }
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/DefaultServiceInfo.java b/pico/spi/src/main/java/io/helidon/pico/spi/DefaultServiceInfo.java
new file mode 100644
index 00000000000..a30d453deb3
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/DefaultServiceInfo.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import io.helidon.pico.types.AnnotationAndValue;
+
+/**
+ * The default/reference implementation for {@link ServiceInfo}.
+ */
+public class DefaultServiceInfo implements ServiceInfo {
+ private final String serviceTypeName;
+ private final Set contractsImplemented;
+ private final Set externalContractsImplemented;
+ private final Set scopeTypeNames;
+ private final Set qualifiers;
+ private final String activatorTypeName;
+ private final Integer runLevel;
+ private final Double weight;
+ private String moduleName;
+
+ /**
+ * Copy ctor.
+ *
+ * @param src the source to copy
+ */
+ protected DefaultServiceInfo(ServiceInfo src) {
+ this.serviceTypeName = src.serviceTypeName();
+ this.contractsImplemented = new TreeSet<>(src.contractsImplemented());
+ this.externalContractsImplemented = new LinkedHashSet<>(src.externalContractsImplemented());
+ this.scopeTypeNames = new LinkedHashSet<>(src.scopeTypeNames());
+ this.qualifiers = new LinkedHashSet<>(src.qualifiers());
+ this.activatorTypeName = src.activatorTypeName();
+ this.runLevel = src.runLevel();
+ this.moduleName = src.moduleName().orElse(null);
+ this.weight = src.declaredWeight().orElse(null);
+ }
+
+ /**
+ * Builder ctor.
+ *
+ * @param b the builder
+ * @see #builder()
+ */
+ @SuppressWarnings("unchecked")
+ protected DefaultServiceInfo(Builder b) {
+ this.serviceTypeName = b.serviceTypeName;
+ this.contractsImplemented = Objects.isNull(b.contractsImplemented)
+ ? Collections.emptySet() : Collections.unmodifiableSet(new TreeSet(b.contractsImplemented));
+ this.externalContractsImplemented = Objects.isNull(b.externalContractsImplemented)
+ ? Collections.emptySet() : Collections.unmodifiableSet(b.externalContractsImplemented);
+ this.scopeTypeNames = Objects.isNull(b.scopeTypeNames)
+ ? Collections.emptySet() : Collections.unmodifiableSet(b.scopeTypeNames);
+ this.qualifiers = Objects.isNull(b.qualifiers)
+ ? Collections.emptySet() : Collections.unmodifiableSet(b.qualifiers);
+ this.activatorTypeName = b.activatorTypeName;
+ this.runLevel = b.runLevel;
+ this.moduleName = b.moduleName;
+ this.weight = b.weight;
+ }
+
+ @Override
+ public Set externalContractsImplemented() {
+ return externalContractsImplemented;
+ }
+
+ @Override
+ public String activatorTypeName() {
+ return activatorTypeName;
+ }
+
+ @Override
+ public Optional moduleName() {
+ return Optional.ofNullable(moduleName);
+ }
+
+ @Override
+ public String serviceTypeName() {
+ return serviceTypeName;
+ }
+
+ @Override
+ public Set scopeTypeNames() {
+ return scopeTypeNames;
+ }
+
+ @Override
+ public Set qualifiers() {
+ return qualifiers;
+ }
+
+ @Override
+ public Set contractsImplemented() {
+ return contractsImplemented;
+ }
+
+ @Override
+ public Integer runLevel() {
+ return runLevel;
+ }
+
+ @Override
+ public Optional declaredWeight() {
+ return Optional.ofNullable(weight);
+ }
+
+
+ @Override
+ public int hashCode() {
+ if (Objects.isNull(serviceTypeName)) {
+ return Objects.hashCode(contractsImplemented());
+ }
+
+ return Objects.hashCode(serviceTypeName()) ^ Objects.hashCode(contractsImplemented());
+ }
+
+ @Override
+ public boolean equals(Object another) {
+ if (Objects.isNull(another) || !(another instanceof ServiceInfo)) {
+ return false;
+ }
+
+ return equals(serviceTypeName(), ((ServiceInfo) another).serviceTypeName())
+ && equals(contractsImplemented(), ((ServiceInfo) another).contractsImplemented())
+ && equals(qualifiers(), ((ServiceInfo) another).qualifiers())
+ && equals(activatorTypeName(), ((ServiceInfo) another).activatorTypeName())
+ && equals(runLevel(), ((ServiceInfo) another).runLevel())
+ && equals(realizedWeight(), ((ServiceInfo) another).realizedWeight())
+ && equals(moduleName(), ((ServiceInfo) another).moduleName());
+ }
+
+ /**
+ * Provides a facade over {@link java.util.Objects#equals(Object, Object)}.
+ *
+ * @param o1 an object
+ * @param o2 an object to compare with a1 for equality
+ * @return true if a1 equals a2
+ */
+ public static boolean equals(Object o1, Object o2) {
+ return Objects.equals(o1, o2);
+ }
+
+ /**
+ * Set/override the module name for this service info. Generally this is only called internally by the framework.
+ *
+ * @param moduleName the module name
+ */
+ public void moduleName(String moduleName) {
+ this.moduleName = moduleName;
+ }
+
+ /**
+ * Matches is a looser form of equality check than {@link #equals(Object, Object)}. If a service matches criteria
+ * it is generally assumed to be viable for assignability.
+ *
+ * @param criteria the criteria to compare against
+ * @return true if the criteria provided matches this instance
+ * @see io.helidon.pico.spi.Services#lookup(ServiceInfo)
+ */
+ @Override
+ public boolean matches(ServiceInfo criteria) {
+ return matches(this, criteria);
+ }
+
+ /**
+ * Matches is a looser form of equality check than {@link #equals(Object, Object)}. If a service matches criteria
+ * it is generally assumed to be viable for assignability.
+ *
+ * @param src the target service info to evaluate
+ * @param criteria the criteria to compare against
+ * @return true if the criteria provided matches this instance
+ * @see io.helidon.pico.spi.Services#lookup(ServiceInfo)
+ */
+ protected static boolean matches(ServiceInfo src, ServiceInfo criteria) {
+ if (Objects.isNull(criteria)) {
+ return true;
+ }
+
+ boolean matches = matches(src.serviceTypeName(), criteria.serviceTypeName());
+ if (matches && Objects.isNull(criteria.serviceTypeName())) {
+ matches = matches(src.contractsImplemented(), criteria.contractsImplemented())
+ || matches(src.serviceTypeName(), criteria.contractsImplemented());
+ }
+ return matches
+ && matches(src.scopeTypeNames(), criteria.scopeTypeNames())
+ && matchesQualifiers(src.qualifiers(), criteria.qualifiers())
+ && matches(src.activatorTypeName(), criteria.activatorTypeName())
+ && matches(src.runLevel(), criteria.runLevel())
+ && matchesWeight(src, criteria.declaredWeight().orElse(null))
+ && matches(src.moduleName(), criteria.moduleName());
+ }
+
+ /**
+ * Matches qualifier collections.
+ *
+ * @param src the target service info to evaluate
+ * @param criteria the criteria to compare against
+ * @return true if the criteria provided matches this instance
+ */
+ public static boolean matchesQualifiers(Set src, Set criteria) {
+ if (criteria.isEmpty()) {
+ return true;
+ }
+
+ if (src.isEmpty()) {
+ return false;
+ }
+
+ if (src.contains(DefaultQualifierAndValue.WILDCARD_NAMED)) {
+ return true;
+ }
+
+ for (QualifierAndValue criteriaQualifier : criteria) {
+ if (src.contains(criteriaQualifier)) {
+ // NOP;
+ continue;
+ } else if (criteriaQualifier.typeName().equals(DefaultQualifierAndValue.NAMED)) {
+ if (criteriaQualifier.equals(DefaultQualifierAndValue.WILDCARD_NAMED)
+ || criteriaQualifier.value().isEmpty()) {
+ // any Named qualifier will match ...
+ boolean hasSameTypeAsCriteria = src.stream()
+ .anyMatch(q -> q.typeName().equals(criteriaQualifier.typeName()));
+ if (hasSameTypeAsCriteria) {
+ continue;
+ }
+ } else if (src.contains(DefaultQualifierAndValue.WILDCARD_NAMED)) {
+ continue;
+ }
+ return false;
+ } else if (criteriaQualifier.value().isEmpty()) {
+ Set sameTypeAsCriteriaSet = src.stream()
+ .filter(q -> q.typeName().equals(criteriaQualifier.typeName()))
+ .collect(Collectors.toSet());
+ if (sameTypeAsCriteriaSet.isEmpty()) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Weight matching is always less than any criteria specified.
+ *
+ * @param src the item being considered
+ * @param criteria the criteria
+ *
+ * @return true if there is a match
+ */
+ protected static boolean matchesWeight(ServiceInfoBasics src, Double criteria) {
+ if (Objects.isNull(criteria)) {
+ return matches(src.declaredWeight().orElse(null), criteria);
+ }
+ Double srcWeight = weightOf(src);
+ return (srcWeight.compareTo(criteria) < 0);
+ }
+
+ /**
+ * Resolves the literal weight of a {@link io.helidon.pico.spi.ServiceInfoBasics} that is passed.
+ *
+ * @param src the weight to calculate for
+ * @return the weight of the service info argument
+ */
+ public static double weightOf(ServiceInfoBasics src) {
+ return Objects.isNull(src) ? DEFAULT_WEIGHT : src.realizedWeight();
+ }
+
+ private static boolean matches(Set> src, Set> criteria) {
+ if (Objects.isNull(criteria) || criteria.isEmpty()) {
+ return true;
+ }
+
+ if (Objects.isNull(src)) {
+ return false;
+ }
+
+ return src.containsAll(criteria);
+ }
+
+ private static boolean matches(String src, Set criteria) {
+ if (Objects.isNull(criteria)) {
+ return true;
+ }
+
+ if (Objects.isNull(src)) {
+ return false;
+ }
+
+ return criteria.contains(src);
+ }
+
+ private static boolean matches(Object src, Object criteria) {
+ if (Objects.isNull(criteria)) {
+ return true;
+ }
+
+ return equals(src, criteria);
+ }
+
+ /**
+ * Clone a service info and wrap it using {@link DefaultServiceInfo}.
+ *
+ * @param src the target to clone
+ * @return the cloned copy of the provided service info
+ */
+ public static DefaultServiceInfo cloneCopy(ServiceInfo src) {
+ if (Objects.isNull(src)) {
+ return null;
+ }
+
+ return new DefaultServiceInfo(src);
+ }
+
+ /**
+ * Constructs an instance of {@link DefaultServiceInfo} with the provided serviceInfo that
+ * describes the instance provided.
+ *
+ * @param instance the instance provided
+ * @param serviceInfo the service info that describes the instance provided
+ * @return the {@link DefaultServiceInfo} instance that identifies the service instance and info
+ */
+ public static DefaultServiceInfo toServiceInfo(Object instance, ServiceInfo serviceInfo) {
+ if (Objects.nonNull(serviceInfo)) {
+ return cloneCopy(serviceInfo);
+ }
+ return DefaultServiceInfo.builder()
+ .serviceTypeName(instance.getClass().getName())
+ .build();
+ }
+
+ /**
+ * Constructs an instance of {@link DefaultServiceInfo} given a service type class and some
+ * basic information that describes the service type.
+ *
+ * @param serviceType the service type
+ * @param siBasics the basic information that describes the service type
+ * @return an instance of {@link DefaultServiceInfo}
+ */
+ public static DefaultServiceInfo toServiceInfoFromClass(Class> serviceType, ServiceInfoBasics siBasics) {
+ if (siBasics instanceof DefaultServiceInfo) {
+ assert (serviceType.getName().equals(siBasics.serviceTypeName()));
+ return (DefaultServiceInfo) siBasics;
+ }
+
+ if (Objects.isNull(siBasics)) {
+ return DefaultServiceInfo.builder()
+ .serviceTypeName(serviceType.getName())
+ .build();
+ }
+
+ return DefaultServiceInfo.builder()
+ .serviceTypeName(serviceType.getName())
+ .scopeTypeNames(siBasics.scopeTypeNames())
+ .contractsImplemented(siBasics.contractsImplemented())
+ .qualifiers(siBasics.qualifiers())
+ .runLevel(siBasics.runLevel())
+ .weight(siBasics.declaredWeight().orElse(null))
+ .build();
+ }
+
+
+ /**
+ * Creates a fluent builder for this type.
+ *
+ * @return A builder for {@link io.helidon.pico.spi.DefaultServiceInfo}.
+ */
+ @SuppressWarnings("unchecked")
+ public static Builder extends DefaultServiceInfo, ? extends Builder, ?>> builder() {
+ return new Builder();
+ }
+
+ /**
+ * Creates a fluent builder initialized with the current values of this instance.
+ *
+ * @return A builder initialized with the current attributes.
+ */
+ @SuppressWarnings("unchecked")
+ public Builder extends DefaultServiceInfo, ? extends Builder, ?>> toBuilder() {
+ return new Builder(this);
+ }
+
+
+ /**
+ * The fluent builder for {@link ServiceInfo}.
+ *
+ * @param the builder type
+ * @param the concrete type being build
+ */
+ public static class Builder> {
+ private String serviceTypeName;
+ private Set contractsImplemented;
+ private Set externalContractsImplemented;
+ private Set scopeTypeNames;
+ private Set qualifiers;
+ private String activatorTypeName;
+ private Integer runLevel;
+ private String moduleName;
+ private Double weight;
+
+ /**
+ * Ctor.
+ *
+ * @see #builder()
+ */
+ protected Builder() {
+ }
+
+ /**
+ * Ctor.
+ *
+ * @param c the existing value object
+ * @see #toBuilder()
+ */
+ protected Builder(C c) {
+ this.serviceTypeName = c.serviceTypeName();
+ this.contractsImplemented = new LinkedHashSet<>(c.contractsImplemented());
+ this.externalContractsImplemented = new LinkedHashSet<>(c.externalContractsImplemented());
+ this.scopeTypeNames = new LinkedHashSet<>(c.scopeTypeNames());
+ this.qualifiers = new LinkedHashSet<>(c.qualifiers());
+ this.activatorTypeName = c.activatorTypeName();
+ this.runLevel = c.runLevel();
+ this.moduleName = c.moduleName().orElse(null);
+ this.weight = c.declaredWeight().orElse(null);
+ }
+
+ /**
+ * Builds the {@link io.helidon.pico.spi.DefaultServiceInfo}.
+ *
+ * @return the fluent builder instance
+ */
+ @SuppressWarnings("unchecked")
+ public C build() {
+ return (C) new DefaultServiceInfo(this);
+ }
+
+ @SuppressWarnings("unchecked")
+ private B identity() {
+ return (B) this;
+ }
+
+ /**
+ * Sets the mandatory serviceTypeName for this {@link ServiceInfo}.
+ *
+ * @param serviceTypeName the service type name
+ * @return this fluent builder
+ */
+ public B serviceTypeName(String serviceTypeName) {
+ this.serviceTypeName = serviceTypeName;
+ return identity();
+ }
+
+ /**
+ * Sets the mandatory serviceTypeName for this {@link ServiceInfo}.
+ *
+ * @param serviceType the service type
+ * @return this fluent builder
+ */
+ public B serviceType(Class> serviceType) {
+ return serviceTypeName(serviceType.getName());
+ }
+
+ /**
+ * Sets the optional name for this {@link ServiceInfo}.
+ *
+ * @param name the name
+ * @return this fluent builder
+ */
+ public B named(String name) {
+ return Objects.isNull(name) ? identity() : qualifier(DefaultQualifierAndValue.createNamed(name));
+ }
+
+ /**
+ * Adds a singular qualifier for this {@link ServiceInfo}.
+ *
+ * @param qualifier the qualifier
+ * @return this fluent builder
+ */
+ public B qualifier(QualifierAndValue qualifier) {
+ if (Objects.nonNull(qualifier)) {
+ if (Objects.isNull(qualifiers)) {
+ qualifiers = new LinkedHashSet<>();
+ }
+ qualifiers.add(qualifier);
+ }
+ return identity();
+ }
+
+ /**
+ * Sets the collection of qualifiers for this {@link ServiceInfo}.
+ *
+ * @param qualifiers the qualifiers
+ * @return this fluent builder
+ */
+ public B qualifiers(Collection qualifiers) {
+ this.qualifiers = Objects.isNull(qualifiers)
+ ? null : new LinkedHashSet<>(qualifiers);
+ return identity();
+ }
+
+ /**
+ * Adds a singular contract implemented for this {@link ServiceInfo}.
+ *
+ * @param contractImplemented the contract implemented
+ * @return this fluent builder
+ */
+ public B contractImplemented(String contractImplemented) {
+ if (Objects.nonNull(contractImplemented)) {
+ if (Objects.isNull(contractsImplemented)) {
+ contractsImplemented = new LinkedHashSet<>();
+ }
+ contractsImplemented.add(contractImplemented);
+ }
+ return identity();
+ }
+
+ /**
+ * Adds a contract implemented.
+ *
+ * @param contract the contract type
+ * @return this fluent builder
+ */
+ public B contractTypeImplemented(Class> contract) {
+ return contractImplemented(contract.getName());
+ }
+
+ /**
+ * Sets the collection of contracts implemented for this {@link ServiceInfo}.
+ *
+ * @param contractsImplemented the contract names implemented
+ * @return this fluent builder
+ */
+ public B contractsImplemented(Collection contractsImplemented) {
+ this.contractsImplemented = Objects.isNull(contractsImplemented)
+ ? null : new LinkedHashSet<>(contractsImplemented);
+ return identity();
+ }
+
+ /**
+ * Adds a singular external contract implemented for this {@link ServiceInfo}.
+ *
+ * @param contractImplemented the type name of the external contract implemented
+ * @return this fluent builder
+ */
+ public B externalContractImplemented(String contractImplemented) {
+ if (Objects.nonNull(contractImplemented)) {
+ if (Objects.isNull(this.externalContractsImplemented)) {
+ this.externalContractsImplemented = new LinkedHashSet<>();
+ }
+ this.externalContractsImplemented.add(contractImplemented);
+ }
+ return contractImplemented(contractImplemented);
+ }
+
+ /**
+ * Adds an external contract implemented.
+ *
+ * @param contract the external contract type
+ * @return this fluent builder
+ */
+ public B externalContractTypeImplemented(Class> contract) {
+ return externalContractImplemented(contract.getName());
+ }
+
+ /**
+ * Sets the collection of contracts implemented for this {@link ServiceInfo}.
+ *
+ * @param contractsImplemented the external contract names implemented
+ * @return this fluent builder
+ */
+ public B externalContractsImplemented(Collection contractsImplemented) {
+ this.externalContractsImplemented = Objects.isNull(contractsImplemented)
+ ? null : new LinkedHashSet<>(contractsImplemented);
+ return identity();
+ }
+
+ /**
+ * Adds a singular scope type name for this {@link ServiceInfo}.
+ *
+ * @param scopeTypeName the scope type name
+ * @return this fluent builder
+ */
+ public B scopeTypeName(String scopeTypeName) {
+ if (Objects.nonNull(scopeTypeName)) {
+ if (Objects.isNull(this.scopeTypeNames)) {
+ this.scopeTypeNames = new LinkedHashSet<>();
+ }
+ this.scopeTypeNames.add(scopeTypeName);
+ }
+ return identity();
+ }
+
+ /**
+ * Sets the scope type.
+ *
+ * @param scopeType the scope type
+ * @return this fluent builder
+ */
+ public B scopeType(Class> scopeType) {
+ return scopeTypeName(scopeType.getName());
+ }
+
+ /**
+ * sets the collection of scope type names declared for this {@link ServiceInfo}.
+ *
+ * @param scopeTypeNames the contract names implemented
+ * @return this fluent builder
+ */
+ public B scopeTypeNames(Collection scopeTypeNames) {
+ this.scopeTypeNames = Objects.isNull(scopeTypeNames)
+ ? null : new LinkedHashSet<>(scopeTypeNames);
+ return identity();
+ }
+
+ /**
+ * Sets the activator type name.
+ *
+ * @param activatorTypeName the activator type name
+ * @return this fluent builder
+ */
+ public B activatorTypeName(String activatorTypeName) {
+ this.activatorTypeName = activatorTypeName;
+ return identity();
+ }
+
+ /**
+ * Sets the activator type.
+ *
+ * @param activatorType the activator type
+ * @return this fluent builder
+ */
+ public B activatorType(Class> activatorType) {
+ return activatorTypeName(activatorType.getName());
+ }
+
+ /**
+ * Sets the run level value.
+ *
+ * @param runLevel the run level
+ * @return this fluent builder
+ */
+ public B runLevel(Integer runLevel) {
+ this.runLevel = runLevel;
+ return identity();
+ }
+
+ /**
+ * Sets the module name value.
+ *
+ * @param moduleName the module name
+ * @return this fluent builder
+ */
+ public B moduleName(String moduleName) {
+ this.moduleName = moduleName;
+ return identity();
+ }
+
+ /**
+ * Sets the weight value.
+ *
+ * @param weight the weight (aka priority)
+ * @return this fluent builder
+ */
+ public B weight(Double weight) {
+ this.weight = weight;
+ return identity();
+ }
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/DependenciesInfo.java b/pico/spi/src/main/java/io/helidon/pico/spi/DependenciesInfo.java
new file mode 100644
index 00000000000..994ed22f69a
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/DependenciesInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents a per {@link ServiceInfo} mapping of {@link DependencyInfo}'s.
+ */
+public interface DependenciesInfo {
+
+ /**
+ * Represents the set of dependencies for each {@link ServiceInfo}.
+ *
+ * @return map from the service info to its dependencies
+ */
+ Map> serviceInfoDependencies();
+
+ /**
+ * Represents a flattened list of all dependencies.
+ *
+ * @return the flattened list of all dependencies
+ */
+ List extends DependencyInfo> allDependencies();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/DependencyInfo.java b/pico/spi/src/main/java/io/helidon/pico/spi/DependencyInfo.java
new file mode 100644
index 00000000000..3f4229c0347
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/DependencyInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Set;
+
+import io.helidon.pico.builder.api.Builder;
+
+/**
+ * Aggregates the set of {@link io.helidon.pico.spi.InjectionPointInfo}'s that are dependent upon a specific
+ * {@link io.helidon.pico.spi.ServiceInfo}.
+ */
+@Builder
+public interface DependencyInfo {
+
+ /**
+ * The service info describing what the injection point dependencies are dependent upon.
+ *
+ * @return the service info dependency
+ */
+ ServiceInfo dependencyTo();
+
+ /**
+ * The set of injection points that depends upon {@link #dependencyTo()}.
+ *
+ * @return the set of dependencies
+ */
+ Set extends InjectionPointInfo> injectionPointDependencies();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/ElementInfo.java b/pico/spi/src/main/java/io/helidon/pico/spi/ElementInfo.java
new file mode 100644
index 00000000000..e72b8b6fcc7
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/ElementInfo.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+import java.util.Set;
+
+import io.helidon.pico.builder.api.Builder;
+import io.helidon.pico.types.AnnotationAndValue;
+
+/**
+ * Abstractly describes method or field elements of a managed service type (i.e., fields, constructors, injectable methods, etc.).
+ */
+@Builder
+public interface ElementInfo {
+
+ /**
+ * The name assigned to constructors.
+ */
+ String CTOR = "";
+
+ /**
+ * The kind of injection target.
+ */
+ enum ElementKind {
+ /**
+ * The injectable constructor. Note that there can be at most 1 injectable constructor.
+ */
+ CTOR,
+
+ /**
+ * A field.
+ */
+ FIELD,
+
+ /**
+ * A method.
+ */
+ METHOD
+ }
+
+ /**
+ * The access describing the target injection point.
+ */
+ enum Access {
+ /**
+ * public.
+ */
+ PUBLIC,
+
+ /**
+ * protected.
+ */
+ PROTECTED,
+
+ /**
+ * package private.
+ */
+ PACKAGE_PRIVATE,
+
+ /**
+ * private.
+ */
+ PRIVATE
+ }
+
+ /**
+ * The injection point/receiver kind.
+ *
+ * @return the kind
+ */
+ ElementKind elementKind();
+
+ /**
+ * The access modifier on the injection point/receiver.
+ *
+ * @return the access
+ */
+ Access access();
+
+ /**
+ * The element type name (e.g., method type or field type).
+ *
+ * @return the target receiver type name
+ */
+ String elementTypeName();
+
+ /**
+ * The element name (e.g., method name or field name).
+ *
+ * @return the target receiver name
+ */
+ String elementName();
+
+ /**
+ * If the element is a method or constructor then this is the ordinal argument position of that argument.
+ *
+ * @return the offset argument, 0 based, or empty if field type
+ */
+ Optional elementOffset();
+
+ /**
+ * True if the injection point is static.
+ *
+ * @return true if static receiver
+ */
+ boolean staticDecl();
+
+ /**
+ * The enclosing class name for the element.
+ *
+ * @return service type name
+ */
+ String serviceTypeName();
+
+ /**
+ * The annotations on this element.
+ *
+ * @return the annotations on this element
+ */
+ Set annotations();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/EventReceiver.java b/pico/spi/src/main/java/io/helidon/pico/spi/EventReceiver.java
new file mode 100644
index 00000000000..e641abbe7d5
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/EventReceiver.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+/**
+ * A receiver of events from the {@link Services} registry. Only {@link ServiceProvider}'s
+ * that are bound to the global service registry are capable of receiving events.
+ *
+ * @see io.helidon.pico.spi.ServiceProviderBindable
+ */
+public interface EventReceiver {
+
+ /**
+ * Events issued from the framework.
+ */
+ enum Event {
+
+ /**
+ * Called after all modules and services from those modules are initially loaded into the service registry.
+ */
+ POST_BIND_ALL_MODULES,
+
+ /**
+ * Called after {@link #POST_BIND_ALL_MODULES} to resolve any latent bindings, prior to {@link #SERVICES_READY}.
+ */
+ FINAL_RESOLVE,
+
+ /**
+ * The service registry is fully populated and ready.
+ */
+ SERVICES_READY
+
+ }
+
+ /**
+ * Called at the end of module and service bindings, when all the services in the service registry have been populated.
+ *
+ * @param event the event
+ */
+ void onEvent(Event event);
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InjectionException.java b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionException.java
new file mode 100644
index 00000000000..df930b9861f
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionException.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+
+/**
+ * Represents an injection exception. These might be thrown either at compile time or at runtime depending upon how the
+ * application is built.
+ */
+public class InjectionException extends PicoServiceProviderException {
+
+ private final Optional activationLog;
+
+ /**
+ * Injection, or a required service lookup related exception.
+ *
+ * @param msg the message
+ */
+ public InjectionException(String msg) {
+ this(msg, null, null);
+ }
+
+ /**
+ * Injection, or a required service lookup related exception.
+ *
+ * @param msg the message
+ * @param cause the root cause
+ * @param serviceProvider the service provider
+ */
+ public InjectionException(String msg, Throwable cause, ServiceProvider> serviceProvider) {
+ this(msg, cause, serviceProvider, Optional.empty());
+ }
+
+ /**
+ * Injection, or a required service lookup related exception.
+ *
+ * @param msg the message
+ * @param cause the root cause
+ * @param serviceProvider the service provider
+ * @param log the activity log
+ */
+ public InjectionException(String msg, Throwable cause, ServiceProvider> serviceProvider, Optional log) {
+ super(msg, cause, serviceProvider);
+ this.activationLog = log;
+ }
+
+ /**
+ * Returns the activation log if available.
+ *
+ * @return the optional activation log
+ */
+ public Optional activationLog() {
+ return activationLog;
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointInfo.java b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointInfo.java
new file mode 100644
index 00000000000..51c440e145d
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointInfo.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Set;
+
+import io.helidon.pico.builder.api.Builder;
+
+/**
+ * Describes a receiver for injection - identifies who/what is requesting an injection that needs to be satisfied.
+ */
+@Builder
+public interface InjectionPointInfo extends ElementInfo {
+
+ /**
+ * The identifying name for this injection point. The identity should be unique for the service type it is contained within.
+ *
+ * This method will return the {@link #baseIdentity()} when {@link #elementOffset()} is null. If not null
+ * then the elemOffset is part of the returned identity.
+ *
+ * @return the unique identity
+ */
+ String identity();
+
+ /**
+ * The base identifying name for this injection point. If the element represents a function, then the function arguments
+ * are encoded in its base identity.
+ *
+ * @return the base identity of the element
+ */
+ String baseIdentity();
+
+ /**
+ * The qualifiers on this element.
+ *
+ * @return The qualifiers on this element.
+ */
+ Set qualifiers();
+
+ /**
+ * True if the injection point is of type {@link java.util.List}.
+ *
+ * @return true if list based receiver
+ */
+ boolean listWrapped();
+
+ /**
+ * True if the injection point is of type {@link java.util.Optional}.
+ *
+ * @return true if optional based receiver
+ */
+ boolean optionalWrapped();
+
+ /**
+ * True if the injection point is of type Provider (or Supplier).
+ *
+ * @return true if provider based receiver
+ */
+ boolean providerWrapped();
+
+ /**
+ * The dependency this is dependent upon.
+ *
+ * @return The service info we are dependent upon.
+ */
+ ServiceInfo dependencyToServiceInfo();
+
+ /**
+ * Creates a pre-configured instance with an identity and a service type dependency.
+ *
+ * @param identity the identity
+ * @param dependencyToServiceInfo the service type dependency
+ * @return the created instance
+ */
+ static DefaultInjectionPointInfo create(String identity,
+ ServiceInfo dependencyToServiceInfo) {
+ return DefaultInjectionPointInfo.builder()
+ .identity(identity)
+ .dependencyToServiceInfo(dependencyToServiceInfo)
+ .build();
+ }
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointProvider.java b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointProvider.java
new file mode 100644
index 00000000000..6481e6da910
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InjectionPointProvider.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import jakarta.inject.Provider;
+
+/**
+ * Provides ability to contextualize the injected service by the target receiver of the injection point dynamically
+ * at runtime.
+ *
+ * @param the type that the provider produces
+ */
+public interface InjectionPointProvider extends Provider {
+
+ /**
+ * Get (or create) an instance of this service type.
+ */
+ @Override
+ default T get() {
+ return get(null, null, true);
+ }
+
+ /**
+ * Get (or create) an instance of this service type - tailored upon its scope and the target (but optional) injection point / context.
+ *
+ * @param ipInfoCtx optionally, the injection point context if known
+ * @param criteria optionally, the service info required by the injection point context if known
+ * @param expected the flag indicating whether the injection point is required to be furnished
+ * @return the resolved service best matching the criteria for the injection point in terms of weight, or null if the context is not supported
+ */
+ T get(InjectionPointInfo ipInfoCtx, ServiceInfo criteria, boolean expected);
+
+ /**
+ * Get (or create) a list of instance of this service type - tailored upon its scope and the target (but optional) injection point / context.
+ *
+ * @param ipInfoCtx optionally, the injection point context if known -
+ * @param criteria optionally, the service info required by the injection point context if known
+ * @param expected the flag indicating whether the injection point is required to be furnished
+ * @return the resolved services matching criteria for the injection point in order of weight, or null if the context is not supported
+ */
+ default List getList(InjectionPointInfo ipInfoCtx, ServiceInfo criteria, boolean expected) {
+ T instance = get(ipInfoCtx, criteria, expected);
+ return (Objects.isNull(instance)) ? null : Collections.singletonList(instance);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Injector.java b/pico/spi/src/main/java/io/helidon/pico/spi/Injector.java
new file mode 100644
index 00000000000..3075499804e
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Injector.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Used to perform programmatic activation and injection.
+ *
+ * Note that the reference implementation of Pico only performs non-reflective, compile-time generation of service activators
+ * for services that it manages. This Injector contract is mainly provided in order to allow other library extensions /
+ * implementations to extend the model to perform other types of injection point resolution.
+ */
+public interface Injector {
+
+ /**
+ * The strategy the injector should attempt to apply. The reference implementation for Pico provider only handles
+ * {@link io.helidon.pico.spi.Injector.Strategy#ACTIVATOR} type.
+ */
+ enum Strategy {
+ /**
+ * Activator based implies compile-time injection strategy. This is the preferred / default strategy.
+ */
+ ACTIVATOR,
+
+ /**
+ * Reflection based implies runtime injection strategy. Note: This is available for other 3rd parties of Pico that choose
+ * to use reflection as a strategy.
+ */
+ REFLECTION,
+
+ /**
+ * Any. Defers the strategy to the provider implementation's capabilities and configuration.
+ */
+ ANY
+ }
+
+ /**
+ * Called to activate and inject a manage service instance or service provider, putting it into
+ * {@link ActivationPhase#ACTIVE}.
+ *
+ * Note that if a {@link ServiceProvider} is passed in then the {@link Activator}
+ * will be used instead. In this case, then any {@link InjectorOptions#startAtPhase()} and
+ * {@link InjectorOptions#finishAtPhase()} arguments will be ignored.
+ *
+ * @param serviceOrServiceProvider the target instance or service provider being activated and injected
+ * @param opts the optional injector options
+ * @param resultHolder the optional holder to receive the activation results, or null to have the provider throw
+ * {@link InjectionException}
+ * @param the managed service instance type
+ * @return the same instance passed in, activated, or else null if an error occurred
+ * @throws InjectionException if an injection problem occurs
+ * @see Activator
+ */
+ T activateInject(T serviceOrServiceProvider,
+ Optional opts,
+ Optional>> resultHolder) throws InjectionException;
+
+ /**
+ * Called to deactivate a managed service or service provider, putting it into {@link ActivationPhase#DESTROYED}.
+ * If a managed service has a {@link jakarta.annotation.PreDestroy} annotated method then it will be called during
+ * this lifecycle event.
+ *
+ * Note that if a {@link ServiceProvider} is passed in then the {@link DeActivator}
+ * will be used instead. In this case, then any {@link InjectorOptions#startAtPhase()} and
+ * {@link InjectorOptions#finishAtPhase()} arguments will be ignored.
+ *
+ * @param serviceOrServiceProvider the service provider or instance registered and being managed
+ * @param opts the optional injector options
+ * @param the managed service instance type
+ * @return the result of the deactivation
+ * @see DeActivator
+ */
+ ActivationResult deactivate(T serviceOrServiceProvider,
+ Optional opts) throws InjectionException;
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InjectorOptions.java b/pico/spi/src/main/java/io/helidon/pico/spi/InjectorOptions.java
new file mode 100644
index 00000000000..c00fad716ad
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InjectorOptions.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+
+import io.helidon.pico.builder.api.Builder;
+
+/**
+ * Provides optional, contextual tunings to the {@link Injector}.
+ *
+ * @see Injector
+ */
+@Builder
+public interface InjectorOptions {
+
+ /**
+ * The optional starting phase for the {@link Activator} behind the {@link Injector}.
+ * The default is the current phase that the managed {@link io.helidon.pico.spi.ServiceProvider} is currently in.
+ *
+ * @return the optional target finish phase
+ */
+ Optional startAtPhase();
+
+ /**
+ * The optional target finishing phase for the {@link Activator} behind the {@link Injector}.
+ * The default is {@link ActivationPhase#ACTIVE}.
+ *
+ * @return the optional target finish phase
+ */
+ Optional finishAtPhase();
+
+ /**
+ * The optional recipient target, describing who and what is being injected.
+ *
+ * @return the optional target injection point info
+ */
+ Optional ipInfo();
+
+ /**
+ * The optional services registry to use, defaulting to {@link PicoServices#services()}.
+ *
+ * @return the optional services registry to use
+ */
+ Optional services();
+
+ /**
+ * The optional activation log that the injection should record its activity on.
+ *
+ * @return the optional activation log to use
+ */
+ Optional log();
+
+ /**
+ * The optional injection strategy the injector should apply. The default is {@link Injector.Strategy#ANY}.
+ *
+ * @return the optional injector strategy to use
+ */
+ Optional strategy();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Intercepted.java b/pico/spi/src/main/java/io/helidon/pico/spi/Intercepted.java
new file mode 100644
index 00000000000..3e1df788575
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Intercepted.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Qualifier;
+
+/**
+ * Indicates that type identified by {@link #value()} is being intercepted.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Qualifier
+@Target(java.lang.annotation.ElementType.TYPE)
+public @interface Intercepted {
+
+ /**
+ * The target being intercepted.
+ *
+ * @return the target class being intercepted
+ */
+ Class> value();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InterceptedTrigger.java b/pico/spi/src/main/java/io/helidon/pico/spi/InterceptedTrigger.java
new file mode 100644
index 00000000000..3e6c7048146
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InterceptedTrigger.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Meta-annotation that when used will trigger the enclosing service type marked with this annotation to become intercepted.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface InterceptedTrigger {
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Interceptor.java b/pico/spi/src/main/java/io/helidon/pico/spi/Interceptor.java
new file mode 100644
index 00000000000..927b8738838
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Interceptor.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * Implementors of this contract must be {@link jakarta.inject.Named} according to the {@link Intercepted}
+ * annotation they support.
+ */
+@Contract
+public interface Interceptor {
+
+ /**
+ * Called during interception of the target V. The implementation typically should finish with the call to
+ * {@link Interceptor.Chain#proceed()}.
+ *
+ * @param ctx the invocation context
+ * @param chain the chain to call proceed on
+ * @param the return value type (or {@link java.lang.Void} for void method elements)
+ * @return the return value to the caller
+ */
+ V proceed(InvocationContext ctx, Chain chain);
+
+
+ /**
+ * Represents the next in line for interception, terminating with a call to the wrapped service provider.
+ *
+ * @param the return value
+ */
+ interface Chain {
+ /**
+ * Call the next interceptor in line, or finishing with the call to the service provider.
+ *
+ * @return the result of the call.
+ */
+ V proceed();
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InvocationContext.java b/pico/spi/src/main/java/io/helidon/pico/spi/InvocationContext.java
new file mode 100644
index 00000000000..87273e586c2
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InvocationContext.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.List;
+import java.util.Map;
+
+import io.helidon.pico.types.AnnotationAndValue;
+import io.helidon.pico.types.TypeName;
+import io.helidon.pico.types.TypedElementName;
+
+/**
+ * Used by {@link io.helidon.pico.spi.Interceptor}.
+ */
+public interface InvocationContext {
+
+ /**
+ * The root service provider being intercepted.
+ *
+ * @return the root service provider being intercepted
+ */
+ ServiceProvider> rootServiceProvider();
+
+ /**
+ * The service type name for the root service provider.
+ *
+ * @return the service type name for the root service provider
+ */
+ TypeName serviceTypeName();
+
+ /**
+ * The annotations on the enclosing type.
+ *
+ * @return the annotations on the enclosing type
+ */
+ List classAnnotations();
+
+ /**
+ * The element info represents the method (or the constructor) being invoked.
+ *
+ * @return the element info represents the method (or the constructor) being invoked
+ */
+ TypedElementName elementInfo();
+
+ /**
+ * The method/element argument info.
+ *
+ * @return the method/element argument info.
+ */
+ TypedElementName[] elementArgInfo();
+
+ /**
+ * The arguments to the method.
+ *
+ * @return the read/write method/element arguments
+ */
+ Object[] elementArgs();
+
+ /**
+ * The contextual info that can be shared between interceptors.
+ *
+ * @return the read/write contextual data that is passed between each chained interceptor
+ */
+ Map contextData();
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/InvocationException.java b/pico/spi/src/main/java/io/helidon/pico/spi/InvocationException.java
new file mode 100644
index 00000000000..87fc2ddafd4
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/InvocationException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+/**
+ * Wraps any checked exceptions that are thrown during the {@link Interceptor} invocations.
+ */
+public class InvocationException extends PicoServiceProviderException {
+
+ /**
+ * Ctor.
+ *
+ * @param msg the message
+ * @param cause the root cause
+ * @param serviceProvider the service provider
+ */
+ public InvocationException(String msg, Throwable cause, ServiceProvider> serviceProvider) {
+ super(msg, cause, serviceProvider);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Module.java b/pico/spi/src/main/java/io/helidon/pico/spi/Module.java
new file mode 100644
index 00000000000..5983fad31f9
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Module.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * Provides aggregation of services to the "containing" (jar) module.
+ * Modules can be provided explicitly by the developer, or automatically if using a pico apt processor during compile time.
+ *
+ * Note: instances of this type are not eligible for injection.
+ *
+ * @see Application
+ */
+@Contract
+public interface Module extends Named {
+
+ /**
+ * Called by the provider implementation at bootstrapping time to bind all services / service providers to the
+ * service registry.
+ *
+ * @param binder the binder used to register the services to the registry
+ */
+ void configure(ServiceBinder binder);
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/Named.java b/pico/spi/src/main/java/io/helidon/pico/spi/Named.java
new file mode 100644
index 00000000000..163d69f4070
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/Named.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Optional;
+
+/**
+ * Provides a means to identify if the instance is named.
+ *
+ * @see jakarta.inject.Named
+ */
+public interface Named {
+
+ /**
+ * The optional name for this instance.
+ *
+ * @return the name associated with this instance or empty if not available or known.
+ */
+ default Optional name() {
+ return Optional.empty();
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/PicoException.java b/pico/spi/src/main/java/io/helidon/pico/spi/PicoException.java
new file mode 100644
index 00000000000..2be4df116e1
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/PicoException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+/**
+ * A general purpose exception.
+ *
+ * @see PicoServiceProviderException
+ * @see InjectionException
+ * @see InvocationException
+ */
+public class PicoException extends RuntimeException {
+
+ /**
+ * A general purpose exception from Pico.
+ *
+ * @param msg the message
+ */
+ public PicoException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * A general purpose exception from Pico.
+ *
+ * @param msg the message
+ * @param cause the root cause
+ */
+ public PicoException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/PicoServiceProviderException.java b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServiceProviderException.java
new file mode 100644
index 00000000000..64745d6f037
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServiceProviderException.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A general purpose exception from Pico.
+ */
+public class PicoServiceProviderException extends PicoException {
+
+ private final ServiceProvider> serviceProvider;
+
+ /**
+ * A general purpose exception from Pico.
+ *
+ * @param msg the message
+ */
+ public PicoServiceProviderException(String msg) {
+ super(msg);
+ this.serviceProvider = null;
+ }
+
+ /**
+ * A general purpose exception from Pico.
+ *
+ * @param msg the message
+ * @param cause the root cause
+ * @param serviceProvider the service provider
+ */
+ public PicoServiceProviderException(String msg, Throwable cause, ServiceProvider> serviceProvider) {
+ super(msg, cause);
+ if (Objects.isNull(serviceProvider)) {
+ if (cause instanceof PicoServiceProviderException) {
+ serviceProvider = ((PicoServiceProviderException) cause).getServiceProvider().orElse(null);
+ }
+ }
+ this.serviceProvider = serviceProvider;
+ }
+
+ /**
+ * The service provider that this exception pertains to, or empty if not related to any particular provider.
+ *
+ * @return the optional / contextual service provider
+ */
+ public Optional> getServiceProvider() {
+ return Optional.ofNullable(serviceProvider);
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage()
+ + (Objects.isNull(serviceProvider)
+ ? "" : (": service provider: " + ServiceProvider.toDescription(serviceProvider)));
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/PicoServices.java b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServices.java
new file mode 100644
index 00000000000..c029259fc75
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServices.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.Future;
+
+import io.helidon.common.Weighted;
+
+/**
+ * Abstract factory for all services provided by a single Helidon Pico provider implementation.
+ * An implementation of this interface must minimally supply a "services registry" - see {@link #services()}.
+ */
+public interface PicoServices extends Weighted {
+
+ /**
+ * Get {@link PicoServices} instance if available. The highest {@link io.helidon.common.Weighted} service will be loaded
+ * and returned.
+ *
+ * @return Pico services instance
+ */
+ static Optional picoServices() {
+ return PicoServicesHolder.picoServices();
+ }
+
+ /**
+ * The service registry.
+ *
+ * @return the services registry
+ */
+ Services services();
+
+ /**
+ * Creates a service binder instance for a specified module.
+ *
+ * @param module the module to offer binding to dynamically, and typically only at early startup initialization
+ *
+ * @return the service binder capable of binding, or empty if not permitted/available
+ */
+ default Optional createServiceBinder(Module module) {
+ return Optional.empty();
+ }
+
+ /**
+ * Optionally, the injector.
+ *
+ * @return the injector, or empty if not available
+ */
+ default Optional extends Injector> injector() {
+ return Optional.empty();
+ }
+
+ /**
+ * Optionally, the service providers' configuration.
+ *
+ * @return the config, or empty if not available
+ */
+ default Optional extends PicoServicesConfig> config() {
+ return Optional.empty();
+ }
+
+ /**
+ * Attempts to perform a graceful {@link io.helidon.pico.spi.Injector#deactivate(Object, java.util.Optional)} on all managed
+ * service instances in the {@link io.helidon.pico.spi.Services} registry. Since deactivation can take some time to
+ * complete, a future is returned that can be used for tracking purposes. A dedicated thread is started to manage the
+ * deactivation/shutdown procedure for all active services in the registry.
+ *
+ * If the service provider does not support shutdown an empty is returned.
+ *
+ * The default reference implementation for Pico will return a map of all service types that were deactivated to any
+ * throwable that was observed during that services shutdown sequence.
+ *
+ * The order in which services are deactivated is dependent upon whether the {@link #activationLog()} is available.
+ * If the activation log is available, then services will be shutdown in reverse chronological order as how they
+ * were started. If the activation log is not enabled or found to be empty then the deactivation will be in reverse
+ * order of {@link io.helidon.pico.api.RunLevel} from the highest value down to the lowest value. If two services share
+ * the same {@link io.helidon.pico.api.RunLevel} value then the ordering will be based upon the implementation's comparator.
+ *
+ * Note that the service registry is NOT prevented from usage during or after shutdown. This means that it is possible
+ * for services to still be in an active state in the service registry even after shutdown is completed. If this is
+ * of concern then the recommendation is for the caller to repeatedly call shutdown() until the map contents are empty.
+ *
+ * @return a future of a map of all managed service types deactivated to any throwable observed during deactivation
+ */
+ default Optional>>> shutdown() {
+ return Optional.empty();
+ }
+
+ /**
+ * Optionally, the service provider activation log.
+ *
+ * @return the injector, or empty if not available
+ */
+ default Optional activationLog() {
+ return Optional.empty();
+ }
+
+}
diff --git a/pico/spi/src/main/java/io/helidon/pico/spi/PicoServicesConfig.java b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServicesConfig.java
new file mode 100644
index 00000000000..2a17affac73
--- /dev/null
+++ b/pico/spi/src/main/java/io/helidon/pico/spi/PicoServicesConfig.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2022 Oracle 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 io.helidon.pico.spi;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import io.helidon.pico.api.Contract;
+
+/**
+ * Provides optional config by the provider implementation.
+ */
+@Contract
+public interface PicoServicesConfig {
+ /**
+ * The short name for pico.
+ */
+ String NAME = "pico";
+
+ /**
+ * The fully qualified name for pico (used for system properties, etc).
+ */
+ String FQN = "io.helidon." + NAME;
+
+ /**
+ * The key association with the name of the provider implementation.
+ */
+ String KEY_PROVIDER = FQN + ".provider";
+ /**
+ * The key association with the version of the provider implementation.
+ */
+ String KEY_VERSION = FQN + ".version";
+
+ /**
+ * Applicable during activation, this is the key that controls the timeout before deadlock detection errors being thrown.
+ */
+ String KEY_DEADLOCK_TIMEOUT_IN_MILLIS = FQN + ".deadlock.timeout.millis";
+ /**
+ * The default deadlock detection timeout in millis.
+ */
+ Long DEFAULT_DEADLOCK_TIMEOUT_IN_MILLIS = 10000L;
+
+ /**
+ * Applicable for capturing activation logs.
+ */
+ String KEY_ACTIVATION_LOGS_ENABLED = FQN + ".activation.logs.enabled";
+ /**
+ * The default value for this is false, meaning that the activation logs will not be recorded or logged.
+ */
+ Boolean DEFAULT_ACTIVATION_LOGS_ENABLED = false;
+
+ /**
+ * The key that models the services registry, and whether the registry can expand dynamically after program startup.
+ */
+ String KEY_SUPPORTS_DYNAMIC = FQN + ".supports.dynamic";
+ /**
+ * The default value for this is false, meaning that the services registry cannot be changed during runtime.
+ */
+ Boolean DEFAULT_SUPPORTS_DYNAMIC = false;
+
+ /**
+ * The key that represents whether the provider support reflection, and reflection based activation/injection.
+ */
+ String KEY_SUPPORTS_REFLECTION = FQN + ".supports.reflection";
+ /**
+ * The default value for this is false, meaning no reflection is available or provided in the implementation.
+ */
+ Boolean DEFAULT_SUPPORTS_REFLECTION = false;
+
+ /**
+ * Can the provider support compile-time activation/injection (i.e., {@link Activator}'s)?
+ */
+ String KEY_SUPPORTS_COMPILE_TIME = FQN + ".supports.compiletime";
+ /**
+ * The default value is true, meaning injection points are evaluated at compile-time.
+ */
+ Boolean DEFAULT_SUPPORTS_COMPILE_TIME = true;
+
+ /**
+ * Can the services registry activate services in a thread-safe manner?
+ */
+ String KEY_SUPPORTS_THREAD_SAFE_ACTIVATION = FQN + ".supports.threadsafe.activation";
+ /**
+ * The default is true, meaning the implementation is (or should be) thread safe.
+ */
+ Boolean DEFAULT_SUPPORTS_THREAD_SAFE_ACTIVATION = true;
+
+ /**
+ * The key to represent whether the provider support and is compliant w/ Jsr-330.
+ */
+ String KEY_SUPPORTS_JSR330 = FQN + ".supports.jsr330";
+ /**
+ * The default value is true.
+ */
+ Boolean DEFAULT_SUPPORTS_JSR330 = true;
+
+ /**
+ * Can the injector / activator support static injection? Note: this is optional in Jsr-330
+ */
+ String KEY_SUPPORTS_JSR330_STATIC = FQN + ".supports.jsr330.static";
+ /**
+ * The default value is false.
+ */
+ Boolean DEFAULT_SUPPORTS_STATIC = false;
+ /**
+ * Can the injector / activator support private injection? Note: this is optional in Jsr-330
+ */
+ String KEY_SUPPORTS_JSR330_PRIVATE = FQN + ".supports.jsr330.private";
+ /**
+ * The default value is false.
+ */
+ Boolean DEFAULT_SUPPORTS_PRIVATE = false;
+
+ /**
+ * Indicates whether the {@link io.helidon.pico.spi.Module}(s) should be read at startup. The default value is true.
+ */
+ String KEY_BIND_MODULES = FQN + ".bind.modules";
+ /**
+ * The default value is true.
+ */
+ Boolean DEFAULT_BIND_MODULES = true;
+
+ /**
+ * Indicates whether the {@link io.helidon.pico.spi.Application}(s) should be used as an optimization at startup to
+ * avoid lookups. The default value is true.
+ */
+ String KEY_BIND_APPLICATION = FQN + ".bind.application";
+ /**
+ * The default value is true.
+ */
+ Boolean DEFAULT_BIND_APPLICATION = true;
+
+ /**
+ * Supports a query mechanism to determine if properties are available/set.
+ *
+ * @param the type for the config value
+ * @param key the key to query for config
+ * @param defaultValueSupplier the default value
+ * @return the configuration value for the associated key, or else the default value supplied
+ */
+ T value(String key, Supplier defaultValueSupplier);
+
+ /**
+ * Return a string-type key value.
+ *
+ * @param key the key
+ * @return the value, or null if no key is found
+ */
+ default String stringValue(String key) {
+ Object val = value(key, null);
+ return Objects.nonNull(val) ? val.toString() : null;
+ }
+
+ /**
+ * Supports a properties-based mechanism to determine configuration.
+ *
+ * @return all properties in this configuration
+ */
+ default Optional