001 // Copyright 2006-2007 Daniel Gredler 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 net.sf.beanform.binding; 016 017 import java.util.Map; 018 import java.util.Map.Entry; 019 020 import org.apache.hivemind.Location; 021 import org.apache.tapestry.IBinding; 022 import org.apache.tapestry.IComponent; 023 024 /** 025 * A special binding type that allows us to simulate adding and removing 026 * bindings to components. This binding behaves like a custom binding unless 027 * there is no custom binding, in which case it behaves like the standard 028 * (default) binding for a given binding name. 029 * 030 * @author Daniel Gredler 031 */ 032 public class DualBinding implements IBinding { 033 034 private IBinding custom; 035 private IBinding standard; 036 037 public DualBinding( IBinding custom, IBinding standard ) { 038 this.custom = custom; 039 this.standard = standard; 040 } 041 042 public void setCustom( IBinding custom ) { 043 this.custom = custom; 044 } 045 046 public Object getObject() { 047 if( this.custom != null ) return this.custom.getObject(); 048 else if( this.standard != null ) return this.standard.getObject(); 049 else return null; 050 } 051 052 public Object getObject( Class type ) { 053 if( this.custom != null ) return this.custom.getObject( type ); 054 else if( this.standard != null ) return this.standard.getObject( type ); 055 else return null; 056 } 057 058 public boolean isInvariant() { 059 return false; 060 } 061 062 public void setObject( Object value ) { 063 if( this.custom != null ) this.custom.setObject( value ); 064 else if( this.standard != null ) this.standard.setObject( value ); 065 } 066 067 public String getDescription() { 068 if( this.custom != null ) return this.custom.getDescription(); 069 else if( this.standard != null ) return this.standard.getDescription(); 070 else return null; 071 } 072 073 public Location getLocation() { 074 if( this.custom != null ) return this.custom.getLocation(); 075 else if( this.standard != null ) return this.standard.getLocation(); 076 else return null; 077 } 078 079 /** 080 * Adds temporary custom bindings to a component by overriding the existing bindings 081 * with {@link DualBinding} instances whose behavior can later be reverted. 082 */ 083 public static void addCustomBindings( IComponent component, Map<String, IBinding> bindings, boolean clearFirst ) { 084 if( clearFirst ) { 085 DualBinding.removeCustomBindings( component ); 086 } 087 for( Entry<String, IBinding> entry : bindings.entrySet() ) { 088 String bindingName = entry.getKey(); 089 IBinding custom = entry.getValue(); 090 IBinding existing = component.getBinding( bindingName ); 091 DualBinding dual; 092 if( existing instanceof DualBinding ) { 093 dual = (DualBinding) existing; 094 dual.setCustom( custom ); 095 } 096 else { 097 dual = new DualBinding( custom, existing ); 098 } 099 component.setBinding( bindingName, dual ); 100 } 101 } 102 103 /** 104 * Reverts the behavior of the specified component's temporarily customized bindings to 105 * whatever it was prior to customization. 106 */ 107 @SuppressWarnings( "unchecked" ) 108 public static void removeCustomBindings( IComponent component ) { 109 Map<String, IBinding> bindings = component.getBindings(); 110 for( IBinding binding : bindings.values() ) { 111 if( binding instanceof DualBinding ) { 112 DualBinding dual = (DualBinding) binding; 113 dual.setCustom( null ); 114 } 115 } 116 } 117 118 }