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.tapestry.enhance;
016    
017    import java.util.Iterator;
018    
019    import org.apache.hivemind.ErrorLog;
020    import org.apache.hivemind.Location;
021    import org.apache.tapestry.IComponent;
022    import org.apache.tapestry.event.PageDetachListener;
023    import org.apache.tapestry.spec.IComponentSpecification;
024    
025    /**
026     * No, this class isn't abstract ... this worker locates abstract properties in the base component
027     * class and provides a concrete implementation for them in the enhanced class.
028     * 
029     * @author Howard M. Lewis Ship
030     * @since 4.0
031     */
032    public class AbstractPropertyWorker implements EnhancementWorker
033    {
034        private ErrorLog _errorLog;
035    
036        public void performEnhancement(EnhancementOperation op, IComponentSpecification spec)
037        {
038            Location location = spec.getLocation();
039    
040            Iterator i = op.findUnclaimedAbstractProperties().iterator();
041    
042            while (i.hasNext())
043            {
044                String name = (String) i.next();
045    
046                try
047                {
048                    createProperty(op, name, location);
049                }
050                catch (Exception ex)
051                {
052                    _errorLog.error(
053                            EnhanceMessages.errorAddingProperty(name, op.getBaseClass(), ex),
054                            location,
055                            ex);
056                }
057            }
058        }
059    
060        private void createProperty(EnhancementOperation op, String name, Location location)
061        {
062            // This won't be null because its always for existing properties.
063    
064            Class propertyType = op.getPropertyType(name);
065    
066            String fieldName = "_$" + name;
067            String defaultFieldName = fieldName + "$defaultValue";
068    
069            op.addField(fieldName, propertyType);
070            op.addField(defaultFieldName, propertyType);
071    
072            EnhanceUtils.createSimpleAccessor(op, fieldName, name, propertyType, location);
073            EnhanceUtils.createSimpleMutator(op, fieldName, name, propertyType, location);
074    
075            // Copy the real attribute into the default attribute inside finish load
076            // (allowing a default value to be set inside finishLoad()).
077    
078            op.extendMethodImplementation(
079                    IComponent.class,
080                    EnhanceUtils.FINISH_LOAD_SIGNATURE,
081                    defaultFieldName + " = " + fieldName + ";");
082    
083            // On page detach, restore the attribute to its default value.
084    
085            op.extendMethodImplementation(
086                    PageDetachListener.class,
087                    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
088                    fieldName + " = " + defaultFieldName + ";");
089    
090            // This is not all that necessary, but is proper.
091    
092            op.claimProperty(name);
093        }
094    
095        public void setErrorLog(ErrorLog errorLog)
096        {
097            _errorLog = errorLog;
098        }
099    }