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
015 package org.apache.tapestry5.internal.transform;
016
017 import org.apache.tapestry5.annotations.Persist;
018 import org.apache.tapestry5.internal.InternalComponentResources;
019 import org.apache.tapestry5.internal.services.ComponentClassCache;
020 import org.apache.tapestry5.ioc.services.PerThreadValue;
021 import org.apache.tapestry5.ioc.services.PerthreadManager;
022 import org.apache.tapestry5.model.MutableComponentModel;
023 import org.apache.tapestry5.plastic.*;
024 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
025 import org.apache.tapestry5.services.transform.TransformationSupport;
026
027 /**
028 * Converts fields with the {@link org.apache.tapestry5.annotations.Persist} annotation into persistent fields.
029 */
030 public 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 }