001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.flatfile; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.List; 023 024/** 025 * Entity collection with the following approach: a size (number of children) 026 * and a prototypical child are assigned. The prototype child is cloned 027 * <code>size</code> times, and these clones become the indexed child entities. 028 */ 029public class EntityArray extends EntityCollectionSupport implements 030 IndexedEntityCollection { 031 private static final long serialVersionUID = 8716199462287161060L; 032 033 private int size = -1; 034 private int minimumSize = 0; 035 private int maximumSize = Integer.MAX_VALUE; 036 private boolean resizable = false; 037 private List<Entity> children; 038 private Entity prototype; 039 040 /** 041 * Create a new EntityArray. 042 */ 043 public EntityArray() { 044 // default constructor 045 } 046 047 /** 048 * Create a new IndexedEntityCollection. 049 * @param size number of occurrences of the prototypical Entity 050 */ 051 public EntityArray(int size) { 052 setSize(size); 053 } 054 055 /** 056 * Create a new EntityArray with the specified prototype. 057 * @param prototype Entity 058 */ 059 public EntityArray(Entity prototype) { 060 setPrototype(prototype); 061 } 062 063 /** 064 * Create a new IndexedEntityCollection. 065 * @param prototype Entity 066 * @param size number of occurrences 067 */ 068 public EntityArray(Entity prototype, int size) { 069 this(prototype); 070 setSize(size); 071 } 072 073 /** 074 * {@inheritDoc} 075 */ 076 public Entity getChild(int index) { 077 initialize(); 078 return (Entity) children.get(index); 079 } 080 081 /** 082 * {@inheritDoc} 083 */ 084 public synchronized Collection<Entity> getChildren() { 085 initialize(); 086 return Collections.unmodifiableCollection(children); 087 } 088 089 /** 090 * Get the prototype. 091 * @return Entity. 092 */ 093 public synchronized Entity getPrototype() { 094 return prototype; 095 } 096 097 /** 098 * Set the prototype. 099 * @param prototype The Entity prototype to set. 100 */ 101 public synchronized void setPrototype(Entity prototype) { 102 if (prototype == null) { 103 throw new IllegalArgumentException("prototype Entity was null"); 104 } 105 this.prototype = prototype; 106 } 107 108 /** 109 * {@inheritDoc} 110 * @throws IllegalArgumentException if <code>size</code> is not valid. 111 */ 112 public synchronized void setSize(int size) { 113 if (this.size >= 0 && !isResizable()) { 114 if (size == this.size()) { 115 return; 116 } 117 throw new IllegalStateException("size already set"); 118 } 119 if (size < minimumSize || size > maximumSize) { 120 throw new IllegalArgumentException("illegal collection size: " 121 + size + "; should be <= " + maximumSize + " and >= " 122 + minimumSize); 123 } 124 this.size = size; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 public synchronized int size() { 131 return size; 132 } 133 134 /** 135 * {@inheritDoc} 136 */ 137 public synchronized boolean isSizable() { 138 return size == -1 || isResizable(); 139 } 140 141 /** 142 * Clone this EntityArray. 143 * @return new EntityArray 144 */ 145 @Override 146 public synchronized EntityArray clone() { 147 EntityArray result = (EntityArray) super.clone(); 148 if (children != null) { 149 result.children = new ArrayList<Entity>(); 150 for (Entity e : children) { 151 result.children.add(e.clone()); 152 } 153 } 154 return result; 155 } 156 157 /** 158 * Initialize this EntityArray. 159 */ 160 private synchronized void initialize() { 161 if (children != null) { 162 return; 163 } 164 if (size < 0) { 165 throw new IllegalStateException("EntityArray size not set"); 166 } 167 if (size == 0) { 168 children = Collections.<Entity>emptyList(); 169 return; 170 } 171 if (prototype == null) { 172 throw new IllegalStateException("Prototype child entity not set"); 173 } 174 children = new ArrayList<Entity>(size); 175 adjustSize(); 176 } 177 178 /** 179 * Adjust the size of this EntityArray. 180 */ 181 private synchronized void adjustSize() { 182 if (children.size() > size) { 183 children.subList(size, children.size()).clear(); 184 return; 185 } 186 for (int i = children.size(); i < size; i++) { 187 children.add(prototype.clone()); 188 } 189 } 190 191 /** 192 * Get the int maximumSize. 193 * @return int 194 */ 195 public synchronized int getMaximumSize() { 196 return maximumSize; 197 } 198 199 /** 200 * Set the int maximumSize. 201 * @param maximumSize int 202 */ 203 public synchronized void setMaximumSize(int maximumSize) { 204 if (maximumSize > Integer.MAX_VALUE || maximumSize < getMinimumSize()) { 205 throw new IllegalArgumentException(Integer.toString(maximumSize)); 206 } 207 this.maximumSize = maximumSize; 208 } 209 210 /** 211 * Get the int minimumSize. 212 * @return int 213 */ 214 public synchronized int getMinimumSize() { 215 return minimumSize; 216 } 217 218 /** 219 * Set the int minimumSize. 220 * @param minimumSize int 221 */ 222 public synchronized void setMinimumSize(int minimumSize) { 223 if (minimumSize < 0 || minimumSize > getMaximumSize()) { 224 throw new IllegalArgumentException(Integer.toString(minimumSize)); 225 } 226 this.minimumSize = minimumSize; 227 } 228 229 /** 230 * Get the boolean resizable. 231 * @return boolean 232 */ 233 public boolean isResizable() { 234 return resizable; 235 } 236 237 /** 238 * Set the boolean resizable. 239 * @param resizable boolean 240 */ 241 public void setResizable(boolean resizable) { 242 this.resizable = resizable; 243 } 244 245}