    001// Copyright 2006, 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
    015package org.apache.tapestry5.internal.transform;
    016
    017import org.apache.tapestry5.annotations.InjectPage;
    018import org.apache.tapestry5.commons.ObjectCreator;
    019import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    020import org.apache.tapestry5.ioc.services.PerthreadManager;
    021import org.apache.tapestry5.model.MutableComponentModel;
    022import org.apache.tapestry5.plastic.InstanceContext;
    023import org.apache.tapestry5.plastic.PlasticClass;
    024import org.apache.tapestry5.plastic.PlasticField;
    025import org.apache.tapestry5.services.ComponentClassResolver;
    026import org.apache.tapestry5.services.ComponentSource;
    027import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
    028import org.apache.tapestry5.services.transform.TransformationSupport;
    029
    030/**
    031 * Performs transformations that allow pages to be injected into components.
    032 *
    033 * @see org.apache.tapestry5.annotations.InjectPage
    034 */
    035public class InjectPageWorker implements ComponentClassTransformWorker2
    036{
    037    private final class InjectedPageConduit extends ReadOnlyComponentFieldConduit
    038    {
    039        private final String injectedPageName;
    040
    041        private final ObjectCreator<Object> pageValue = perThreadManager.createValue(new ObjectCreator<Object>() {
    042            @Override
    043            public Object createObject() {
    044                return componentSource.getPage(injectedPageName);
    045            }
    046        });
    047
    048        private InjectedPageConduit(String className, String fieldName,
    049                                    String injectedPageName)
    050        {
    051            super(className, fieldName);
    052
    053            this.injectedPageName = injectedPageName;
    054        }
    055
    056        public Object get(Object instance, InstanceContext context)
    057        {
    058            return pageValue.createObject();
    059        }
    060    }
    061
    062    private final ComponentSource componentSource;
    063
    064    private final ComponentClassResolver resolver;
    065
    066    private final PerthreadManager perThreadManager;
    067
    068    public InjectPageWorker(ComponentSource componentSource, ComponentClassResolver resolver, PerthreadManager perThreadManager)
    069    {
    070        this.componentSource = componentSource;
    071        this.resolver = resolver;
    072        this.perThreadManager = perThreadManager;
    073    }
    074
    075    public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
    076    {
    077        for (PlasticField field : plasticClass.getFieldsWithAnnotation(InjectPage.class))
    078        {
    079            addInjectedPage(field);
    080        }
    081    }
    082
    083    private void addInjectedPage(PlasticField field)
    084    {
    085        InjectPage annotation = field.getAnnotation(InjectPage.class);
    086
    087        field.claim(annotation);
    088
    089        String pageName = annotation.value();
    090
    091        String fieldName = field.getName();
    092
    093        String injectedPageName = InternalUtils.isBlank(pageName) ? resolver
    094                .resolvePageClassNameToPageName(field.getTypeName()) : pageName;
    095
    096        field.setConduit(new InjectedPageConduit(field.getPlasticClass().getClassName(), fieldName, injectedPageName));
    097    }
    098}