001package jmri.beans; 002 003import java.util.Arrays; 004import java.util.HashMap; 005import java.util.HashSet; 006import java.util.Set; 007 008/** 009 * Provide support for converging the Arbitrary* classes with the non-arbitrary 010 * versions of those classes so that the Arbitrary* version can extend the 011 * non-arbitrary class. 012 * 013 * @author Randall Wood Copyright 2015, 2020 014 */ 015public class ArbitraryPropertySupport implements BeanInterface { 016 017 private final HashMap<String, Object> properties = new HashMap<>(); 018 private final UnboundBean bean; 019 020 public ArbitraryPropertySupport(UnboundBean bean) { 021 this.bean = bean; 022 } 023 024 /** {@inheritDoc} */ 025 @Override 026 public void setIndexedProperty(String key, int index, Object value) { 027 if (BeanUtil.hasIntrospectedProperty(this.bean, key)) { 028 BeanUtil.setIntrospectedIndexedProperty(this.bean, key, index, value); 029 } else { 030 if (!this.properties.containsKey(key)) { 031 this.properties.put(key, new Object[1]); 032 } 033 Object[] array = (Object[]) this.properties.get(key); 034 if (index < array.length) { 035 array[index] = value; 036 } else { 037 Object[] grown = Arrays.copyOf(array, index + 1); 038 grown[index] = value; 039 this.properties.put(key, grown); 040 } 041 } 042 } 043 044 /** {@inheritDoc} */ 045 @Override 046 public Object getIndexedProperty(String key, int index) { 047 if (this.properties.containsKey(key) && this.properties.get(key).getClass().isArray()) { 048 try { 049 return ((Object[]) this.properties.get(key))[index]; 050 } catch (ArrayIndexOutOfBoundsException ex) { 051 return null; 052 } 053 } 054 return BeanUtil.getIntrospectedIndexedProperty(this.bean, key, index); 055 } 056 057 /** {@inheritDoc} */ 058 @Override 059 public void setProperty(String key, Object value) { 060 // use write method for property if it exists 061 if (BeanUtil.hasIntrospectedProperty(this.bean, key)) { 062 BeanUtil.setIntrospectedProperty(this.bean, key, value); 063 } else { 064 this.properties.put(key, value); 065 } 066 } 067 068 /** {@inheritDoc} */ 069 @Override 070 public Object getProperty(String key) { 071 if (this.properties.containsKey(key)) { 072 return this.properties.get(key); 073 } 074 return BeanUtil.getIntrospectedProperty(this.bean, key); 075 } 076 077 /** {@inheritDoc} */ 078 @Override 079 public boolean hasProperty(String key) { 080 return (this.properties.containsKey(key) || BeanUtil.hasIntrospectedProperty(this.bean, key)); 081 } 082 083 /** {@inheritDoc} */ 084 @Override 085 public boolean hasIndexedProperty(String key) { 086 return ((this.properties.containsKey(key) && this.properties.get(key).getClass().isArray()) || 087 BeanUtil.hasIntrospectedIndexedProperty(this.bean, key)); 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public Set<String> getPropertyNames() { 093 HashSet<String> names = new HashSet<>(); 094 names.addAll(this.properties.keySet()); 095 names.addAll(BeanUtil.getIntrospectedPropertyNames(this.bean)); 096 return names; 097 } 098 099}