001 // Copyright 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.EventConstants; 018 import org.apache.tapestry5.Link; 019 import org.apache.tapestry5.ValueEncoder; 020 import org.apache.tapestry5.annotations.ActivationRequestParameter; 021 import org.apache.tapestry5.internal.services.ComponentClassCache; 022 import org.apache.tapestry5.ioc.util.IdAllocator; 023 import org.apache.tapestry5.model.MutableComponentModel; 024 import org.apache.tapestry5.plastic.FieldHandle; 025 import org.apache.tapestry5.plastic.PlasticClass; 026 import org.apache.tapestry5.plastic.PlasticField; 027 import org.apache.tapestry5.runtime.Component; 028 import org.apache.tapestry5.runtime.ComponentEvent; 029 import org.apache.tapestry5.services.ComponentEventHandler; 030 import org.apache.tapestry5.services.Request; 031 import org.apache.tapestry5.services.ValueEncoderSource; 032 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2; 033 import org.apache.tapestry5.services.transform.TransformationSupport; 034 035 /** 036 * Hooks the activate event handler on the component (presumably, a page) to 037 * extract query parameters, and hooks the link decoration events to extract values 038 * and add them to the {@link Link}. 039 * 040 * @see ActivationRequestParameter 041 * @since 5.2.0 042 */ 043 @SuppressWarnings("all") 044 public class ActivationRequestParameterWorker implements ComponentClassTransformWorker2 045 { 046 private final Request request; 047 048 private final ComponentClassCache classCache; 049 050 private final ValueEncoderSource valueEncoderSource; 051 052 public ActivationRequestParameterWorker(Request request, ComponentClassCache classCache, 053 ValueEncoderSource valueEncoderSource) 054 { 055 this.request = request; 056 this.classCache = classCache; 057 this.valueEncoderSource = valueEncoderSource; 058 } 059 060 public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model) 061 { 062 for (PlasticField field : plasticClass.getFieldsWithAnnotation(ActivationRequestParameter.class)) 063 { 064 mapFieldToQueryParameter(field, support); 065 } 066 } 067 068 private void mapFieldToQueryParameter(PlasticField field, TransformationSupport support) 069 { 070 ActivationRequestParameter annotation = field.getAnnotation(ActivationRequestParameter.class); 071 072 String parameterName = getParameterName(field, annotation); 073 074 // Assumption: the field type is not one that's loaded by the component class loader, so it's safe 075 // to convert to a hard type during class transformation. 076 077 Class fieldType = classCache.forName(field.getTypeName()); 078 079 ValueEncoder encoder = valueEncoderSource.getValueEncoder(fieldType); 080 081 FieldHandle handle = field.getHandle(); 082 083 String fieldName = String.format("%s.%s", field.getPlasticClass().getClassName(), field.getName()); 084 085 setValueFromInitializeEventHandler(support, fieldName, handle, parameterName, encoder); 086 087 decorateLinks(support, fieldName, handle, parameterName, encoder); 088 089 preallocateName(support, parameterName); 090 } 091 092 093 private static void preallocateName(TransformationSupport support, final String parameterName) 094 { 095 ComponentEventHandler handler = new ComponentEventHandler() 096 { 097 public void handleEvent(Component instance, ComponentEvent event) 098 { 099 IdAllocator idAllocator = event.getEventContext().get(IdAllocator.class, 0); 100 101 idAllocator.allocateId(parameterName); 102 } 103 }; 104 105 support.addEventHandler(EventConstants.PREALLOCATE_FORM_CONTROL_NAMES, 1, 106 "ActivationRequestParameterWorker preallocate form control name '" + parameterName + "' event handler", 107 handler); 108 } 109 110 @SuppressWarnings("all") 111 private void setValueFromInitializeEventHandler(TransformationSupport support, String fieldName, final FieldHandle handle, 112 final String parameterName, final ValueEncoder encoder) 113 { 114 ComponentEventHandler handler = new ComponentEventHandler() 115 { 116 public void handleEvent(Component instance, ComponentEvent event) 117 { 118 String clientValue = request.getParameter(parameterName); 119 120 if (clientValue == null) 121 return; 122 123 Object value = encoder.toValue(clientValue); 124 125 handle.set(instance, value); 126 } 127 }; 128 129 support.addEventHandler(EventConstants.ACTIVATE, 0, 130 String.format("Restoring field %s from query parameter '%s'", fieldName, parameterName), handler); 131 132 } 133 134 @SuppressWarnings("all") 135 private static void decorateLinks(TransformationSupport support, String fieldName, final FieldHandle handle, 136 final String parameterName, final ValueEncoder encoder) 137 { 138 ComponentEventHandler handler = new ComponentEventHandler() 139 { 140 public void handleEvent(Component instance, ComponentEvent event) 141 { 142 Object value = handle.get(instance); 143 144 if (value == null) 145 { 146 return; 147 } 148 149 Link link = event.getEventContext().get(Link.class, 0); 150 151 String clientValue = encoder.toClient(value); 152 153 link.addParameter(parameterName, clientValue); 154 } 155 }; 156 157 support.addEventHandler(EventConstants.DECORATE_COMPONENT_EVENT_LINK, 0, 158 String.format("ActivationRequestParameterWorker decorate component event link event handler for field %s as query parameter '%s'", fieldName, parameterName), handler); 159 160 support.addEventHandler(EventConstants.DECORATE_PAGE_RENDER_LINK, 0, String.format( 161 "ActivationRequestParameterWorker decorate page render link event handler for field %s as query parameter '%s'", fieldName, parameterName), handler); 162 } 163 164 private String getParameterName(PlasticField field, ActivationRequestParameter annotation) 165 { 166 if (annotation.value().equals("")) 167 return field.getName(); 168 169 return annotation.value(); 170 } 171 172 }