001// Copyright 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.EventConstants;
018import org.apache.tapestry5.annotations.PageActivationContext;
019import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
020import org.apache.tapestry5.ioc.internal.util.InternalUtils;
021import org.apache.tapestry5.model.MutableComponentModel;
022import org.apache.tapestry5.plastic.FieldHandle;
023import org.apache.tapestry5.plastic.PlasticClass;
024import org.apache.tapestry5.plastic.PlasticField;
025import org.apache.tapestry5.runtime.Component;
026import org.apache.tapestry5.runtime.ComponentEvent;
027import org.apache.tapestry5.services.ComponentEventHandler;
028import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
029import org.apache.tapestry5.services.transform.TransformationSupport;
030
031import java.util.List;
032
033/**
034 * Provides the page activation context handlers.
035 *
036 * @see org.apache.tapestry5.annotations.PageActivationContext
037 */
038public class PageActivationContextWorker implements ComponentClassTransformWorker2
039{
040    public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
041    {
042        List<PlasticField> fields = plasticClass.getFieldsWithAnnotation(PageActivationContext.class);
043
044        switch (fields.size())
045        {
046            case 0:
047                break;
048
049            case 1:
050
051                transformField(support, fields.get(0));
052
053                break;
054
055            default:
056
057                List<String> names = CollectionFactory.newList();
058
059                for (PlasticField field : fields)
060                {
061                    names.add(field.getName());
062                }
063
064                throw new RuntimeException(String.format("Illegal number of fields annotated with @PageActivationContext: %s. Only one field is allowed.", InternalUtils.joinSorted(names)));
065        }
066    }
067
068    private void transformField(TransformationSupport support, PlasticField field)
069    {
070        PageActivationContext annotation = field.getAnnotation(PageActivationContext.class);
071
072        FieldHandle handle = field.getHandle();
073
074        if (annotation.activate())
075        {
076            support.addEventHandler(EventConstants.ACTIVATE, 1,
077                    "PageActivationContextWorker activate event handler",
078                    createActivationHandler(field.getTypeName(), handle));
079        }
080
081        if (annotation.passivate())
082        {
083            support.addEventHandler(EventConstants.PASSIVATE, 0,
084                    "PageActivationContextWorker passivate event handler", createPassivateHandler(handle));
085        }
086
087        // We don't claim the field, and other workers may even replace it with a FieldConduit.
088
089    }
090
091    private static ComponentEventHandler createActivationHandler(final String fieldType, final FieldHandle handle)
092    {
093        return new ComponentEventHandler()
094        {
095            public void handleEvent(Component instance, ComponentEvent event)
096            {
097                Object value = event.coerceContext(0, fieldType);
098
099                handle.set(instance, value);
100            }
101        };
102    }
103
104    private static ComponentEventHandler createPassivateHandler(final FieldHandle handle)
105    {
106        return new ComponentEventHandler()
107        {
108            public void handleEvent(Component instance, ComponentEvent event)
109            {
110                Object value = handle.get(instance);
111
112                event.storeResult(value);
113            }
114        };
115    }
116}