001//  Copyright 2008, 2009, 2011 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.ioc.internal;
016
017import org.apache.tapestry5.ioc.Invokable;
018import org.apache.tapestry5.ioc.OperationTracker;
019import org.apache.tapestry5.ioc.internal.util.JDKUtils;
020import org.slf4j.Logger;
021
022import java.util.concurrent.locks.Lock;
023
024/**
025 * Manages a per-thread OperationTracker using a ThreadLocal.
026 */
027public class PerThreadOperationTracker implements OperationTracker
028{
029    private final Logger logger;
030
031    private final Lock lock = JDKUtils.createLockForThreadLocalCreation();
032
033    private final ThreadLocal<OperationTrackerImpl> perThread = new ThreadLocal<OperationTrackerImpl>()
034    {
035        @Override
036        protected OperationTrackerImpl initialValue()
037        {
038            return new OperationTrackerImpl(logger);
039        }
040    };
041
042    public PerThreadOperationTracker(Logger logger)
043    {
044        this.logger = logger;
045    }
046
047    OperationTracker get()
048    {
049        lock.lock();
050
051        try
052        {
053            return perThread.get();
054        } finally
055        {
056            lock.unlock();
057        }
058    }
059
060    void cleanup()
061    {
062        try
063        {
064            lock.lock();
065            if (perThread.get().isEmpty()) perThread.remove();
066        } finally
067        {
068            lock.unlock();
069        }
070    }
071
072    public void run(String description, Runnable operation)
073    {
074        try
075        {
076            get().run(description, operation);
077        } finally
078        {
079            cleanup();
080        }
081    }
082
083    public <T> T invoke(String description, Invokable<T> operation)
084    {
085        try
086        {
087            return get().invoke(description, operation);
088        } finally
089        {
090            cleanup();
091        }
092    }
093}