View Javadoc
1   /*
2   Copyright (c) 2016 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl.complex;
18  
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.NoSuchElementException;
24  
25  import com.healthmarketscience.jackcess.DataType;
26  import com.healthmarketscience.jackcess.PropertyMap;
27  import com.healthmarketscience.jackcess.impl.PropertyMapImpl;
28  
29  /**
30   * PropertyMap implementation for multi-value, complex properties.  The
31   * properties for these columns seem to be dispersed between both the primary
32   * column and the complex value column.  The primary column only seems to have
33   * the simple "multi-value" property and the rest seem to be on the complex
34   * value column.  This PropertyMap implementation combines them into one
35   * synthetic map.
36   *
37   * @author James Ahlborn
38   */
39  public class MultiValueColumnPropertyMap implements PropertyMap
40  {
41    /** properties from the primary column */
42    private final PropertyMap _primary;
43    /** properties from the complex column */
44    private final PropertyMap _complex;
45  
46    public MultiValueColumnPropertyMap(PropertyMap primary, PropertyMap complex) 
47    {
48      _primary = primary;
49      _complex = complex;
50    }
51  
52    public String getName() {
53      return _primary.getName();
54    }
55  
56    public int getSize() {
57      return _primary.getSize() + _complex.getSize();
58    }
59  
60    public boolean isEmpty() {
61      return _primary.isEmpty() && _complex.isEmpty();
62    }
63  
64    public Property get(String name) {
65      Property prop = _primary.get(name);
66      if(prop != null) {
67        return prop;
68      }
69      return _complex.get(name);
70    }
71  
72    public Object getValue(String name) {
73      return getValue(name, null);
74    }
75  
76    public Object getValue(String name, Object defaultValue) {
77      Property prop = get(name);
78      return ((prop != null) ? prop.getValue() : defaultValue);
79    }
80  
81    public Property put(String name, Object value) {
82      return put(name, null, value);
83    }
84  
85    public Property put(String name, DataType type, Object value) {
86      // the only property which seems to go in the "primary" is the "multi
87      // value" property
88      if(isPrimaryKey(name)) {
89        return _primary.put(name, DataType.BOOLEAN, value);
90      }
91      return _complex.put(name, value);
92    }
93  
94    public void putAll(Iterable<? extends Property> props) {
95      if(props == null) {
96        return;
97      }
98  
99      for(Property prop : props) {
100       if(isPrimaryKey(prop.getName())) {
101         ((PropertyMapImpl)_primary).put(prop);
102       } else {
103         ((PropertyMapImpl)_complex).put(prop);
104       }
105     }
106   }  
107 
108   public Property remove(String name) {
109     if(isPrimaryKey(name)) {
110       return _primary.remove(name);
111     }
112     return _complex.remove(name);
113   }
114 
115   public void save() throws IOException {
116     _primary.save();
117     _complex.save();
118   }
119 
120   public Iterator<Property> iterator() {
121     final List<Iterator<Property>> iters = new ArrayList<Iterator<Property>>(2);
122     iters.add(_primary.iterator());
123     iters.add(_complex.iterator());
124 
125     return new Iterator<Property>() {
126       private Iterator<Property> _cur;
127       private Property _next = findNext();
128 
129       private Property findNext() {
130         while(!iters.isEmpty()) {
131           _cur = iters.get(0);
132           if(_cur.hasNext()) {
133             return _cur.next();
134           }
135           iters.remove(0);
136           _cur = null;
137         }
138         return null;
139       }
140 
141       public boolean hasNext() {
142         return (_next != null);
143       }
144 
145       public Property next() {
146         if(!hasNext()) {
147           throw new NoSuchElementException();
148         }
149         Property prop = _next;
150         _next = findNext();
151         return prop;
152       }
153 
154       public void remove() {
155         if(_cur != null) {
156           _cur.remove();
157           _cur = null;
158         }
159       }
160     };
161   }
162 
163   @Override
164   public String toString() {
165     return PropertyMapImpl.toString(this);
166   }
167 
168   private static boolean isPrimaryKey(String name) {
169     // the multi-value key seems to be the only one on the primary column
170     return ALLOW_MULTI_VALUE_PROP.equals(name);
171   } 
172 }