package gueei.binding.pojo; import gueei.binding.BindingLog; import gueei.binding.Command; import gueei.binding.IObservable; import gueei.binding.IPropertyContainer; import gueei.binding.Observable; import java.lang.reflect.Method; import java.util.Collection; import java.util.Hashtable; import android.view.View; public class PojoViewModelWrapper<T extends PojoViewModel> implements IPropertyContainer { private final T mViewModel; private final Hashtable<String, PojoObservable<?>> observables = new Hashtable<String, PojoObservable<?>>(); private final Hashtable<String, PojoCommand> commands = new Hashtable<String, PojoCommand>(); private PojoViewModelWrapper(T viewModel){ mViewModel = viewModel; attachToViewModel(); } @SuppressWarnings({ "rawtypes", "unchecked" }) private void attachToViewModel() { try{ for(Method m: mViewModel.getClass().getMethods()){ String methodName = m.getName(); // Find out all getters. We suppose getters must be in this format getPropertyName // And it must be argument-less if ((methodName.startsWith("get")) && (methodName.length()>=3)){ String propertyName = methodName.substring(3); // Ignore getClass if (propertyName.equals("Class")) continue; // So we have a getter, now look for the setter (if existed) // setter is in setPropertyName format // where it takes one parameter, and it must be the same as the getter parameter Class<?> type = m.getReturnType(); Method setter = null; try{ setter = mViewModel.getClass().getMethod("set" + propertyName, type); }catch(NoSuchMethodException nse){ // OK, it is read-only setter = null; } observables.put(propertyName, new PojoObservable(type, m, setter)); }else{ // It's not a getter, see if it can be a command // A command must be argument-less public method if (m.getParameterTypes().length>0) continue; // Should not have any return (void) if (m.getReturnType()!= void.class) continue; commands.put(methodName, new PojoCommand(m)); } } }catch(Exception e){ BindingLog.exception("PojoViewModelWrapper.attachToViewModel", e); } } public void onPropertyChanged(String name){ if (observables.containsKey(name)){ observables.get(name).onPropertyChanged(); } } public static <Tv extends PojoViewModel> PojoViewModelWrapper<Tv> create(Tv viewModel){ PojoViewModelWrapper<Tv> wrapper = new PojoViewModelWrapper<Tv>(viewModel); viewModel.getHelper().registerWrapper(wrapper); return wrapper; } public IObservable<?> getObservableByName(String name) throws Exception { return observables.get(name); } public Command getCommandByName(String name) throws Exception { return commands.get(name); } public Object getValueByName(String name) throws Exception { return null; } private class PojoCommand extends Command{ private final Method mMethod; public PojoCommand(Method method){ mMethod = method; } public void Invoke(View view, Object... args) { try { mMethod.invoke(mViewModel); } catch (Exception e) { BindingLog.exception("PojoViewModelWrapper.PojoCommand.Invoke", e); } } } private class PojoObservable<To> extends Observable<To>{ private final Method mGetter, mSetter; // prevent loop back recursion of setting private boolean ignoreNext = false; public PojoObservable(Class<To> type, Method getter, Method setter) { super(type); mGetter= getter; mSetter = setter; } public void onPropertyChanged(){ if (!ignoreNext){ this.notifyChanged(); } ignoreNext = false; } @Override protected void doSetValue(To newValue, Collection<Object> initiators) { super.doSetValue(newValue, initiators); if (mSetter==null) return; // Readonly try{ ignoreNext = true; mSetter.invoke(mViewModel, newValue); }catch(Exception e){ BindingLog.exception("PojoViewModelWrapper.PojoObservable.doSetValue", e); } } @SuppressWarnings("unchecked") @Override public To get() { try { return (To)mGetter.invoke(mViewModel); } catch (Exception e) { BindingLog.exception("PojoViewModelWrapper.PojoObservable.get", e); return null; } } } }