View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.flatfile;
18  
19  import java.io.Serializable;
20  import java.util.AbstractList;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.commons.collections4.IteratorUtils;
30  import org.apache.commons.collections4.Transformer;
31  import org.apache.commons.lang3.ArrayUtils;
32  import org.apache.commons.lang3.Validate;
33  
34  /**
35   * Basic implementation of NamedEntityCollection.
36   * @version $Revision: 1766123 $ $Date: 2016-10-21 15:40:45 -0500 (Fri, 21 Oct 2016) $
37   */
38  public class EntityMap extends EntityCollectionSupport implements NamedEntityCollection {
39  
40      private static final long serialVersionUID = 3162898927743996952L;
41  
42      private static class Child implements Serializable {
43  
44          /** Serialization version */
45          private static final long serialVersionUID = 2347729609002856564L;
46  
47          private final String name;
48          @SuppressWarnings("PMD.UnusedPrivateField") // false positive; this field is used in EntityMap#clone()
49          private final Entity entity;
50  
51          /**
52           * Create a new Child instance.
53           * @param name of child
54           * @param entity child
55           */
56          public Child(String name, Entity entity) {
57              this.name = name;
58              if (entity == null) {
59                  throw new IllegalArgumentException();
60              }
61              this.entity = entity;
62          }
63  
64      }
65  
66      /**
67       * Expose the Child list as List<Entity>. This is necessary because we permit nameless children,
68       * which we want to account for in a layout but have no need of referencing later.
69       */
70      private static class ChildrenList extends AbstractList<Entity> implements Serializable {
71  
72          private static final long serialVersionUID = -954784669450571284L;
73  
74          private static final Transformer<Child, Entity> CHILD_TO_ENTITY = new Transformer<Child, Entity>() {
75  
76              public Entity transform(Child input) {
77                  return input.entity;
78              }
79          };
80  
81          private final List<Child> wrapped;
82  
83          /**
84           * Create a new {@link ChildrenList} wrapping the specified {@link List}.
85           * @param wrapped {@link List}
86           */
87          private ChildrenList(List<Child> wrapped) {
88              super();
89              this.wrapped = wrapped;
90          }
91  
92          /**
93           * {@inheritDoc}
94           */
95          @Override
96          public Entity get(int index) {
97              return CHILD_TO_ENTITY.transform(wrapped.get(index));
98          }
99  
100         /**
101          * {@inheritDoc}
102          */
103         @Override
104         public Iterator<Entity> iterator() {
105             return IteratorUtils.transformedIterator(wrapped.iterator(), CHILD_TO_ENTITY);
106         }
107 
108         @Override
109         public int size() {
110             return wrapped.size();
111         }
112 
113     }
114 
115     /** All children */
116     private List<Child> children;
117 
118     /** contains mapped children only */
119     private Map<String, Entity> childMap;
120 
121     private List<Entity> exposeChildrenList;
122 
123     /**
124      * Add a child.
125      * @param name if {@code null} filler element
126      * @param child non-null child Entity
127      */
128     public synchronized void add(String name, Entity child) {
129         Validate.notNull(child, "child entity is null");
130 
131         if (children == null) {
132             children = new ArrayList<Child>();
133             exposeChildrenList = new ChildrenList(children);
134             childMap = new LinkedHashMap<String, Entity>();
135         }
136         if (childMap.containsKey(name)) {
137             throw new IllegalArgumentException("cannot add > 1 child entity '" + name + "'");
138         }
139         if (name != null) {
140             childMap.put(name, child);
141         }
142         children.add(new Child(name, child));
143     }
144 
145     /**
146      * Get a map of the children.
147      * @return Map<String, Entity>
148      */
149     public synchronized Map<String, Entity> getChildMap() {
150         return childMap == null ? Collections.<String, Entity> emptyMap() : Collections.unmodifiableMap(childMap);
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     public synchronized String[] getChildNames() {
157         return childMap == null ? ArrayUtils.EMPTY_STRING_ARRAY
158             : childMap.keySet().toArray(new String[childMap.size()]);
159     }
160 
161     /**
162      * {@inheritDoc}
163      */
164     public Entity getChild(String name) {
165         return getChildMap().get(name);
166     }
167 
168     /**
169      * {@inheritDoc}
170      */
171     public boolean hasChild(String name) {
172         return getChildMap().containsKey(name);
173     }
174 
175     /**
176      * {@inheritDoc}
177      */
178     public synchronized Collection<Entity> getChildren() {
179         return children == null ? Collections.<Entity> emptyList() : Collections.unmodifiableList(exposeChildrenList);
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     @Override
186     public synchronized EntityMap clone() {
187         EntityMap result = (EntityMap) super.clone();
188         result.children = null;
189         result.childMap = null;
190         result.exposeChildrenList = null;
191         if (children != null) {
192             for (Child child : children) {
193                 result.add(child.name, child.entity.clone());
194             }
195         }
196         return result;
197     }
198 }