/* * Copyright 2007 Rickard Öberg. All Rights Reserved. * Copyright 2007 Alin Dreghiciu. All Rights Reserved. * Copyright 2007 Edward Yakop. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.qi4j.library.beans.properties; import org.qi4j.api.common.AppliesTo; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * Generic property mixin. Methods in interface * can be of the following types: * setFoo = set property named foo * getFoo = get property named foo * addFoo = add object to list named foo * removeFoo = remove object from list named foo * fooIterator - return an iterator over the list of Foos */ @AppliesTo( { Getters.class, Setters.class, Iterables.class } ) public class PropertiesMixin implements InvocationHandler { private static final PropertyHandler[] HANDLERS = new PropertyHandler[] { new AbstractPropertyHandler( Setters.SET ) { protected Object handleProperty( Properties properties, String propertyName, Object[] args ) { properties.set( propertyName, args[ 0 ] ); return null; } }, new GetPropertyHandler( Getters.GET ), new GetPropertyHandler( Getters.IS ), new GetPropertyHandler( Getters.HAS ), new AbstractPropertyHandler( Setters.ADD ) { public Object handleProperty( Properties properties, String propertyName, Object[] args ) { properties.add( propertyName, args[ 0 ] ); return null; } }, new AbstractPropertyHandler( Setters.REMOVE ) { protected Object handleProperty( Properties properties, String propertyName, Object[] args ) { properties.remove( propertyName, args[ 0 ] ); return null; } }, new AbstractPropertyHandler( new Iterables() ) { protected Object handleProperty( Properties properties, String propertyName, Object[] args ) { return properties.iterator( propertyName ); } } }; // Attributes ---------------------------------------------------- Properties properties; /** * Construct and empty properties mixins. * * @since 0.1.0 */ public PropertiesMixin() { properties = new Properties(); } // InvocationHandler implementation ------------------------------ @SuppressWarnings( "unchecked" ) public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { String methodName = method.getName(); for( PropertyHandler handler : HANDLERS ) { if( handler.shouldHandle( methodName ) ) { return handler.handleInvocation( properties, methodName, args ); } } return null; } private interface PropertyHandler { boolean shouldHandle( String methodName ); Object handleInvocation( Properties properties, String methodName, Object[] args ); } private static abstract class AbstractPropertyHandler implements PropertyHandler { private PropertyNameExtractor propertyNameExtractor; public AbstractPropertyHandler( PropertyNameExtractor propertyNameExtractor ) { this.propertyNameExtractor = propertyNameExtractor; } public Object handleInvocation( Properties properties, String methodName, Object[] args ) { String propertyName = propertyNameExtractor.extractPropertyName( methodName ); return handleProperty( properties, propertyName, args ); } protected abstract Object handleProperty( Properties properties, String propertyName, Object[] args ); public boolean shouldHandle( String methodName ) { return propertyNameExtractor.extractPropertyName( methodName ) != null; } } private static final class GetPropertyHandler extends AbstractPropertyHandler { public GetPropertyHandler( PropertyNameExtractor propertyNameExtractor ) { super( propertyNameExtractor ); } protected Object handleProperty( Properties properties, String propertyName, Object[] args ) { return properties.get( propertyName ); } } }