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}