<commit_before>/*
 * Copyright (c) 2007, <NAME>. All Rights Reserved.
 * Copyright (c) 2007, <NAME>. All Rights Reserved.
 *
 * 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.qi4j.runtime;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.qi4j.api.Composite;
import org.qi4j.api.CompositeFactory;
import org.qi4j.api.CompositeInstantiationException;
import org.qi4j.api.DependencyResolver;
import org.qi4j.api.FragmentFactory;
import org.qi4j.api.model.CompositeModel;
import org.qi4j.api.model.CompositeObject;
import org.qi4j.spi.DefaultDependencyResolver;

/**
 * Default implementation of CompositeFactory
 */
public final class CompositeFactoryImpl
    implements CompositeFactory
{
    private FragmentFactory fragmentFactory;
    private Map<Class, CompositeModel> composites;
    private Map<CompositeObject, CompositeContextImpl> objectContexts;
    private List<DependencyResolver> resolvers;

    public CompositeFactoryImpl()
    {
        this( new FragmentFactoryImpl(), null );
    }

    public CompositeFactoryImpl( FragmentFactory aFragmentFactory, List<DependencyResolver> resolvers )
    {
        fragmentFactory = aFragmentFactory;
        if( resolvers == null )
        {
            DefaultDependencyResolver defaultResolver = new DefaultDependencyResolver();
            resolvers = new ArrayList<DependencyResolver>();
            resolvers.add( defaultResolver );
        }
        this.resolvers = resolvers;
        objectContexts = new ConcurrentHashMap<CompositeObject, CompositeContextImpl>();
        composites = new ConcurrentHashMap<Class, CompositeModel>();
    }

    public <T extends Composite> T newInstance( Class<T> aCompositeClass )
        throws CompositeInstantiationException
    {
        // Ensure that given class extends Composite
        if( !Composite.class.isAssignableFrom( aCompositeClass ) )
        {
            throw new CompositeInstantiationException( "Class " + aCompositeClass.getName() + " does not extend " + Composite.class.getName() );
        }

        // Instantiate proxy for given composite interface
        try
        {
            CompositeModel compositeModel = getCompositeModel( aCompositeClass );
            CompositeObject compositeObject = new CompositeObject( compositeModel, aCompositeClass );
            CompositeContextImpl context = getCompositeContext( compositeObject );

            CompositeInvocationHandler handler = new CompositeInvocationHandler( context );
            ClassLoader proxyClassloader = aCompositeClass.getClassLoader();
            Class[] interfaces = new Class[]{ aCompositeClass };
            return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassloader, interfaces, handler ) );
        }
        catch( Exception e )
        {
            System.out.println( e );
            e.printStackTrace();
            throw new CompositeInstantiationException( e );
        }
    }

    public <T> T cast( Class<T> aCompositeClass, Object anObject )
    {
        if( aCompositeClass.isInstance( anObject ) )
        {
            return aCompositeClass.cast( anObject );
        }

        if( anObject instanceof Proxy )
        {
            InvocationHandler handler = Proxy.getInvocationHandler( anObject );
            if( handler instanceof ProxyReferenceInvocationHandler )
            {
                // Get real handler
                handler = Proxy.getInvocationHandler( ( (ProxyReferenceInvocationHandler) handler ).getProxy() );
            }
            ClassLoader proxyClassLoader = aCompositeClass.getClassLoader();

            try
            {
                Class[] interfaces = new Class[]{ aCompositeClass };
                return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassLoader, interfaces, handler ) );
            }
            catch( Exception e )
            {
                throw new CompositeInstantiationException( e );
            }
        }
        else
        {
            throw new CompositeInstantiationException( "Not a composite object:" + anObject );
        }
    }

    public <T extends Composite> T wrapInstance( Class<T> aCompositeClass, Object anObject )
    {
        if( anObject instanceof Proxy && anObject instanceof Composite )
        {
            InvocationHandler wrappedHandler = Proxy.getInvocationHandler( anObject );
            if( wrappedHandler instanceof WrappedCompositeInvocationHandler )
            {
                Object wrappedObject = ( (WrappedCompositeInvocationHandler) wrappedHandler ).getWrappedInstance();
                if( aCompositeClass.isInstance( wrappedObject ) )
                {
                    anObject = wrappedObject;
                }
            }
        }

        CompositeObject wrappedCompositeObject = null;
        if( anObject instanceof Proxy )
        {
            wrappedCompositeObject = CompositeInvocationHandler.getInvocationHandler( anObject ).getContext().getCompositeObject();
        }

        CompositeModel compositeModel = getCompositeModel( aCompositeClass );
        Class wrappedInterface = anObject.getClass().getInterfaces()[ 0 ];
        CompositeObject compositeObject = new CompositeObject( compositeModel, aCompositeClass, wrappedCompositeObject, wrappedInterface );
        CompositeContextImpl context = getCompositeContext( compositeObject );
        CompositeInvocationHandler handler = new WrappedCompositeInvocationHandler( anObject, context );
        ClassLoader proxyClassLoader = aCompositeClass.getClassLoader();

        try
        {
            Class[] interfaces = new Class[]{ aCompositeClass };
            return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassLoader, interfaces, handler ) );
        }<commit_msg>Unwrapping of Wrapped instances are no longer going to happen, right?<commit_after>/*
 * Copyright (c) 2007, <NAME>. All Rights Reserved.
 * Copyright (c) 2007, <NAME>. All Rights Reserved.
 *
 * 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.qi4j.runtime;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.qi4j.api.Composite;
import org.qi4j.api.CompositeFactory;
import org.qi4j.api.CompositeInstantiationException;
import org.qi4j.api.DependencyResolver;
import org.qi4j.api.FragmentFactory;
import org.qi4j.api.model.CompositeModel;
import org.qi4j.api.model.CompositeObject;
import org.qi4j.api.model.CompositeContext;
import org.qi4j.spi.DefaultDependencyResolver;

/**
 * Default implementation of CompositeFactory
 */
public final class CompositeFactoryImpl
    implements CompositeFactory
{
    private FragmentFactory fragmentFactory;
    private Map<Class, CompositeModel> composites;
    private Map<CompositeObject, CompositeContextImpl> objectContexts;
    private List<DependencyResolver> resolvers;

    public CompositeFactoryImpl()
    {
        this( new FragmentFactoryImpl(), null );
    }

    public CompositeFactoryImpl( FragmentFactory aFragmentFactory, List<DependencyResolver> resolvers )
    {
        fragmentFactory = aFragmentFactory;
        if( resolvers == null )
        {
            DefaultDependencyResolver defaultResolver = new DefaultDependencyResolver();
            resolvers = new ArrayList<DependencyResolver>();
            resolvers.add( defaultResolver );
        }
        this.resolvers = resolvers;
        objectContexts = new ConcurrentHashMap<CompositeObject, CompositeContextImpl>();
        composites = new ConcurrentHashMap<Class, CompositeModel>();
    }

    public <T extends Composite> T newInstance( Class<T> aCompositeClass )
        throws CompositeInstantiationException
    {
        // Ensure that given class extends Composite
        if( !Composite.class.isAssignableFrom( aCompositeClass ) )
        {
            throw new CompositeInstantiationException( "Class " + aCompositeClass.getName() + " does not extend " + Composite.class.getName() );
        }

        // Instantiate proxy for given composite interface
        try
        {
            CompositeModel compositeModel = getCompositeModel( aCompositeClass );
            CompositeObject compositeObject = new CompositeObject( compositeModel, aCompositeClass );
            CompositeContextImpl context = getCompositeContext( compositeObject );

            CompositeInvocationHandler handler = new CompositeInvocationHandler( context );
            ClassLoader proxyClassloader = aCompositeClass.getClassLoader();
            Class[] interfaces = new Class[]{ aCompositeClass };
            return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassloader, interfaces, handler ) );
        }
        catch( Exception e )
        {
            System.out.println( e );
            e.printStackTrace();
            throw new CompositeInstantiationException( e );
        }
    }

    public <T> T cast( Class<T> aCompositeClass, Object anObject )
    {
        if( aCompositeClass.isInstance( anObject ) )
        {
            return aCompositeClass.cast( anObject );
        }

        if( anObject instanceof Proxy )
        {
            InvocationHandler handler = Proxy.getInvocationHandler( anObject );
            if( handler instanceof ProxyReferenceInvocationHandler )
            {
                // Get real handler
                handler = Proxy.getInvocationHandler( ( (ProxyReferenceInvocationHandler) handler ).getProxy() );
            }
            ClassLoader proxyClassLoader = aCompositeClass.getClassLoader();

            try
            {
                Class[] interfaces = new Class[]{ aCompositeClass };
                return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassLoader, interfaces, handler ) );
            }
            catch( Exception e )
            {
                throw new CompositeInstantiationException( e );
            }
        }
        else
        {
            throw new CompositeInstantiationException( "Not a composite object:" + anObject );
        }
    }

    public <T extends Composite> T wrapInstance( Class<T> aCompositeClass, Object anObject )
    {
// TODO: After discussing with Rickard, this should not happen anymore. And therefor uncommented. Rickard; Confirm, then remove!
//        // If we are wrapping a Composite...
//        if( anObject instanceof Proxy && anObject instanceof Composite )
//        {
//            InvocationHandler wrappedHandler = Proxy.getInvocationHandler( anObject );
//            // ... and that Composite is already a wrapped instance....
//            if( wrappedHandler instanceof WrappedCompositeInvocationHandler )
//            {
//                // ... then unwrap it.
//                Object wrappedObject = ( (WrappedCompositeInvocationHandler) wrappedHandler ).getWrappedInstance();
//                if( aCompositeClass.isInstance( wrappedObject ) )
//                {
//                    anObject = wrappedObject;
//                }
//            }
//        }
//

        CompositeObject wrappedCompositeObject = null;
//        if( anObject instanceof Proxy )
//        {
//            CompositeInvocationHandler compositeInvocationHandler = CompositeInvocationHandler.getInvocationHandler( anObject );
//            CompositeContext compositeContext = compositeInvocationHandler.getContext();
//            wrappedCompositeObject = compositeContext.getCompositeObject();
//        }

        CompositeModel compositeModel = getCompositeModel( aCompositeClass );
        Class wrappedInterface = anObject.getClass().getInterfaces()[ 0 ]; // Returns the top Composite interface
        CompositeObject compositeObject = new CompositeObject( compositeModel, aCompositeClass, wrappedCompositeObject, wrappedInterface );
        CompositeContextImpl context = getCompositeContext( compositeObject );
        CompositeInvocationHandler handler = new WrappedCompositeInvocationHandler( anObject, context );
        ClassLoader proxyClassLoader = aCompositeClass.getClassLoader();

        try
        {
            Class[] interfaces = new Class[]{ aCompositeClass };
            return aCompositeClass.cast( Proxy.newProxyInstance( proxyClassLoader, interfaces, handler ) );
        }
{'fraction_non_alphanumeric': 0.07861564854180651, 'fraction_numerical': 0.003356455582904453, 'mean_word_length': 2.732739420935412, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4823311', 'n_tokens_mistral': 3331, 'n_tokens_neox': 3239, 'n_words': 882}