Package org.apache.hivemind.lib.adapter

Source Code of org.apache.hivemind.lib.adapter.AdapterRegistryFactory

// Copyright 2004, 2005 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.hivemind.lib.adapter;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.hivemind.ServiceImplementationFactory;
import org.apache.hivemind.ServiceImplementationFactoryParameters;
import org.apache.hivemind.lib.util.AdapterRegistry;
import org.apache.hivemind.lib.util.AdapterRegistryImpl;
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.ClassFactory;
import org.apache.hivemind.service.MethodIterator;
import org.apache.hivemind.service.MethodSignature;

/**
* Constructs a service where the first parameter of each method is used to selected an adapter from
* an {@link org.apache.hivemind.lib.util.AdapterRegistry}. The method invocation is then delegated
* to the adapter.
* <p>
* The service factory parameter defines a configuration (of
* {@link org.apache.hivemind.lib.adapter.AdapterRegistryContribution}that provide the mapping from
* Java classes (or interfaces) to adapter instances.
*
* @author Howard M. Lewis Ship
* @since 1.1
*/
public class AdapterRegistryFactory implements ServiceImplementationFactory
{
    private ClassFactory _classFactory;

    public Object createCoreServiceImplementation(
            ServiceImplementationFactoryParameters factoryParameters)
    {
        AdapterRegistry ar = new AdapterRegistryImpl();

        buildAdapterRegistry(factoryParameters, ar);

        Class implClass = buildImplementationClass(factoryParameters);

        try
        {
            Constructor c = implClass.getConstructors()[0];

            return c.newInstance(new Object[]
            { ar });
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(ex.getMessage(), HiveMind
                    .getLocation(factoryParameters.getFirstParameter()), ex);
        }

    }

    // package private for testing purposes

    void buildAdapterRegistry(ServiceImplementationFactoryParameters factoryParameters,
            AdapterRegistry ar)
    {
        Class serviceInterface = factoryParameters.getServiceInterface();

        AdapterRegistryParameter p = (AdapterRegistryParameter) factoryParameters
                .getFirstParameter();

        List contributions = p.getContributions();

        Iterator i = contributions.iterator();

        while (i.hasNext())
        {
            AdapterRegistryContribution c = (AdapterRegistryContribution) i.next();

            try
            {
                Object adapter = c.getAdapter();

                if (!serviceInterface.isAssignableFrom(adapter.getClass()))
                    throw new ClassCastException(AdapterMessages.adapterWrongInterface(adapter, c
                            .getRegisterClass(), serviceInterface));

                ar.register(c.getRegisterClass(), adapter);
            }
            catch (Exception ex)
            {
                factoryParameters.getErrorLog().error(ex.getMessage(), c.getLocation(), ex);
            }

        }

    }

    // package private for testing purposes

    private Class buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters)
    {
        String name = ClassFabUtils.generateClassName(factoryParameters.getServiceInterface());

        return buildImplementationClass(factoryParameters, name);
    }

    // package private for testing purposes

    Class buildImplementationClass(ServiceImplementationFactoryParameters factoryParameters,
            String name)
    {
        Class serviceInterface = factoryParameters.getServiceInterface();

        ClassFab cf = _classFactory.newClass(name, Object.class);

        cf.addInterface(serviceInterface);

        cf.addField("_adapterRegistry", AdapterRegistry.class);

        cf.addConstructor(new Class[]
        { AdapterRegistry.class }, null, "_adapterRegistry = $1;");

        // TODO: Should we add a check for $1 == null?

        cf.addMethod(Modifier.PRIVATE, new MethodSignature(serviceInterface, "_getAdapter",
                new Class[]
                { Object.class }, null), "return (" + serviceInterface.getName()
                + ") _adapterRegistry.getAdapter($1.getClass());");

        MethodIterator i = new MethodIterator(serviceInterface);

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

            if (proper(sig))
            {
                addAdaptedMethod(cf, sig);
            }
            else
            {
                ClassFabUtils.addNoOpMethod(cf, sig);

                factoryParameters.getErrorLog().error(
                        AdapterMessages.improperServiceMethod(sig),
                        HiveMind.getLocation(factoryParameters.getFirstParameter()),
                        null);
            }

        }

        if (!i.getToString())
            ClassFabUtils.addToStringMethod(cf, AdapterMessages.toString(factoryParameters
                    .getServiceId(), serviceInterface));

        return cf.createClass();
    }

    private void addAdaptedMethod(ClassFab cf, MethodSignature sig)
    {
        String body = "return ($r) _getAdapter($1)." + sig.getName() + "($$);";

        cf.addMethod(Modifier.PUBLIC, sig, body);
    }

    /**
     * A "proper" method is one with at least one parameter and whose first parameter is an object
     * (not primitive) type.
     */

    private boolean proper(MethodSignature sig)
    {
        Class[] parameterTypes = sig.getParameterTypes();

        return parameterTypes != null && parameterTypes.length > 0
                && !parameterTypes[0].isPrimitive();
    }

    public void setClassFactory(ClassFactory classFactory)
    {
        _classFactory = classFactory;
    }
}
TOP

Related Classes of org.apache.hivemind.lib.adapter.AdapterRegistryFactory

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.