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    package org.apache.tapestry.enhance;
015    
016    import org.apache.hivemind.ErrorLog;
017    import org.apache.hivemind.Location;
018    import org.apache.hivemind.service.MethodSignature;
019    import org.apache.tapestry.IComponent;
020    import org.apache.tapestry.event.PageDetachListener;
021    import org.apache.tapestry.spec.IComponentSpecification;
022    
023    import java.lang.reflect.Modifier;
024    import java.util.Iterator;
025    
026    
027    /**
028     * Enhances the {@link org.apache.tapestry.IComponent#getClientId()} property.
029     */
030    public class ClientIdPropertyWorker implements EnhancementWorker
031    {
032        private static final String PROPERTY_NAME = "clientId";
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                if (name.equals(PROPERTY_NAME)) {
047                    
048                    try
049                    {
050                        createProperty(op, name, location);
051                    }
052                    catch (Exception ex)
053                    {
054                        _errorLog.error(
055                                EnhanceMessages.errorAddingProperty(name, op.getBaseClass(), ex),
056                                location,
057                                ex);
058                    }
059                    
060                    break;
061                }
062            }
063        }
064    
065        private void createProperty(EnhancementOperation op, String name, Location location)
066        {
067            // This won't be null because its always for existing properties.
068    
069            Class propertyType = op.getPropertyType(name);
070    
071            String fieldName = "_$" + name;
072            String defaultFieldName = fieldName + "$defaultValue";
073    
074            op.addField(fieldName, propertyType);
075            op.addField(defaultFieldName, propertyType);
076            
077            String methodName = op.getAccessorMethodName(name);
078            
079            // Build special getter logic 
080            // if the client id is null "peek" at the next possible unique id
081            
082            StringBuffer str = new StringBuffer();
083            
084            str.append(" if(").append(fieldName).append(" == null){")
085            .append(" if (getPage() == null) { return null; }")
086            .append(" String tempId = getSpecifiedId();")
087            .append(" if (tempId == null) { return null; }")
088            .append(" return getPage().getRequestCycle().peekUniqueId(org.apache.tapestry.TapestryUtils#convertTapestryIdToNMToken(tempId));")
089            .append("} else { ");
090            
091            // else return the existing clientId
092            
093            str.append("return ").append(fieldName).append(";");
094            str.append("}");
095            
096            op.addMethod(
097                    Modifier.PUBLIC,
098                    new MethodSignature(propertyType, methodName, null, null),
099                    str.toString(),
100                    location);
101            
102            EnhanceUtils.createSimpleMutator(op, fieldName, name, propertyType, location);
103            
104            // Copy the real attribute into the default attribute inside finish load
105            // (allowing a default value to be set inside finishLoad()).
106    
107            op.extendMethodImplementation(
108                    IComponent.class,
109                    EnhanceUtils.FINISH_LOAD_SIGNATURE,
110                    defaultFieldName + " = " + fieldName + ";");
111    
112            // On page detach, restore the attribute to its default value.
113    
114            op.extendMethodImplementation(
115                    PageDetachListener.class,
116                    EnhanceUtils.PAGE_DETACHED_SIGNATURE,
117                    fieldName + " = " + defaultFieldName + ";");
118    
119            // This is not all that necessary, but is proper.
120    
121            op.claimProperty(name);
122        }
123    
124        public void setErrorLog(ErrorLog errorLog)
125        {
126            _errorLog = errorLog;
127        }
128    }