Package org.apache.hivemind.lib.impl

Source Code of org.apache.hivemind.lib.impl.ServicePropertyFactory

//  Copyright 2004 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.impl;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.ServiceImplementationFactory;
import org.apache.hivemind.internal.Module;
import org.apache.hivemind.service.BodyBuilder;
import org.apache.hivemind.service.ClassFab;
import org.apache.hivemind.service.ClassFabUtils;
import org.apache.hivemind.service.ClassFactory;
import org.apache.hivemind.service.MethodSignature;
import org.apache.hivemind.util.ConstructorUtils;
import org.apache.hivemind.util.PropertyAdaptor;
import org.apache.hivemind.util.PropertyUtils;

/**
* Factory that dynamically exposes a property of another service. A proxy
* is constructed that accesses the target service and obtains a property from that.
* The service interface of the constructed service must match the
* type of the exposed property.
*
* @author Howard Lewis Ship
*/
public class ServicePropertyFactory implements ServiceImplementationFactory
{
    private ClassFactory _classFactory;

    public Object createCoreServiceImplementation(
        String serviceId,
        Class serviceInterface,
        Log serviceLog,
        Module invokingModule,
        List parameters)
    {
        ServicePropertyFactoryParameter p = (ServicePropertyFactoryParameter) parameters.get(0);

        Object targetService = p.getService();
        String propertyName = p.getPropertyName();

        PropertyAdaptor pa = PropertyUtils.getPropertyAdaptor(targetService, propertyName);

        String readMethodName = pa.getReadMethodName();

        if (readMethodName == null)
            throw new ApplicationRuntimeException(
                ImplMessages.servicePropertyNotReadable(propertyName, targetService),
                null,
                p.getLocation(),
                null);

        if (!(serviceInterface.isAssignableFrom(pa.getPropertyType())))
            throw new ApplicationRuntimeException(
                ImplMessages.servicePropertyWrongType(
                    propertyName,
                    targetService,
                    pa.getPropertyType(),
                    serviceInterface),
                p.getLocation(),
                null);

        // Now we're good to go.

        String name = ClassFabUtils.generateClassName("ServicePropertyProxy");

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

        addInfrastructure(cf, targetService, serviceInterface, propertyName, readMethodName);

        addMethods(cf, serviceId, serviceInterface, propertyName, targetService);

        Class proxyClass = cf.createClass();

        try
        {
            return ConstructorUtils.invokeConstructor(proxyClass, new Object[] { targetService });
        }
        catch (Throwable ex)
        {
            throw new ApplicationRuntimeException(ex.getMessage(), p.getLocation(), ex);
        }
    }

    private void addInfrastructure(
        ClassFab cf,
        Object targetService,
        Class serviceInterface,
        String propertyName,
        String readPropertyMethodName)
    {
        cf.addInterface(serviceInterface);

        Class targetServiceClass = targetService.getClass();

        cf.addField("_targetService", targetServiceClass);

        cf.addConstructor(
            new Class[] { targetServiceClass },
            null,
            "{ super(); _targetService = $1; }");

        BodyBuilder b = new BodyBuilder();

        b.begin();
        b.addln(
            "{0} property = _targetService.{1}();",
            serviceInterface.getName(),
            readPropertyMethodName);

        b.addln("if (property == null)");
        b.add("  throw new java.lang.NullPointerException(");
        b.addQuoted(ImplMessages.servicePropertyWasNull(propertyName, targetService));
        b.addln(");");

        b.addln("return property;");

        b.end();

        MethodSignature sig =
            new MethodSignature(serviceInterface, "_targetServiceProperty", null, null);
        cf.addMethod(Modifier.FINAL | Modifier.PRIVATE, sig, b.toString());
    }

    private void addMethods(
        ClassFab cf,
        String serviceId,
        Class serviceInterface,
        String propertyName,
        Object targetService)
    {
        boolean toString = false;

        Method[] methods = serviceInterface.getMethods();

        for (int i = 0; i < methods.length; i++)
        {
            Method method = methods[i];

            toString |= ClassFabUtils.isToString(method);

            String body = "return ($r) _targetServiceProperty()." + method.getName() + "($$);";

            cf.addMethod(Modifier.PUBLIC, new MethodSignature(method), body);
        }

        if (!toString)
            ClassFabUtils.addToStringMethod(
                cf,
                ImplMessages.servicePropertyToString(
                    serviceId,
                    serviceInterface,
                    propertyName,
                    targetService));
    }

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

Related Classes of org.apache.hivemind.lib.impl.ServicePropertyFactory

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.