001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     vpasquier <vpasquier@nuxeo.com>
016 *     slacoin <slacoin@nuxeo.com>
017 */
018package org.nuxeo.ecm.automation.test;
019
020import java.util.HashMap;
021import java.util.Map;
022
023import com.google.inject.Key;
024import com.google.inject.OutOfScopeException;
025import com.google.inject.Provider;
026import com.google.inject.Scope;
027
028/**
029 * @since 5.7.3
030 */
031public class AutomationScope implements Scope {
032
033    public final static AutomationScope INSTANCE = new AutomationScope();
034
035    protected final ThreadLocal<Map<Key<?>, Object>> values = new ThreadLocal<Map<Key<?>, Object>>() {
036        protected Map<Key<?>, Object> initialValue() {
037            return new HashMap<Key<?>, Object>();
038        };
039    };
040
041    protected AutomationScope() {;
042    }
043
044    public void enter() {
045        values.get();
046    }
047
048    public void exit() {
049        values.remove();
050    }
051
052    @Override
053    public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
054        return new Provider<T>() {
055
056            @Override
057            public T get() {
058                Map<Key<?>, Object> scopedMap = getScopedObjectMap(key);
059                @SuppressWarnings("unchecked")
060                T current = (T) scopedMap.get(key);
061                if (current == null && !scopedMap.containsKey(key)) {
062                    current = unscoped.get();
063                    scopedMap.put(key, current);
064                }
065                return current;
066            }
067
068        };
069    }
070
071    private <T> Map<Key<?>, Object> getScopedObjectMap(Key<T> key) {
072        Map<Key<?>, Object> scopedObjects = values.get();
073        if (scopedObjects == null) {
074            throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block");
075        }
076        return scopedObjects;
077    }
078
079}