Package org.apache.tapestry.internal.services

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

// 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.tapestry.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.tapestry.internal.InternalComponentResources;
import org.apache.tapestry.internal.InternalConstants;
import org.apache.tapestry.internal.SingleKeySymbolProvider;
import org.apache.tapestry.internal.SyntheticModuleDef;
import org.apache.tapestry.internal.SyntheticSymbolSourceContributionDef;
import org.apache.tapestry.internal.test.InternalBaseTestCase;
import org.apache.tapestry.internal.transform.pages.BasicComponent;
import org.apache.tapestry.internal.transform.pages.BasicSubComponent;
import org.apache.tapestry.ioc.Registry;
import org.apache.tapestry.ioc.RegistryBuilder;
import org.apache.tapestry.ioc.def.ContributionDef;
import org.apache.tapestry.ioc.def.ModuleDef;
import org.apache.tapestry.ioc.services.PropertyAccess;
import org.apache.tapestry.ioc.services.SymbolProvider;
import org.apache.tapestry.runtime.Component;
import org.apache.tapestry.services.TapestryModule;
import org.slf4j.Logger;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/**
* Tests for {@link org.apache.tapestry.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.tapestry.internal.transform.pages.SynthComponent";

    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(_contextLoader,
                transformer, logger);

        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();
    }

    /** More of an integration test. */
    @Test
    public void load_component_via_service() throws Exception
    {
        Component target = createComponent(BasicComponent.class);

        // Should not be an instance, since it is loaded by a different class loader.
        assertFalse(BasicComponent.class.isInstance(target));

        _access.set(target, "value", "some default value");
        assertEquals(_access.get(target, "value"), "some default value");

        _access.set(target, "retainedValue", "some retained value");
        assertEquals(_access.get(target, "retainedValue"), "some retained value");

        // Setting a property value before pageDidLoad will cause that value
        // to be the default when the page detaches.

        target.containingPageDidLoad();

        _access.set(target, "value", "some transient value");
        assertEquals(_access.get(target, "value"), "some transient value");

        target.containingPageDidDetach();

        assertEquals(_access.get(target, "value"), "some default value");
        assertEquals(_access.get(target, "retainedValue"), "some retained value");
    }

    @Test
    public void load_sub_component_via_service() throws Exception
    {
        Component target = createComponent(BasicSubComponent.class);

        target.containingPageDidLoad();

        _access.set(target, "value", "base class");
        assertEquals(_access.get(target, "value"), "base class");

        _access.set(target, "intValue", 33);
        assertEquals(_access.get(target, "intValue"), 33);

        target.containingPageDidDetach();

        assertNull(_access.get(target, "value"));
        assertEquals(_access.get(target, "intValue"), 0);
    }

    /**
     * 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));

        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.fireUpdateEvent();

        // 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();

        // Can't wait for the HiveMind code base to start using some generics for this kind of
        // thing.

        Instantiator inst = _source.findInstantiator(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);

        SymbolProvider provider = new SingleKeySymbolProvider(
                InternalConstants.TAPESTRY_ALIAS_MODE_SYMBOL, "servlet");
        ContributionDef contribution = new SyntheticSymbolSourceContributionDef("AliasMode",
                provider, "before:ApplicationDefaults");

        ModuleDef module = new SyntheticModuleDef(contribution);

        builder.add(module);

        _registry = builder.build();

        // _registry.getService("Alias", Alias.class).setMode("servlet");

        _source = _registry.getService(ComponentInstantiatorSource.class);
        _access = _registry.getService(PropertyAccess.class);

        _source.addPackage("org.apache.tapestry.internal.transform.pages");
    }

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

        _registry = null;
        _source = null;
        _access = null;
    }
}
TOP

Related Classes of org.apache.tapestry.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.