001    // Copyright 2007, 2008, 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.SessionState;
018    import org.apache.tapestry5.func.F;
019    import org.apache.tapestry5.func.Predicate;
020    import org.apache.tapestry5.internal.services.ComponentClassCache;
021    import org.apache.tapestry5.model.MutableComponentModel;
022    import org.apache.tapestry5.plastic.FieldConduit;
023    import org.apache.tapestry5.plastic.InstanceContext;
024    import org.apache.tapestry5.plastic.PlasticClass;
025    import org.apache.tapestry5.plastic.PlasticField;
026    import org.apache.tapestry5.services.ApplicationStateManager;
027    import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
028    import org.apache.tapestry5.services.transform.TransformationSupport;
029    
030    import java.util.List;
031    
032    /**
033     * Looks for the {@link org.apache.tapestry5.annotations.SessionState} annotations and
034     * converts read and write access on such fields into calls to the {@link ApplicationStateManager}.
035     */
036    public class ApplicationStateWorker implements ComponentClassTransformWorker2
037    {
038        private final ApplicationStateManager applicationStateManager;
039    
040        private final ComponentClassCache componentClassCache;
041    
042        public ApplicationStateWorker(ApplicationStateManager applicationStateManager,
043                ComponentClassCache componentClassCache)
044        {
045            this.applicationStateManager = applicationStateManager;
046            this.componentClassCache = componentClassCache;
047        }
048    
049        public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
050        {
051            for (PlasticField field : plasticClass.getFieldsWithAnnotation(SessionState.class))
052            {
053                SessionState annotation = field.getAnnotation(SessionState.class);
054    
055                transform(plasticClass, field, annotation.create());
056    
057                field.claim(annotation);
058            }
059        }
060    
061        @SuppressWarnings("unchecked")
062        private void transform(PlasticClass transformation, PlasticField field, final boolean create)
063        {
064            final Class fieldClass = componentClassCache.forName(field.getTypeName());
065    
066            field.setConduit(new FieldConduit()
067            {
068                public void set(Object instance, InstanceContext context, Object newValue)
069                {
070                    applicationStateManager.set(fieldClass, newValue);
071                }
072    
073                public Object get(Object instance, InstanceContext context)
074                {
075                    return create ? applicationStateManager.get(fieldClass) : applicationStateManager
076                            .getIfExists(fieldClass);
077                }
078            });
079    
080            final String expectedName = field.getName() + "Exists";
081    
082            List<PlasticField> fields = F.flow(transformation.getAllFields()).filter(new Predicate<PlasticField>()
083            {
084                public boolean accept(PlasticField field)
085                {
086                    return field.getTypeName().equals("boolean") && field.getName().equalsIgnoreCase(expectedName);
087                }
088            }).toList();
089    
090            for (PlasticField existsField : fields)
091            {
092                existsField.claim(this);
093    
094                final String className = transformation.getClassName();
095    
096                final String fieldName = existsField.getName();
097    
098                existsField.setConduit(new ReadOnlyComponentFieldConduit(className, fieldName)
099                {
100                    public Object get(Object instance, InstanceContext context)
101                    {
102                        return applicationStateManager.exists(fieldClass);
103                    }
104                });
105            }
106        }
107    }