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 015package org.apache.tapestry5.internal.transform; 016 017import java.lang.reflect.Modifier; 018 019import org.apache.tapestry5.ComponentResources; 020import org.apache.tapestry5.internal.InternalComponentResources; 021import org.apache.tapestry5.internal.services.ComponentClassCache; 022import org.apache.tapestry5.ioc.services.PerThreadValue; 023import org.apache.tapestry5.ioc.services.PerthreadManager; 024import org.apache.tapestry5.model.MutableComponentModel; 025import org.apache.tapestry5.plastic.ComputedValue; 026import org.apache.tapestry5.plastic.FieldConduit; 027import org.apache.tapestry5.plastic.InstanceContext; 028import org.apache.tapestry5.plastic.PlasticClass; 029import org.apache.tapestry5.plastic.PlasticField; 030import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 031import 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 */ 037public 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}