/* * * Copyright 2014 Netflix, Inc. * * 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 com.netflix.loadbalancer.reactive; import com.netflix.client.RetryHandler; import com.netflix.client.config.IClientConfig; import com.netflix.client.config.IClientConfigKey; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * A context object that is created at start of each load balancer execution * and contains certain meta data of the load balancer and mutable state data of * execution per listener per request. Each listener will get its own context * to work with. But it can also call {@link ExecutionContext#getGlobalContext()} to * get the shared context between all listeners. * * @author Allen Wang * */ public class ExecutionContext<T> { private final Map<String, Object> context; private final ConcurrentHashMap<Object, ChildContext<T>> subContexts; private final T request; private final IClientConfig requestConfig; private final RetryHandler retryHandler; private final IClientConfig clientConfig; private static class ChildContext<T> extends ExecutionContext<T> { private final ExecutionContext<T> parent; ChildContext(ExecutionContext<T> parent) { super(parent.request, parent.requestConfig, parent.clientConfig, parent.retryHandler, null); this.parent = parent; } @Override public ExecutionContext<T> getGlobalContext() { return parent; } } public ExecutionContext(T request, IClientConfig requestConfig, IClientConfig clientConfig, RetryHandler retryHandler) { this.request = request; this.requestConfig = requestConfig; this.clientConfig = clientConfig; this.context = new ConcurrentHashMap<String, Object>(); this.subContexts = new ConcurrentHashMap<Object, ChildContext<T>>(); this.retryHandler = retryHandler; } ExecutionContext(T request, IClientConfig requestConfig, IClientConfig clientConfig, RetryHandler retryHandler, ConcurrentHashMap<Object, ChildContext<T>> subContexts) { this.request = request; this.requestConfig = requestConfig; this.clientConfig = clientConfig; this.context = new ConcurrentHashMap<String, Object>(); this.subContexts = subContexts; this.retryHandler = retryHandler; } ExecutionContext<T> getChildContext(Object obj) { if (subContexts == null) { return null; } ChildContext<T> subContext = subContexts.get(obj); if (subContext == null) { subContext = new ChildContext<T>(this); ChildContext<T> old = subContexts.putIfAbsent(obj, subContext); if (old != null) { subContext = old; } } return subContext; } public T getRequest() { return request; } public Object get(String name) { return context.get(name); } public <S> S getClientProperty(IClientConfigKey<S> key) { S value; if (requestConfig != null) { value = requestConfig.get(key); if (value != null) { return value; } } value = clientConfig.get(key); return value; } public void put(String name, Object value) { context.put(name, value); } /** * @return The IClientConfig object used to override the client's default configuration * for this specific execution. */ public IClientConfig getRequestConfig() { return requestConfig; } /** * * @return The shared context for all listeners. */ public ExecutionContext<T> getGlobalContext() { return this; } public RetryHandler getRetryHandler() { return retryHandler; } }