// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry5.ioc.internal.services;

import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newConcurrentMap;
import org.apache.tapestry5.ioc.services.*;

import static java.lang.String.format;
import java.util.Map;

/**
 *
 */
public class DefaultImplementationBuilderImpl implements DefaultImplementationBuilder
{
    private final Map<Class, Object> cache = newConcurrentMap();

    private final ClassFactory classFactory;

    public DefaultImplementationBuilderImpl(@Builtin ClassFactory classFactory)
    {
        this.classFactory = classFactory;
    }

    public <S> S createDefaultImplementation(Class<S> serviceInterface)
    {
        S instance = serviceInterface.cast(cache.get(serviceInterface));

        if (instance == null)
        {
            instance = createInstance(serviceInterface);
            cache.put(serviceInterface, instance);
        }

        return instance;
    }

    /**
     * Creates a class and an instance of that class. Updates the cache and returns the instance.
     */
    private <S> S createInstance(Class<S> serviceInterface)
    {
        // In rare race conditions, we may end up creating two (or more)
        // NOOP class/instance pairs for the same interface. You need multiple threads
        // asking for a NOOP class for the same interface pretty much simulataneously.
        // We just let this happen.

        Class<S> noopClass = createClass(serviceInterface);

        try
        {
            S instance = noopClass.newInstance();

            cache.put(serviceInterface, instance);

            return instance;
        }
        catch (Exception ex)
        {
            throw new RuntimeException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    private <S> Class<S> createClass(Class<S> serviceInterface)
    {
        ClassFab cf = classFactory.newClass(serviceInterface);

        MethodIterator mi = new MethodIterator(serviceInterface);

        while (mi.hasNext())
        {
            MethodSignature sig = mi.next();

            cf.addNoOpMethod(sig);
        }

        if (!mi.getToString()) cf.addToString(format("<NoOp %s>", serviceInterface.getName()));

        return cf.createClass();
    }
}

@@ -16,16 +16,22 @@
 06, 2007
+, 2011
  The Apa
@@ -240,20 +240,16 @@
 at%0A//%0A//
-    
  http://
@@ -669,22 +669,38 @@
 %0Aimport 
-static
+java.util.Map;%0A%0Aimport
  org.apa
@@ -752,144 +752,359 @@
 tory
-.newConcurrentMap;%0Aimport org.apache.tapestry5.ioc.services.*;%0A%0Aimport static java.lang.String.format;%0Aimport java.util.Map;%0A%0A/**%0A *%0A */
+;%0Aimport org.apache.tapestry5.ioc.services.Builtin;%0Aimport org.apache.tapestry5.ioc.services.DefaultImplementationBuilder;%0Aimport org.apache.tapestry5.ioc.services.PlasticProxyFactory;%0Aimport org.apache.tapestry5.plastic.ClassInstantiator;%0Aimport org.apache.tapestry5.plastic.PlasticClass;%0Aimport org.apache.tapestry5.plastic.PlasticClassTransformer;%0A
 %0Apub
@@ -1233,16 +1233,34 @@
 cache = 
+CollectionFactory.
 newConcu
@@ -1290,29 +1290,36 @@
 e final 
-Class
+PlasticProxy
 Factory 
 classFac
@@ -1306,29 +1306,29 @@
 roxyFactory 
-class
+proxy
 Factory;%0A%0A  
@@ -1381,22 +1381,33 @@
 ltin
- Class
+%0A    PlasticProxy
 Factory 
 clas
@@ -1402,21 +1402,21 @@
 Factory 
-class
+proxy
 Factory)
@@ -1435,21 +1435,21 @@
    this.
-class
+proxy
 Factory 
@@ -1450,21 +1450,21 @@
 ctory = 
-class
+proxy
 Factory;
@@ -1961,16 +1961,22 @@
 nstance(
+final 
 Class%3CS%3E
@@ -2012,324 +2012,65 @@
     
-// In rare race conditions, we may end up creating two (or more)%0A        // NOOP c
+C
 lass
-/i
+I
 nstan
-ce pairs for the same interface. You need multiple threads%0A        // asking for a NOOP class for the same interface pretty much simulataneously.%0A        // We just let this happen.%0A%0A        Class%3CS%3E noopClass = 
+tiator instantiator = proxyFactory.
 create
-Class
+Proxy
 (ser
@@ -2086,689 +2086,173 @@
 face
-);%0A%0A        try%0A        %7B%0A            S instance = noopClass.newInstance();%0A%0A            cache.put(serviceInterface, instance);%0A%0A            return instance;%0A        %7D%0A        catch (Exception ex)%0A        %7B%0A            throw new RuntimeException(ex);%0A        %7D%0A    %7D%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    private %3CS%3E Class%3CS%3E createClass(Class%3CS%3E serviceInterface)%0A    %7B%0A        ClassFab cf = classFactory.newClass(serviceInterface);%0A%0A        MethodIterator mi = new MethodIterator(serviceInterface);%0A%0A        while (mi.hasNext())%0A        %7B%0A            MethodSignature sig = mi.next();%0A%0A            cf.addNoOpMethod(sig);%0A        %7D%0A%0A        if (!mi.getToString()) cf.addTo
+, new PlasticClassTransformer()%0A        %7B%0A            public void transform(PlasticClass plasticClass)%0A            %7B%0A                plasticClass.addToString(
 String
-(
+.
 form
@@ -2301,39 +2301,98 @@
 ));%0A
-%0A        return cf.createClass(
+            %7D%0A        %7D);%0A%0A        return serviceInterface.cast(instantiator.newInstance()
 );%0A 

Convert DefaultImplementationBuilderImpl to use PlasticProxyFactory