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.annotations.Environmental; 018 import org.apache.tapestry5.internal.services.ComponentClassCache; 019 import org.apache.tapestry5.model.MutableComponentModel; 020 import org.apache.tapestry5.plastic.*; 021 import org.apache.tapestry5.services.Environment; 022 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 023 import org.apache.tapestry5.services.transform.TransformationSupport; 024 025 /** 026 * Obtains a value from the {@link Environment} service based on the field type. This is triggered by the presence of 027 * the {@link Environmental} annotation. 028 */ 029 @SuppressWarnings("rawtypes") 030 public class EnvironmentalWorker implements ComponentClassTransformWorker2 031 { 032 private final Environment environment; 033 034 private final ComponentClassCache classCache; 035 036 037 @SuppressWarnings("unchecked") 038 private final class EnvironmentalConduit implements FieldConduit 039 { 040 private final String componentClassName; 041 042 private final String fieldName; 043 044 private final Class environmentalType; 045 046 private final boolean required; 047 048 private EnvironmentalConduit(String componentClassName, String fieldName, final Class environmentalType, 049 boolean required) 050 { 051 this.componentClassName = componentClassName; 052 this.fieldName = fieldName; 053 this.environmentalType = environmentalType; 054 this.required = required; 055 } 056 057 public Object get(Object instance, InstanceContext context) 058 { 059 return required ? environment.peekRequired(environmentalType) : environment.peek(environmentalType); 060 } 061 062 public void set(Object instance, InstanceContext context, Object newValue) 063 { 064 throw new RuntimeException(String.format("Field %s.%s is read only.", componentClassName, fieldName)); 065 } 066 } 067 068 public EnvironmentalWorker(Environment environment, ComponentClassCache classCache) 069 { 070 this.environment = environment; 071 072 this.classCache = classCache; 073 } 074 075 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) 076 { 077 for (PlasticField field : plasticClass.getFieldsWithAnnotation(Environmental.class)) 078 { 079 transform(model.getComponentClassName(), field); 080 } 081 } 082 083 private void transform(final String componentClassName, PlasticField field) 084 { 085 Environmental annotation = field.getAnnotation(Environmental.class); 086 087 field.claim(annotation); 088 089 final String fieldName = field.getName(); 090 091 final Class fieldType = classCache.forName(field.getTypeName()); 092 093 final boolean required = annotation.value(); 094 095 ComputedValue<FieldConduit<Object>> provider = new ComputedValue<FieldConduit<Object>>() 096 { 097 public FieldConduit<Object> get(InstanceContext context) 098 { 099 return new EnvironmentalConduit(componentClassName, fieldName, fieldType, required); 100 } 101 102 public void set(Object instance, InstanceContext context, Object newValue) 103 { 104 throw new RuntimeException( 105 String.format("Field %s of component %s is read only.", fieldName, componentClassName)); 106 } 107 }; 108 109 field.setComputedConduit(provider); 110 } 111 112 }