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.Environmental; 018import org.apache.tapestry5.internal.services.ComponentClassCache; 019import org.apache.tapestry5.model.MutableComponentModel; 020import org.apache.tapestry5.plastic.*; 021import org.apache.tapestry5.services.Environment; 022import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 023import 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") 030public 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}