001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.internal.transform;
014
015import org.apache.tapestry5.func.F;
016import org.apache.tapestry5.func.Predicate;
017import org.apache.tapestry5.ioc.ObjectLocator;
018import org.apache.tapestry5.ioc.OperationTracker;
019import org.apache.tapestry5.ioc.annotations.Inject;
020import org.apache.tapestry5.ioc.util.ExceptionUtils;
021import org.apache.tapestry5.model.MutableComponentModel;
022import org.apache.tapestry5.plastic.PlasticClass;
023import org.apache.tapestry5.plastic.PlasticField;
024import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
025import org.apache.tapestry5.services.transform.InjectionProvider2;
026import org.apache.tapestry5.services.transform.TransformationSupport;
027
028/**
029 * Performs injection triggered by any field annotated with the {@link org.apache.tapestry5.ioc.annotations.Inject}
030 * annotation or the {@link javax.inject.Inject} annotation.
031 *
032 * The implementation of this worker mostly delegates to a chain of command of {@link InjectionProvider2}.
033 */
034public class InjectWorker implements ComponentClassTransformWorker2
035{
036    private final ObjectLocator locator;
037
038    // Really, a chain of command
039
040    private final InjectionProvider2 injectionProvider;
041
042    private final OperationTracker tracker;
043
044    private final Predicate<PlasticField> MATCHER = new Predicate<PlasticField>()
045    {
046        public boolean accept(PlasticField field)
047        {
048            return field.hasAnnotation(Inject.class) ||
049                    field.hasAnnotation(javax.inject.Inject.class);
050        }
051    };
052
053    public InjectWorker(ObjectLocator locator, InjectionProvider2 injectionProvider, OperationTracker tracker)
054    {
055        this.locator = locator;
056        this.injectionProvider = injectionProvider;
057        this.tracker = tracker;
058    }
059
060    public void transform(final PlasticClass plasticClass, TransformationSupport support, final MutableComponentModel model)
061    {
062        for (final PlasticField field : F.flow(plasticClass.getUnclaimedFields()).filter(MATCHER))
063        {
064            final String fieldName = field.getName();
065
066            tracker.run(String.format("Injecting field  %s.%s", plasticClass.getClassName(), fieldName), new Runnable()
067            {
068                public void run()
069                {
070                    try
071                    {
072                        boolean success = injectionProvider.provideInjection(field, locator, model);
073
074                        if (success)
075                        {
076                            field.claim("@Inject");
077                        }
078                    } catch (RuntimeException ex)
079                    {
080                        throw new RuntimeException(String.format("Error obtaining injected value for field %s.%s: %s", plasticClass.getClassName(), fieldName, ExceptionUtils.toMessage(ex)), ex);
081                    }
082                }
083            });
084        }
085    }
086}