View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.sequencer.text;
25  
26  import java.util.Arrays;
27  import org.modeshape.common.util.CheckArg;
28  
29  /**
30   * An text sequencer implementation that uses a {@link #setColumnStartPositions(String) list of column numbers} to split incoming
31   * rows into fixed-width columns. By default, this class treats each row as a single column. There is an implicit column start
32   * index of 0 for the first column.
33   * 
34   * @see AbstractTextSequencer
35   */
36  public class FixedWidthTextSequencer extends AbstractTextSequencer {
37  
38      private int[] columnStartPositions = new int[] {};
39  
40      /**
41       * Set the column start positions. The column start positions are 0-based. Everything before the first start position is
42       * treated as the first column.
43       * <p>
44       * As an example, if the column start positions were {3, 6, 15} and the incoming stream was:
45       * 
46       * <pre>
47       *           1         2
48       * 012345678901234567890
49       * supercallifragilistic
50       * expialidocious
51       * </pre>
52       * This sequencer would return the following rows:
53       * <pre>
54       * row 1: "sup", "erc", "allifragi", "listic"
55       * row 2: "exp:, "ial", "idocious"
56       * </pre>
57       * 
58       * Note that there are only three columns returned in the second row, as there were not enough characters to reach the third
59       * start position.
60       * </p>
61       * 
62       * @param columnStartPositions the column startPositions; may not be null
63       */
64      public void setColumnStartPositions( int[] columnStartPositions ) {
65          CheckArg.isNotNull(columnStartPositions, "columnStartPositions");
66  
67          this.columnStartPositions = columnStartPositions;
68          Arrays.sort(columnStartPositions);
69      }
70  
71      /**
72       * Set the column start positions from a list of column start positions concatenated into a single, comma-delimited string.
73       * 
74       * @param commaDelimitedColumnStartPositions a list of column start positions concatenated into a single, comma-delimited
75       *        string; may not be null
76       * @see #setColumnStartPositions(int[])
77       */
78      public void setColumnStartPositions( String commaDelimitedColumnStartPositions ) {
79          CheckArg.isNotNull(commaDelimitedColumnStartPositions, "commaDelimitedColumnStartPositions");
80  
81          String[] stringStartPositions = commaDelimitedColumnStartPositions.split(",");
82          int[] columnStartPositions = new int[stringStartPositions.length];
83  
84          for (int i = 0; i < stringStartPositions.length; i++) {
85              columnStartPositions[i] = Integer.valueOf(stringStartPositions[i]);
86          }
87  
88          setColumnStartPositions(columnStartPositions);
89      }
90  
91      @Override
92      protected String[] parseLine( String line ) {
93          assert line != null;
94  
95          int columnCount = columnStartPositions.length + 1;
96          int currentPos = 0;
97  
98          String[] columns = new String[columnCount];
99  
100         for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
101             int endPos = columnIndex >= columnCount - 1 ? Integer.MAX_VALUE : columnStartPositions[columnIndex];
102             String chunk = parseColumn(line, currentPos, endPos);
103 
104             // The line was shorter than expected
105             if (chunk == null) {
106                 assert columnIndex > 0 : "parseColumn failed to return the first column in string " + line;
107 
108                 String[] truncatedColumns = new String[columnIndex - 1];
109                 System.arraycopy(columns, 0, truncatedColumns, 0, columnIndex - 1);
110                 return truncatedColumns;
111             }
112             columns[columnIndex] = chunk;
113             currentPos = endPos;
114         }
115 
116         return columns;
117     }
118 
119     private String parseColumn( String line,
120                                 int startPos,
121                                 int endPos ) {
122         int length = line.length();
123 
124         if (length < startPos) {
125             return null;
126         }
127 
128         if (length < endPos) {
129             return line.substring(startPos);
130         }
131 
132         return line.substring(startPos, endPos);
133     }
134 
135 }