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 }