1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package jakarta.faces.component; 20 21 22 import jakarta.el.ValueExpression; 23 import jakarta.faces.context.FacesContext; 24 import jakarta.faces.convert.Converter; 25 26 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent; 27 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty; 28 29 /** 30 * Displays a value to the user. 31 */ 32 @JSFComponent(defaultRendererType = "jakarta.faces.Text") 33 public class UIOutput extends UIComponentBase implements ValueHolder 34 { 35 public static final String COMPONENT_TYPE = "jakarta.faces.Output"; 36 public static final String COMPONENT_FAMILY = "jakarta.faces.Output"; 37 38 private Converter _converter; 39 40 /** 41 * Construct an instance of the UIOutput. 42 */ 43 public UIOutput() 44 { 45 setRendererType("jakarta.faces.Text"); 46 } 47 48 @Override 49 public String getFamily() 50 { 51 return COMPONENT_FAMILY; 52 } 53 54 public Object getLocalValue() 55 { 56 return getStateHelper().get(PropertyKeys.value); 57 } 58 59 /** 60 * Gets The initial value of this component. 61 * 62 * @return the new value value 63 */ 64 @JSFProperty 65 public Object getValue() 66 { 67 return getStateHelper().eval(PropertyKeys.value); 68 } 69 70 /** 71 * The initial value of this component. 72 */ 73 public void setValue(Object value) 74 { 75 getStateHelper().put(PropertyKeys.value, value ); 76 } 77 78 /** 79 * @since 2.2 80 */ 81 public void resetValue() 82 { 83 setValue(null); 84 } 85 86 /** 87 * An expression that specifies the Converter for this component. 88 * <p> 89 * The value can either be a static value (ID) or an EL expression. When a static id is 90 * specified, an instance of the converter type registered with that id is used. When this 91 * is an EL expression, the result of evaluating the expression must be an object that 92 * implements the Converter interface. 93 * </p> 94 */ 95 @JSFProperty(partialStateHolder=true) 96 public Converter getConverter() 97 { 98 if (_converter != null) 99 { 100 return _converter; 101 } 102 ValueExpression expression = getValueExpression("converter"); 103 if (expression != null) 104 { 105 return (Converter) expression.getValue(getFacesContext().getELContext()); 106 } 107 return null; 108 } 109 110 public void setConverter(Converter converter) 111 { 112 this._converter = converter; 113 if (initialStateMarked()) 114 { 115 getStateHelper().put(PropertyKeys.converterSet,Boolean.TRUE); 116 } 117 // The argument converter must be inspected for the presence of the ResourceDependency annotation. 118 //_handleAnnotations(FacesContext.getCurrentInstance(), converter); 119 } 120 121 private boolean _isSetConverter() 122 { 123 Boolean value = (Boolean) getStateHelper().get(PropertyKeys.converterSet); 124 return value == null ? false : value; 125 } 126 127 public void markInitialState() 128 { 129 super.markInitialState(); 130 if (_converter != null && 131 _converter instanceof PartialStateHolder) 132 { 133 ((PartialStateHolder)_converter).markInitialState(); 134 } 135 } 136 137 public void clearInitialState() 138 { 139 if (initialStateMarked()) 140 { 141 super.clearInitialState(); 142 if (_converter != null && 143 _converter instanceof PartialStateHolder) 144 { 145 ((PartialStateHolder)_converter).clearInitialState(); 146 } 147 } 148 } 149 150 enum PropertyKeys 151 { 152 value 153 , converterSet 154 } 155 156 @Override 157 public Object saveState(FacesContext facesContext) 158 { 159 if (initialStateMarked()) 160 { 161 Object parentSaved = super.saveState(facesContext); 162 Object converterSaved = null; 163 boolean nullDelta = true; 164 if (!_isSetConverter() && 165 _converter != null && 166 _converter instanceof PartialStateHolder) 167 { 168 //Delta 169 StateHolder holder = (StateHolder) _converter; 170 if (!holder.isTransient()) 171 { 172 Object attachedState = holder.saveState(facesContext); 173 if (attachedState != null) 174 { 175 nullDelta = false; 176 converterSaved = new _AttachedDeltaWrapper(_converter.getClass(), 177 attachedState); 178 } 179 } 180 else 181 { 182 nullDelta = false; 183 converterSaved = null; 184 } 185 } 186 else if (_isSetConverter() || _converter != null) 187 { 188 // A converter that does not implement StateHolder does not need 189 // to save/restore the state, so we can consider it inmutable. 190 // If Call saveAttachedState(), keep the value, but do not set 191 // nullDelta only if the converter was not set after markInitialState(), 192 // so if the parent returns null, this part will return 193 // null and when is restored, it will return null, but it prevents 194 // add the attached object into the state. 195 if (!_isSetConverter() && _converter != null && 196 !(_converter instanceof StateHolder)) 197 { 198 //No op. Note converterSaved is not taken into account if 199 //nullDelta is true. 200 } 201 else 202 { 203 //Full 204 converterSaved = saveAttachedState(facesContext,_converter); 205 // If _converter == null, setConverter() was called after 206 // markInitialState(), set nullDelta to false and save the 207 // null spot. 208 nullDelta = false; 209 } 210 } 211 212 if (parentSaved == null && nullDelta) 213 { 214 //No values 215 return null; 216 } 217 else if (parentSaved != null && nullDelta) 218 { 219 return new Object[]{parentSaved}; 220 } 221 return new Object[]{parentSaved, converterSaved}; 222 } 223 else 224 { 225 Object[] values = new Object[2]; 226 values[0] = super.saveState(facesContext); 227 values[1] = saveAttachedState(facesContext,_converter); 228 return values; 229 } 230 } 231 232 @Override 233 public void restoreState(FacesContext facesContext, Object state) 234 { 235 if (state == null) 236 { 237 return; 238 } 239 240 Object[] values = (Object[])state; 241 super.restoreState(facesContext,values[0]); 242 // Have values.length == 1 considers _converter is nullDelta, in that 243 // case, there is no need to do any changes, but note this will only work 244 // if UIOutput does not have any more StateHolder properties!. 245 if (values.length == 2) 246 { 247 if (values[1] instanceof _AttachedDeltaWrapper) 248 { 249 //Delta 250 ((StateHolder)_converter).restoreState(facesContext, 251 ((_AttachedDeltaWrapper) values[1]).getWrappedStateObject()); 252 } 253 else 254 { 255 //Full 256 _converter = (Converter) restoreAttachedState(facesContext,values[1]); 257 } 258 } 259 } 260 261 /* 262 void _handleAnnotations(FacesContext context, Object inspected) 263 { 264 if (inspected == null) { 265 return; 266 } 267 268 ResourceDependency annotation = inspected.getClass().getAnnotation(ResourceDependency.class); 269 270 if (annotation == null) 271 { 272 // If the ResourceDependency annotation is not present, the argument must be inspected for the presence 273 // of the ResourceDependencies annotation. 274 ResourceDependencies dependencies = inspected.getClass().getAnnotation(ResourceDependencies.class); 275 if (dependencies != null) 276 { 277 // If the ResourceDependencies annotation is present, the action described in ResourceDependencies 278 // must be taken. 279 for (ResourceDependency dependency : dependencies.value()) 280 { 281 _handleResourceDependency(context, dependency); 282 } 283 } 284 } 285 else 286 { 287 // If the ResourceDependency annotation is present, the action described in ResourceDependency must be 288 // taken. 289 _handleResourceDependency(context, annotation); 290 } 291 } 292 293 private void _handleResourceDependency(FacesContext context, ResourceDependency annotation) 294 { 295 // If this annotation is not present on the class in question, no action must be taken. 296 if (annotation != null) 297 { 298 Application application = context.getApplication(); 299 300 // Create a UIOutput instance by passing jakarta.faces.Output. to 301 // Application.createComponent(java.lang.String). 302 UIOutput output = (UIOutput) application.createComponent(COMPONENT_TYPE); 303 304 // Get the annotation instance from the class and obtain the values of the name, library, and 305 // target attributes. 306 String name = annotation.name(); 307 308 // Obtain the renderer-type for the resource name by passing name to 309 // ResourceHandler.getRendererTypeForResourceName(java.lang.String). 310 String rendererType = application.getResourceHandler().getRendererTypeForResourceName(name); 311 312 // Call setRendererType on the UIOutput instance, passing the renderer-type. 313 output.setRendererType(rendererType); 314 315 // Obtain the Map of attributes from the UIOutput component by calling UIComponent.getAttributes(). 316 Map<String, Object> attributes = output.getAttributes(); 317 318 // Store the name into the attributes Map under the key "name". 319 attributes.put("name", name); 320 321 // If library is the empty string, let library be null. 322 String library = annotation.library(); 323 if (library != null && library.length() > 0) 324 { 325 // If library is non-null, store it under the key "library". 326 attributes.put("library", library); 327 } 328 329 // If target is the empty string, let target be null. 330 String target = annotation.target(); 331 if (target != null && target.length() > 0) 332 { 333 // If target is non-null, store it under the key "target". 334 attributes.put("target", target); 335 } 336 else 337 { 338 // Otherwise, if target is null, call UIViewRoot.addComponentResource(jakarta.faces.context.FacesContext, 339 // jakarta.faces.component.UIComponent), passing the UIOutput instance as the second argument. 340 context.getViewRoot().addComponentResource(context, output); 341 } 342 } 343 } 344 */ 345 }