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.func.F; 018import org.apache.tapestry5.func.Mapper; 019import org.apache.tapestry5.func.Predicate; 020import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 021import org.apache.tapestry5.ioc.internal.util.OneShotLock; 022import org.apache.tapestry5.ioc.util.AvailableValues; 023import org.apache.tapestry5.ioc.util.UnknownValueException; 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}