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 }