001// Copyright 2006, 2007, 2008, 2009, 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 org.apache.tapestry5.annotations.Persist; 018import org.apache.tapestry5.internal.InternalComponentResources; 019import org.apache.tapestry5.internal.services.ComponentClassCache; 020import org.apache.tapestry5.ioc.services.PerThreadValue; 021import org.apache.tapestry5.ioc.services.PerthreadManager; 022import org.apache.tapestry5.model.MutableComponentModel; 023import org.apache.tapestry5.plastic.*; 024import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 025import org.apache.tapestry5.services.transform.TransformationSupport; 026 027/** 028 * Converts fields with the {@link org.apache.tapestry5.annotations.Persist} annotation into persistent fields. 029 */ 030public class PersistWorker implements ComponentClassTransformWorker2 031{ 032 class PersistentFieldConduit implements FieldConduit<Object> 033 { 034 private final InternalComponentResources resources; 035 036 private final String name; 037 038 private final PerThreadValue<Object> fieldValue = perThreadManager.createValue(); 039 040 private final Object defaultValue; 041 042 public PersistentFieldConduit(InternalComponentResources resources, String name, 043 Object defaultValue) 044 { 045 this.resources = resources; 046 this.name = name; 047 this.defaultValue = defaultValue; 048 } 049 050 public Object get(Object instance, InstanceContext context) 051 { 052 if (!fieldValue.exists()) 053 { 054 Object persistedValue = resources.hasFieldChange(name) ? resources.getFieldChange(name) : defaultValue; 055 056 fieldValue.set(persistedValue); 057 } 058 059 return fieldValue.get(); 060 } 061 062 public void set(Object instance, InstanceContext context, Object newValue) 063 { 064 resources.persistFieldChange(name, newValue); 065 066 fieldValue.set(newValue); 067 } 068 } 069 070 private final ComponentClassCache classCache; 071 072 private final PerthreadManager perThreadManager; 073 074 public PersistWorker(ComponentClassCache classCache, PerthreadManager perThreadManager) 075 { 076 this.classCache = classCache; 077 this.perThreadManager = perThreadManager; 078 } 079 080 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) 081 { 082 for (PlasticField field : plasticClass.getFieldsWithAnnotation(Persist.class)) 083 { 084 makeFieldPersistent(field, model); 085 } 086 } 087 088 private void makeFieldPersistent(PlasticField field, MutableComponentModel model) 089 { 090 Persist annotation = field.getAnnotation(Persist.class); 091 092 field.claim(annotation); 093 094 final String logicalFieldName = model.setFieldPersistenceStrategy(field.getName(), annotation.value()); 095 096 final Object defaultValue = determineDefaultValueFromFieldType(field); 097 098 ComputedValue<FieldConduit<Object>> computed = new ComputedValue<FieldConduit<Object>>() 099 { 100 public FieldConduit<Object> get(InstanceContext context) 101 { 102 InternalComponentResources resources = context.get(InternalComponentResources.class); 103 return new PersistentFieldConduit(resources, logicalFieldName, defaultValue); 104 } 105 }; 106 107 field.setComputedConduit(computed); 108 } 109 110 private Object determineDefaultValueFromFieldType(PlasticField field) 111 { 112 return classCache.defaultValueForType(field.getTypeName()); 113 } 114}