001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.service.impl;
016
017import org.apache.commons.logging.Log;
018import org.apache.hivemind.ServiceImplementationFactoryParameters;
019import org.apache.hivemind.impl.BaseLocatable;
020import org.apache.hivemind.util.PropertyUtils;
021
022/**
023 * Represents one facet of constructing a service implementation instance. A facet is either a
024 * property to be set on the constructed instance, or a parameter to the instance class'
025 * constructor. Facets are nested properties within
026 * {@link org.apache.hivemind.service.impl.BuilderParameter}, and are used by
027 * {@link org.apache.hivemind.service.impl.BuilderFactory}.
028 * 
029 * @author Howard Lewis Ship
030 */
031public abstract class BuilderFacet extends BaseLocatable
032{
033    private String _propertyName;
034
035    /**
036     * Implemented in subclasses to provide a specific value for the facet (for use as a constructor
037     * parameter, or as a value to set a property to).
038     * 
039     * @param factoryParameters
040     *            the parameters that define the service point and its environment
041     * @param targetType
042     *            the desired property type (extracted from the property type of the property to be
043     *            updated, when a property is known)
044     */
045    public abstract Object getFacetValue(ServiceImplementationFactoryParameters factoryParameters,
046            Class targetType);
047
048    public abstract boolean isAssignableToType(
049            ServiceImplementationFactoryParameters factoryParameters, Class targetType);
050
051    public String getPropertyName()
052    {
053        return _propertyName;
054    }
055
056    public void setPropertyName(String string)
057    {
058        _propertyName = string;
059    }
060
061    /**
062     * Attempts to autowire a property of the target. This requires that
063     * <ul>
064     * <li>The facet type defines a default property name and facet type
065     * <li>The facet instance does not have a specified property name
066     * <li>The (default) property is writeable
067     * <li>The (default) property is assignable from the facet type
068     * </ul>
069     * If all conditions are met, then the property is updated to the facet value, and the property
070     * name is returned. In all other cases, null is returned.
071     * 
072     * @param target
073     *            The service implementation being constructed
074     * @param factoryParameters
075     *            the parameters that define the service point and its environment
076     */
077    public String autowire(Object target, ServiceImplementationFactoryParameters factoryParameters)
078    {
079        if (_propertyName != null)
080            return null;
081
082        String defaultPropertyName = getDefaultPropertyName();
083
084        if (defaultPropertyName == null)
085            return null;
086
087        if (!PropertyUtils.isWritable(target, defaultPropertyName))
088            return null;
089
090        Class propertyType = PropertyUtils.getPropertyType(target, defaultPropertyName);
091
092        if (isAssignableToType(factoryParameters, propertyType))
093        {
094            Object facetValue = getFacetValue(factoryParameters, propertyType);
095
096            PropertyUtils.write(target, defaultPropertyName, facetValue);
097
098            Log log = factoryParameters.getLog();
099
100            if (log.isDebugEnabled())
101                log.debug("Autowired property " + defaultPropertyName + " to " + facetValue);
102
103            return defaultPropertyName;
104        }
105
106        return null;
107    }
108
109    /**
110     * Returns null. Subclasses can provide the default name for a property used by
111     * {@link #autowire(Object, ServiceImplementationFactoryParameters)}.
112     */
113    protected String getDefaultPropertyName()
114    {
115        return null;
116    }
117
118    /** @since 1.1 */
119    public boolean canAutowireConstructorParameter()
120    {
121        return false;
122    }
123
124}