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.ComponentResources; 018import org.apache.tapestry5.annotations.InjectContainer; 019import org.apache.tapestry5.internal.services.ComponentClassCache; 020import org.apache.tapestry5.model.MutableComponentModel; 021import org.apache.tapestry5.plastic.*; 022import org.apache.tapestry5.runtime.Component; 023import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 024import org.apache.tapestry5.services.transform.TransformationSupport; 025 026/** 027 * Identifies the {@link org.apache.tapestry5.annotations.InjectContainer} annotation and adds code 028 * to initialize it to 029 * the core component. 030 */ 031public class InjectContainerWorker implements ComponentClassTransformWorker2 032{ 033 private final ComponentClassCache cache; 034 035 public InjectContainerWorker(ComponentClassCache cache) 036 { 037 this.cache = cache; 038 } 039 040 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) 041 { 042 for (final PlasticField field : plasticClass.getFieldsWithAnnotation(InjectContainer.class)) 043 { 044 transformField(field); 045 } 046 } 047 048 private void transformField(PlasticField field) 049 { 050 InjectContainer annotation = field.getAnnotation(InjectContainer.class); 051 052 field.claim(annotation); 053 054 ComputedValue<FieldConduit<Object>> provider = createFieldValueConduitProvider(field); 055 056 field.setComputedConduit(provider); 057 } 058 059 private ComputedValue<FieldConduit<Object>> createFieldValueConduitProvider(PlasticField field) 060 { 061 final String fieldName = field.getName(); 062 063 final String fieldTypeName = field.getTypeName(); 064 065 return new ComputedValue<FieldConduit<Object>>() 066 { 067 public FieldConduit<Object> get(InstanceContext context) 068 { 069 final Class fieldType = cache.forName(fieldTypeName); 070 final ComponentResources resources = context.get(ComponentResources.class); 071 072 return new ReadOnlyComponentFieldConduit(resources, fieldName) 073 { 074 public Object get(Object instance, InstanceContext context) 075 { 076 Component container = resources.getContainer(); 077 078 if (!fieldType.isInstance(container)) 079 { 080 String message = String.format( 081 "Component %s (type %s) is not assignable to field %s.%s (of type %s).", container 082 .getComponentResources().getCompleteId(), container.getClass().getName(), resources.getComponentModel() 083 .getComponentClassName(), fieldName, fieldTypeName); 084 085 throw new RuntimeException(message); 086 } 087 088 return container; 089 } 090 }; 091 } 092 }; 093 } 094}