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.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.util.Iterator;
25  
26  import org.apache.commons.lang3.ArrayUtils;
27  
28  /**
29   * Implementation of common operations for an EntityCollection.
30   * @version $Revision: 1301248 $ $Date: 2012-03-15 17:20:49 -0500 (Thu, 15 Mar 2012) $
31   */
32  public abstract class EntityCollectionSupport extends EntitySupport implements EntityCollection {
33      /** Serialization version */
34      private static final long serialVersionUID = 5902476686737324304L;
35  
36      private static final byte[] DEFAULT_DELIMITER = ArrayUtils.EMPTY_BYTE_ARRAY;
37  
38      private byte[] delim = DEFAULT_DELIMITER;
39      private boolean delimAfter = true;
40      private boolean suppressEmptyChildren = true;
41  
42      /**
43       * {@inheritDoc}
44       */
45      public final synchronized int length() {
46          int result = 0;
47          for (Iterator<Entity> it = getChildren().iterator(); it.hasNext();) {
48              Entity e = it.next();
49              if (shouldSuppress(e)) {
50                  continue;
51              }
52              result += e.length();
53              if (it.hasNext() || isDelimAfter()) {
54                  result += getDelim().length;
55              }
56          }
57          return result;
58      }
59  
60      /**
61       * {@inheritDoc}
62       */
63      public final synchronized void readFrom(InputStream is) throws IOException {
64          for (Iterator<Entity> it = getChildren().iterator(); it.hasNext();) {
65              Entity e = it.next();
66              if (shouldSuppress(e)) {
67                  continue;
68              }
69              e.readFrom(is);
70              if (it.hasNext() || isDelimAfter()) {
71                  is.skip(getDelim().length);
72              }
73          }
74      }
75  
76      /**
77       * {@inheritDoc}
78       */
79      public final synchronized void writeTo(OutputStream os) throws IOException {
80          for (Iterator<Entity> it = getChildren().iterator(); it.hasNext();) {
81              Entity e = it.next();
82              if (shouldSuppress(e)) {
83                  continue;
84              }
85              e.writeTo(os);
86              if (it.hasNext() || isDelimAfter()) {
87                  os.write(getDelim());
88              }
89          }
90      }
91  
92      /**
93       * {@inheritDoc}
94       */
95      public final synchronized byte[] getValue() {
96          ByteArrayOutputStream baos = new ByteArrayOutputStream();
97          try {
98              writeTo(baos);
99          } catch (IOException e) {
100             throw new RuntimeException(e);
101         }
102         return baos.toByteArray();
103     }
104 
105     /**
106      * {@inheritDoc}
107      */
108     public final synchronized void setValue(byte[] b) {
109         try {
110             readFrom(new ByteArrayInputStream(b));
111         } catch (IOException e) {
112             throw new RuntimeException(e);
113         }
114     }
115 
116     /**
117      * {@inheritDoc}
118      */
119     public final void setValue(byte[] b, int offset, int length) {
120         try {
121             readFrom(new ByteArrayInputStream(b, offset, length));
122         } catch (IOException e) {
123             throw new RuntimeException(e);
124         }
125     }
126 
127     /**
128      * Learn whether a trailing delimiter will be added when a delimiter is being used.
129      * @return boolean.
130      */
131     public boolean isDelimAfter() {
132         return delimAfter;
133     }
134 
135     /**
136      * Set whether to add a trailing delimiter when a delimiter is being used.
137      * Default is <code>true</code>.
138      * @param delimAfter The boolean delimAfter to set.
139      */
140     public void setDelimAfter(boolean delimAfter) {
141         this.delimAfter = delimAfter;
142     }
143 
144     /**
145      * Get the delimiter to use between children.
146      * @return byte[].
147      */
148     public byte[] getDelim() {
149         return delim;
150     }
151 
152     /**
153      * Set the delimiter to use between children.
154      * @param delim The byte[] delimiter to set.
155      */
156     public synchronized void setDelim(byte[] delim) {
157         this.delim = delim == null ? DEFAULT_DELIMITER : delim;
158     }
159 
160     /**
161      * Get the boolean suppressEmptyChildren.
162      * @return boolean
163      */
164     public boolean isSuppressEmptyChildren() {
165         return suppressEmptyChildren;
166     }
167 
168     /**
169      * Set the boolean suppressEmptyChildren.
170      * @param suppressEmptyChildren boolean
171      */
172     public void setSuppressEmptyChildren(boolean suppressEmptyChildren) {
173         this.suppressEmptyChildren = suppressEmptyChildren;
174     }
175 
176     /**
177      * {@inheritDoc}
178      */
179     @Override
180     public EntityCollectionSupport clone() {
181         return (EntityCollectionSupport) super.clone();
182     }
183 
184     /**
185      * Learn whether the specified child should be suppressed.
186      * @param child to check
187      * @return boolean
188      */
189     protected boolean shouldSuppress(Entity child) {
190         return isSuppressEmptyChildren() && child.length() == 0;
191     }
192 
193 }