001 // Copyright 2006, 2007, 2010, 2011 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.tapestry5.internal.transform;
016
017 import java.lang.reflect.Modifier;
018
019 import org.apache.tapestry5.ComponentResources;
020 import org.apache.tapestry5.internal.InternalComponentResources;
021 import org.apache.tapestry5.internal.services.ComponentClassCache;
022 import org.apache.tapestry5.ioc.services.PerThreadValue;
023 import org.apache.tapestry5.ioc.services.PerthreadManager;
024 import org.apache.tapestry5.model.MutableComponentModel;
025 import org.apache.tapestry5.plastic.ComputedValue;
026 import org.apache.tapestry5.plastic.FieldConduit;
027 import org.apache.tapestry5.plastic.InstanceContext;
028 import org.apache.tapestry5.plastic.PlasticClass;
029 import org.apache.tapestry5.plastic.PlasticField;
030 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
031 import org.apache.tapestry5.services.transform.TransformationSupport;
032
033 /**
034 * Designed to be just about the last worker in the pipeline. Its job is to convert each otherwise unclaimed
035 * field into a value stored in the {@link PerthreadManager}.
036 */
037 public final class UnclaimedFieldWorker implements ComponentClassTransformWorker2
038 {
039 private final PerthreadManager perThreadManager;
040
041 private final ComponentClassCache classCache;
042
043 static class UnclaimedFieldConduit implements FieldConduit<Object>
044 {
045 private final InternalComponentResources resources;
046
047 private final PerThreadValue<Object> fieldValue;
048
049 // Set prior to the containingPageDidLoad lifecycle event
050 private Object fieldDefaultValue;
051
052 private UnclaimedFieldConduit(InternalComponentResources resources, PerThreadValue<Object> fieldValue,
053 Object fieldDefaultValue)
054 {
055 this.resources = resources;
056
057 this.fieldValue = fieldValue;
058 this.fieldDefaultValue = fieldDefaultValue;
059 }
060
061 public Object get(Object instance, InstanceContext context)
062 {
063 return fieldValue.get(fieldDefaultValue);
064 }
065
066 public void set(Object instance, InstanceContext context, Object newValue)
067 {
068 fieldValue.set(newValue);
069
070 // This catches the case where the instance initializer method sets a value for the field.
071 // That value is captured and used when no specific value has been stored.
072
073 if (!resources.isLoaded())
074 fieldDefaultValue = newValue;
075 }
076 }
077
078 public UnclaimedFieldWorker(ComponentClassCache classCache, PerthreadManager perThreadManager)
079 {
080 this.classCache = classCache;
081 this.perThreadManager = perThreadManager;
082 }
083
084 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
085 {
086 for (PlasticField field : plasticClass.getUnclaimedFields())
087 {
088 transformField(field);
089 }
090 }
091
092 private void transformField(PlasticField field)
093 {
094 if (Modifier.isFinal(field.getModifiers()))
095 return;
096
097 ComputedValue<FieldConduit<Object>> computed = createComputedFieldConduit(field);
098
099 field.setComputedConduit(computed);
100 }
101
102 private ComputedValue<FieldConduit<Object>> createComputedFieldConduit(PlasticField field)
103 {
104 final String fieldType = field.getTypeName();
105
106 return new ComputedValue<FieldConduit<Object>>()
107 {
108 public FieldConduit<Object> get(InstanceContext context)
109 {
110 Object fieldDefaultValue = classCache.defaultValueForType(fieldType);
111 InternalComponentResources resources = context.get(InternalComponentResources.class);
112
113 return new UnclaimedFieldConduit(resources, perThreadManager.createValue(), fieldDefaultValue);
114 }
115 };
116 }
117 }