blob: ae82c07ad6ab8ed78162926883838057d09c7dcd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.tamaya.spi;
import javax.annotation.Priority;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* This class models the component that is managing the lifecycle current the
* services used by the Configuration API.
*/
public interface ServiceContext extends ClassloaderAware{
/**
* True if the {@link Priority} annotation class is available on the classpath.
*/
boolean PRIORITY_ANNOTATION_AVAILABLE = checkPriorityAnnotation(ServiceContextManager.getDefaultClassLoader());
/**
* Checks if the {@link Priority} annotation class is on the classpath.
* @param classLoader the target classloader, not null.
* @return true, if the annotation is loaded.
*/
static boolean checkPriorityAnnotation(ClassLoader classLoader) {
try{
Class.forName("javax.annotation.Priority", true, classLoader);
return true;
}catch(Exception e){
return false;
}
}
/**
* Get the ordinal of the ServiceContext.
* @return ordinal of the ServiceContext. The one with the highest ordinal will be taken.
*/
default int ordinal(){
return getPriority(this);
}
/**
* Checks the given instance for a @Priority annotation. If present the annotation's value is evaluated. If no such
* annotation is present, a default priority of {@code 1} is returned.
* @param o the instance, not {@code null}.
* @return a priority, by default 1.
*/
static int getPriority(Object o){
int prio = 1;
if(PRIORITY_ANNOTATION_AVAILABLE) {
Priority priority = o.getClass().getAnnotation(Priority.class);
if (priority != null) {
prio = priority.value();
}
}
return prio;
}
/**
* Access a service singleton via its type.
* If multiple implementations for the very serviceType exist then
* the one with the highest {@link javax.annotation.Priority} will be used.
*
* @param <T> the type of the service type.
* @param serviceType the service type.
* @return The instance to be used, or {@code null}
* @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority.
*/
default <T> T getService(Class<T> serviceType){
return getService(serviceType, null);
}
/**
* Access a service singleton via its type.
* If multiple implementations for the very serviceType exist then
* the one with the highest {@link javax.annotation.Priority} will be used.
*
* @param <T> the type of the service type.
* @param serviceType the service type.
* @param supplier the supplier to be used, if no services could be evaluated. If null,
* an empty collection is returned, when no services
* could be located.
* @return The instance to be used, or {@code null}
* @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority.
*/
<T> T getService(Class<T> serviceType, Supplier<T> supplier);
/**
* Factory method to createObject a type, hereby a new instance is created on each access.
* If multiple implementations for the very serviceType exist then
* the one with the highest {@link javax.annotation.Priority} will be used as the base
* for creating subsequent instances.
*
* @param <T> the type of the service type.
* @param serviceType the service type.
* @return The new instance to be used, or {@code null}
* @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority.
*/
default <T> T create(Class<T> serviceType){
return create(serviceType, null);
}
/**
* Factory method to createObject a type, hereby a new instance is created on each access.
* If multiple implementations for the very serviceType exist then
* the one with the highest {@link javax.annotation.Priority} will be used as the base
* for creating subsequent instances.
*
* @param supplier the supplier to create a new service, if no service could be autodetected.
* @param <T> the type of the service type.
* @param serviceType the service type.
* @return The new instance to be used, or {@code null}
* @throws org.apache.tamaya.ConfigException if there are multiple service implementations with the maximum priority.
*/
<T> T create(Class<T> serviceType, Supplier<T> supplier);
/**
* Access a createList current services, given its type. The bootstrap mechanism should
* order the instance for precedence, hereby the most significant should be
* first in order.
*
* @param serviceType
* the service type.
* @param <T> the type of the createList element returned by this method
* @return The instance to be used, never {@code null}
*/
default <T> List<T> getServices(Class<T> serviceType){
return getServices(serviceType, null);
}
/**
* Access a createList current services, given its type. The bootstrap mechanism should
* order the instance for precedence, hereby the most significant should be
* first in order. If no instances could be found, the instances supplied by the
* supplier given are registered and used.
*
* @param serviceType
* the service type.
* @param <T> the type of the createList element returned by this method
* @param supplier the supplier to be used, if no services could be evaluated. If null,
* an empty collection is returned, when no services
* could be located.
* @return The instance to be used, never {@code null}
*/
<T> List<T> getServices(Class<T> serviceType, Supplier<List<T>> supplier);
/**
* Loads resources from the current runtime context. This method allows to use runtime
* specific code to load resources, e.g. within OSGI environments.
* @param resource the resource, not {@code null}.
* @return the resources found
* @throws IOException if load fails.
*/
default Collection<URL> getResources(String resource){
List<URL> urls = new ArrayList<>();
try {
Enumeration<URL> found = getClassLoader().getResources(resource);
while (found.hasMoreElements()) {
urls.add(found.nextElement());
}
}catch(Exception e){
Logger.getLogger(ServiceContext.class.getName())
.log(Level.FINEST, e, () -> "Failed to lookup resources: " + resource);
}
return urls;
}
/**
* Loads a resource from the current runtime context. This method allows to use runtime
* specific code to load a resource, e.g. within OSGI environments.
* @param resource the resource, not {@code null}.
* @return the resource found, or {@code null}.
*/
default URL getResource(String resource){
return getClassLoader().getResource(resource);
}
/**
* Registers the given instance as a singleton service for the given instance, if no
* instance already has been registered.
*
* @param type the type to register, not null.
* @param instance the instance, not null.
* @param <T> thy type.
* @param force if true, any existing instance will be replaced.
* @return the instance registered or already present.
*/
<T> T register(Class<T> type, T instance, boolean force);
/**
* Registers the given instancea as servicea for the given instance, if no
* * instance already has been registered.
* @param type the type to register, not null.
* @param instances the instancea, not null.
* @param <T> thy type.
* @param force if true, any existing instances will be replaced.
* @return the instances registered or already present.
*/
<T> List<T> register(Class<T> type, List<T> instances, boolean force);
/**
* Resets the current service context, removing all loaded services. This implicitly triggers a new load
* of the service context.
*/
void reset();
}