    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    }