    001// Copyright 2006-2014 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.internal.services;
    016
    017import org.apache.tapestry5.commons.util.AvailableValues;
    018import org.apache.tapestry5.commons.util.CollectionFactory;
    019import org.apache.tapestry5.commons.util.UnknownValueException;
    020import org.apache.tapestry5.func.F;
    021import org.apache.tapestry5.func.Mapper;
    022import org.apache.tapestry5.func.Predicate;
    023import org.apache.tapestry5.ioc.internal.util.OneShotLock;
    024import org.apache.tapestry5.services.Environment;
    025
    026import java.util.LinkedList;
    027import java.util.List;
    028import java.util.Map;
    029import java.util.Map.Entry;
    030
    031/**
    032 * A non-threadsafe implementation (expects to use the "perthread" service lifecyle).
    033 */
    034public class EnvironmentImpl implements Environment
    035{
    036
    037    // My generics mojo breaks down when we talk about the key and the value being related
    038    // types.
    039
    040    private Map<Class, LinkedList> typeToStack = CollectionFactory.newMap();
    041
    042    private final OneShotLock lock = new OneShotLock();
    043
    044    @SuppressWarnings("unchecked")
    045    private <T> LinkedList<T> stackFor(Class<T> type)
    046    {
    047        lock.check();
    048
    049        LinkedList<T> result = typeToStack.get(type);
    050
    051        if (result == null)
    052        {
    053            result = CollectionFactory.newLinkedList();
    054            typeToStack.put(type, result);
    055        }
    056
    057        return result;
    058    }
    059
    060    public <T> T peek(Class<T> type)
    061    {
    062        LinkedList<T> stack = stackFor(type);
    063
    064        return stack.isEmpty() ? null : stack.getFirst();
    065    }
    066
    067    public <T> T peekRequired(Class<T> type)
    068    {
    069        T result = peek(type);
    070
    071        if (result == null)
    072        {
    073            List<Class> types = CollectionFactory.newList();
    074            for (Map.Entry<Class, LinkedList> e : typeToStack.entrySet())
    075            {
    076                LinkedList list = e.getValue();
    077
    078                if (list != null && !list.isEmpty())
    079                    types.add(e.getKey());
    080            }
    081
    082            throw new UnknownValueException(String.format("No object of type %s is available from the Environment.", type.getName()),
    083                    new AvailableValues("Environmentals",
    084                            F.flow(typeToStack.entrySet()).remove(new Predicate<Entry<Class, LinkedList>>()
    085                            {
    086                                public boolean accept(Entry<Class, LinkedList> element)
    087                                {
    088                                    return element.getValue().isEmpty();
    089                                }
    090                            }).map(new Mapper<Entry<Class, LinkedList>, String>()
    091                            {
    092                                public String map(Entry<Class, LinkedList> element)
    093                                {
    094                                    return element.getKey().getName();
    095                                }
    096                            }).toList()));
    097        }
    098
    099        return result;
    100    }
    101
    102    public <T> T pop(Class<T> type)
    103    {
    104        LinkedList<T> stack = stackFor(type);
    105
    106        return stack.removeFirst();
    107    }
    108
    109    public <T> T push(Class<T> type, T instance)
    110    {
    111        LinkedList<T> stack = stackFor(type);
    112
    113        T result = stack.isEmpty() ? null : stack.getFirst();
    114
    115        stack.addFirst(instance);
    116
    117        return result;
    118    }
    119
    120    public void threadDidCleanup()
    121    {
    122        lock.lock();
    123    }
    124
    125    public void cloak()
    126    {
    127        throw new UnsupportedOperationException("cloak() is no longer available in Tapestry 5.4.");
    128    }
    129
    130    public void decloak()
    131    {
    132        throw new UnsupportedOperationException("decloak() is no longer available in Tapestry 5.4.");
    133    }
    134}