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.ioc.internal.util.InternalUtils;
019import org.apache.tapestry5.ioc.services.PerThreadValue;
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 PerThreadValue<Object> pageValue = perThreadManager.createValue();
042
043        private InjectedPageConduit(String className, String fieldName,
044                                    String injectedPageName)
045        {
046            super(className, fieldName);
047
048            this.injectedPageName = injectedPageName;
049        }
050
051        public Object get(Object instance, InstanceContext context)
052        {
053            if (!pageValue.exists())
054            {
055                pageValue.set(componentSource.getPage(injectedPageName));
056            }
057
058            return pageValue.get();
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}