    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
    015    package org.apache.tapestry5.ioc.internal;
    016
    017    import org.apache.tapestry5.ioc.Invokable;
    018    import org.apache.tapestry5.ioc.OperationTracker;
    019    import org.apache.tapestry5.ioc.internal.util.JDKUtils;
    020    import org.slf4j.Logger;
    021
    022    import java.util.concurrent.locks.Lock;
    023
    024    /**
    025     * Manages a per-thread OperationTracker using a ThreadLocal.
    026     */
    027    public 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    }