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    
015    package org.apache.hivemind.service.impl;
016    
017    import org.apache.commons.logging.Log;
018    import org.apache.hivemind.ServiceImplementationFactoryParameters;
019    import org.apache.hivemind.impl.BaseLocatable;
020    import 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     */
031    public 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    }