Package org.apache.tapestry5.internal.services

Source Code of org.apache.tapestry5.internal.services.ComponentInstantiatorSourceImplTest

// Copyright 2006, 2007, 2008, 2009, 2010 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.internal.services;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.UUID;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;

import org.apache.tapestry5.internal.InternalComponentResources;
import org.apache.tapestry5.internal.test.InternalBaseTestCase;
import org.apache.tapestry5.internal.transform.pages.BasicComponent;
import org.apache.tapestry5.ioc.Registry;
import org.apache.tapestry5.ioc.RegistryBuilder;
import org.apache.tapestry5.ioc.internal.services.ClasspathURLConverterImpl;
import org.apache.tapestry5.ioc.services.ClasspathURLConverter;
import org.apache.tapestry5.ioc.services.PropertyAccess;
import org.apache.tapestry5.runtime.Component;
import org.apache.tapestry5.services.TapestryModule;
import org.apache.tapestry5.services.UpdateListenerHub;
import org.slf4j.Logger;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/**
* Tests for {@link org.apache.tapestry5.internal.services.ComponentInstantiatorSourceImpl}. Several of these tests are
* more of the form of integration tests that instantiate the Tapestry IoC Registry.
*/
public class ComponentInstantiatorSourceImplTest extends InternalBaseTestCase
{
    private static final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();

    private static final String SYNTH_COMPONENT_CLASSNAME = "org.apache.tapestry5.internal.transform.pages.SynthComponent";

    private final ClasspathURLConverter converter = new ClasspathURLConverterImpl();

    private File extraClasspath;

    private ComponentInstantiatorSource source;

    private Registry registry;

    private PropertyAccess access;

    private ClassLoader extraLoader;

    private String tempDir;

    @Test
    public void controlled_packages() throws Exception
    {
        ComponentClassTransformer transformer = newMock(ComponentClassTransformer.class);
        Logger logger = mockLogger();

        replay();

        ComponentInstantiatorSourceImpl e = new ComponentInstantiatorSourceImpl(logger, contextLoader, transformer,
                                                                                null, converter);

        assertEquals(e.inControlledPackage("foo.bar.Baz"), false);

        // Check that classes in the default package are never controlled

        assertEquals(e.inControlledPackage("Biff"), false);

        // Now add a controlled package

        e.addPackage("foo.bar");

        assertEquals(e.inControlledPackage("foo.bar.Baz"), true);

        // Sub-packages of controlled packages are controlled as well

        assertEquals(e.inControlledPackage("foo.bar.biff.Pop"), true);

        // Parents of controlled packages are not controlled

        assertEquals(e.inControlledPackage("foo.Gloop"), false);

        verify();
    }

    /**
     * This allows tests the exists() method.
     */
    @Test
    public void component_class_reload() throws Exception
    {
        // Ensure it doesn't already exist:

        assertFalse(source.exists(SYNTH_COMPONENT_CLASSNAME));

        // Create the class on the fly.

        createSynthComponentClass("Original");

        assertTrue(source.exists(SYNTH_COMPONENT_CLASSNAME));

        getMocksControl().resetToNice();
       
        Named named = (Named) createComponent(SYNTH_COMPONENT_CLASSNAME);

        assertEquals(named.getName(), "Original");

        String path = tempDir + "/" + SYNTH_COMPONENT_CLASSNAME.replace('.', '/') + ".class";
        URL url = new File(path).toURL();

        long dtm = readDTM(url);

        while (true)
        {
            if (readDTM(url) != dtm) break;

            // Keep re-writing the file until we see the DTM change.

            createSynthComponentClass("Updated");
        }

        // Detect the change and clear out the internal caches

        UpdateListenerHub hub = registry.getService("UpdateListenerHub", UpdateListenerHub.class);

        hub.fireCheckForUpdates();

        // This will be the new version of the class

        named = (Named) createComponent(SYNTH_COMPONENT_CLASSNAME);

        assertEquals(named.getName(), "Updated");
    }

    private long readDTM(URL url) throws Exception
    {
        URLConnection connection = url.openConnection();

        connection.connect();

        return connection.getLastModified();
    }

    private void createSynthComponentClass(String name) throws CannotCompileException, NotFoundException, IOException
    {
        ClassPool pool = new ClassPool();
        // Inside Maven Surefire, the system classpath is not sufficient to find all
        // the necessary files.
        pool.appendClassPath(new LoaderClassPath(extraLoader));

        CtClass ctClass = pool.makeClass(SYNTH_COMPONENT_CLASSNAME);

        ctClass.setSuperclass(pool.get(BasicComponent.class.getName()));

        // Implement method getName()

        CtMethod method = CtNewMethod.make("public String getName() { return \"" + name + "\"; }", ctClass);
        ctClass.addMethod(method);

        ctClass.addInterface(pool.get(Named.class.getName()));

        ctClass.writeFile(extraClasspath.getAbsolutePath());
    }

    private Component createComponent(Class componentClass)
    {
        String classname = componentClass.getName();

        return createComponent(classname);
    }

    private Component createComponent(String classname)
    {
        InternalComponentResources resources = mockInternalComponentResources();

        replay();

        Instantiator inst = source.getInstantiator(classname);

        Component target = inst.newInstance(resources);

        verify();

        return target;
    }

    @BeforeClass
    public void setup_tests() throws Exception
    {
        String tempdir = System.getProperty("java.io.tmpdir");
        String uid = UUID.randomUUID().toString();

        tempDir = tempdir + "/tapestry-test-classpath/" + uid;
        extraClasspath = new File(tempDir);

        System.out.println("Creating dir: " + extraClasspath);

        extraClasspath.mkdirs();

        URL url = extraClasspath.toURL();

        extraLoader = new URLClassLoader(new URL[] { url }, contextLoader);
        RegistryBuilder builder = new RegistryBuilder(extraLoader);

        builder.add(TapestryModule.class);

        registry = builder.build();

        source = registry.getService(ComponentInstantiatorSource.class);
        access = registry.getService(PropertyAccess.class);

        source.addPackage("org.apache.tapestry5.internal.transform.pages");
    }

    @AfterClass
    public void cleanup_tests()
    {
        registry.shutdown();

        registry = null;
        source = null;
        access = null;
    }
}
TOP

Related Classes of org.apache.tapestry5.internal.services.ComponentInstantiatorSourceImplTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.