001// Copyright 2008, 2010, 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.internal.services; 016 017import org.apache.tapestry5.commons.services.InvalidationEventHub; 018import org.apache.tapestry5.commons.services.InvalidationListener; 019import org.apache.tapestry5.commons.services.PlasticProxyFactory; 020import org.apache.tapestry5.commons.services.TypeCoercer; 021import org.apache.tapestry5.commons.util.CollectionFactory; 022import org.apache.tapestry5.internal.plastic.PlasticInternalUtils; 023import org.apache.tapestry5.ioc.annotations.ComponentClasses; 024import org.apache.tapestry5.ioc.annotations.ComponentLayer; 025import org.apache.tapestry5.ioc.annotations.PostInjection; 026 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.List; 030import java.util.Map; 031import java.util.Map.Entry; 032 033public class ComponentClassCacheImpl implements ComponentClassCache 034{ 035 private final Map<String, Class> cache = CollectionFactory.newConcurrentMap(); 036 037 private final PlasticProxyFactory plasticFactory; 038 039 private final TypeCoercer typeCoercer; 040 041 public ComponentClassCacheImpl(@ComponentLayer 042 PlasticProxyFactory plasticFactory, TypeCoercer typeCoercer) 043 { 044 this.plasticFactory = plasticFactory; 045 this.typeCoercer = typeCoercer; 046 } 047 048 @PostInjection 049 public void setupInvalidation(@ComponentClasses InvalidationEventHub hub) { 050 hub.addInvalidationCallback(this::listen);; 051 } 052 053 @SuppressWarnings("rawtypes") 054 private List<String> listen(List<String> resources) 055 { 056 057 if (resources.isEmpty()) 058 { 059 cache.clear(); 060 } 061 else { 062 063 final Iterator<Entry<String, Class>> iterator = cache.entrySet().iterator(); 064 065 while (iterator.hasNext()) 066 { 067 final Entry<String, Class> entry = iterator.next(); 068 if (resources.contains(entry.getKey())) 069 { 070 iterator.remove(); 071 } 072 } 073 074 } 075 076 return Collections.emptyList(); 077 } 078 079 @SuppressWarnings("unchecked") 080 public Object defaultValueForType(String className) 081 { 082 Class clazz = forName(className); 083 084 if (!clazz.isPrimitive()) 085 return null; 086 087 // Remembering that 0 coerces to boolean false, this covers all the primitive 088 // types (boolean, int, short, etc.) 089 return typeCoercer.coerce(0, clazz); 090 } 091 092 public Class forName(String className) 093 { 094 Class result = cache.get(className); 095 096 if (result == null) 097 { 098 result = lookupClassForType(className); 099 100 cache.put(className, result); 101 } 102 103 return result; 104 } 105 106 private Class lookupClassForType(String className) 107 { 108 ClassLoader componentLoader = plasticFactory.getProxyFactory(className).getClassLoader(); 109 try 110 { 111 return PlasticInternalUtils.toClass(componentLoader, className); 112 } 113 catch (ClassNotFoundException ex) 114 { 115 throw new RuntimeException(ex); 116 } 117 } 118}