View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *  
17   */
18  
19  package org.caleigo.core;
20  
21  import java.io.*;
22  import java.util.*;
23  
24  /*** The EntityReader is a FilterReader that adds read methods for reading 
25   * entities, selections and related data.
26   *
27   * @author  Dennis Zikovic
28   * @version 1.00
29   * 
30   *//* 
31   *
32   * WHEN        WHO               WHY & WHAT
33   * -----------------------------------------------------------------------------
34   * 2003-02-24  Dennis Zikovic    Creation
35   */
36  public class EntityReader extends FilterReader
37  {
38      // Data members ------------------------------------------------------------
39      private int mFieldSeparator = ';';
40      private int mRecordSeparator = '\n';
41      private int mStringDelimiter = '"';
42  
43      private String mNullValue = "";
44      
45      private int mLastReadSeperator = mRecordSeparator;
46  
47      // Constructors ------------------------------------------------------------
48      public EntityReader(Reader in)
49      {
50          super(in);
51      }
52      
53      public EntityReader(Reader in, int fieldSeparator, int entitySeparator)
54      {
55          this(in);
56          mFieldSeparator = fieldSeparator;
57          mRecordSeparator = entitySeparator;
58      }
59      
60      // Action methods ----------------------------------------------------------
61      public IEntity readEntity(IEntityDescriptor entityDescriptor) throws IOException
62      {
63          IEntity entity = entityDescriptor.createEntity();
64          
65          Object data = null;
66          for(int j=0; j<entity.getEntityDescriptor().getFieldCount(); j++)
67          {
68              data = this.readData(entity.getEntityDescriptor().getFieldDescriptor(j).getDataType());
69              if(data!=this)
70                  entity.setData(entityDescriptor.getFieldDescriptor(j), data);
71          }
72          
73          entity.setStatusFlag(IEntity.PERSISTENT);
74          entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
75          return entity;
76      }
77      
78      /*** Reads a mapped selection from the Reader until end of data. Using this
79       * method makes it possible to read from files that has an old entity 
80       * descriptor that has changed since the data was written.
81       */
82      public ISelection readMappedSelection(IEntityDescriptor entityDescriptor) throws IOException
83      {
84          ISelection selection = new Selection(entityDescriptor);
85          
86          // Read and create field map.
87          ArrayList fieldArray = new ArrayList();
88          do
89          {
90              fieldArray.add(this.readData(DataType.STRING));
91          }
92          while(mLastReadSeperator!=mRecordSeparator);        
93          
94          // Validate field map.
95          IFieldDescriptor fieldMap[] = new IFieldDescriptor[fieldArray.size()];
96          for(int j=0; j<fieldArray.size(); j++)
97              fieldMap[j] = findFieldDescriptor(entityDescriptor, fieldArray.get(j).toString());
98          
99          // Read selection until end of data.
100         //
101         // Note that the ready method is not reliable on input streams returned
102         // from zip files. Because of that extra checks is added on the last
103         // read seperator to avoid reading in empty entities.
104         IEntity entity; 
105         Object data;
106         while(in.ready() && mLastReadSeperator==mRecordSeparator)
107         {
108             entity = entityDescriptor.createEntity();
109             
110             for(int j=0; j==0 || j<fieldMap.length && (mLastReadSeperator==mFieldSeparator); j++)
111             {
112                 if(fieldMap[j]!=null)
113                 {
114                     data = this.readData(((IFieldDescriptor)fieldMap[j]).getDataType());
115                     entity.setData(entityDescriptor.getFieldDescriptor(j), data);
116                 }
117                 else    
118                     this.readData(null);
119             }
120             
121 			if(mLastReadSeperator==mRecordSeparator)
122 			{
123 				entity.setStatusFlag(IEntity.PERSISTENT);
124 				entity.clearStatusFlag(IEntity.DIRTY | IEntity.EMPTY);
125 				selection.addEntity(entity);
126 			}
127         }
128     
129         return selection;
130     }
131 
132     // Access methods ----------------------------------------------------------
133     
134     public int getFieldSeparator()
135     {
136         return mFieldSeparator;
137     }
138     
139     public void setFieldSeparator(int character)
140     {
141         mFieldSeparator = character;
142     }
143     
144     public int getRecordSeparator()
145     {
146         return mRecordSeparator;
147     }
148     
149     public void setRecordSeparator(int character)
150     {
151         mRecordSeparator = character;
152     }
153     
154     public int getStringDelimiter()
155     {
156         return mStringDelimiter;
157     }
158     
159     public void setStringDelimiter(int character)
160     {
161         mStringDelimiter = character;
162     }
163     
164     public String getNullValue()
165     {
166         return mNullValue;
167     }
168     
169     public void setNullValue(String nullString)
170     {
171         mNullValue = nullString;
172     }
173     
174     // Help methods ------------------------------------------------------------
175     
176     protected Object readData(DataType dataType) throws IOException
177     {
178         StringBuffer buf = new StringBuffer(255);
179         boolean isUsingDelimiter = dataType!=null && this.useStringDelimiter(dataType);
180         boolean isInDelimitedZone = false;
181                 
182         // MAX_VALUE check added to solve endless loop bugg that occured on
183         // some machines. No pattern to determine why and where was identified.
184         int ch = (char)in.read();  
185         while(ch>0 && ch<Character.MAX_VALUE && (isInDelimitedZone || !(ch==mFieldSeparator || ch==mRecordSeparator)))
186         {
187             if(isUsingDelimiter && ch==mStringDelimiter)
188             {
189                 isInDelimitedZone = !isInDelimitedZone;
190                 if(isInDelimitedZone && buf.length()>0)
191                     buf.append((char)ch);
192             }
193             else if(!isUsingDelimiter || isInDelimitedZone)
194                 buf.append((char)ch);
195                 
196             ch = (char)in.read();        
197         }
198         mLastReadSeperator = ch;
199         
200         // Covert data using the fields data type and return it.
201         // Trim non-delimited data to handle poorly manually edited data files
202         // and to counteract microsoft double character newlines.
203         if(dataType==null || (mNullValue.length()==0 && buf.length()==0) || buf.equals(mNullValue))
204             return null;
205         else
206         {
207             String data = buf.toString();
208             if(!isUsingDelimiter)
209                 data = data.trim();
210             return dataType.convertFrom(data);
211         }
212     }
213     
214     protected boolean useStringDelimiter(DataType dataType)
215     {
216         return mStringDelimiter>0 && dataType==DataType.STRING;
217     }
218     
219     private IFieldDescriptor findFieldDescriptor(IEntityDescriptor entityDescriptor, String sourceName)
220     {
221         for(int j=0; j<entityDescriptor.getFieldCount(); j++)
222             if(entityDescriptor.getFieldDescriptor(j).getSourceName().equals(sourceName))
223                 return entityDescriptor.getFieldDescriptor(j);
224         return null;
225     }
226 }