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 015 package org.apache.tapestry5.internal.transform; 016 017 import org.apache.tapestry5.ComponentResources; 018 import org.apache.tapestry5.annotations.InjectContainer; 019 import org.apache.tapestry5.internal.services.ComponentClassCache; 020 import org.apache.tapestry5.model.MutableComponentModel; 021 import org.apache.tapestry5.plastic.*; 022 import org.apache.tapestry5.runtime.Component; 023 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 024 import 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 */ 031 public 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 }