001: package com.calipso.reportgenerator.common;
002:
003: import com.calipso.reportgenerator.reportcalculator.*;
004: import com.calipso.reportgenerator.reportdefinitions.ReportSourceDefinition;
005: import com.calipso.reportgenerator.reportdefinitions.DimensionSourceDefinition;
006: import com.calipso.reportgenerator.reportdefinitions.types.ReportDataType;
007: import com.calipso.common.DateEx;
008:
009: import java.io.*;
010: import java.util.Iterator;
011: import java.util.Date;
012: import java.util.StringTokenizer;
013: import java.text.SimpleDateFormat;
014:
015: /**
016: *
017: * User: jbassino
018: * Date: 08-ago-2005
019: * Time: 14:04:07
020: * Calipso Software
021: */
022: public class MatrixCsvSerializer {
023:
024: public static ByteArrayOutputStream csvSerialize(Matrix matrix)
025: throws IOException, InfoException {
026: ByteArrayOutputStream stream = new ByteArrayOutputStream();
027: Iterator it = matrix.iterator();
028: while (it.hasNext()) {
029: StringBuffer buffer = new StringBuffer();
030: Object[] objects = (Object[]) it.next();
031: for (int i = 0; i < objects.length; i++) {
032: Object object = objects[i];
033: //Verifica si el objeto es date. Caso contrario retornara null
034: String date = serializeDate(object);
035: if (object == null) {
036: buffer.append(";");
037: } else {
038: if (date != null) {
039: buffer.append(date + ";");
040: } else {
041: if (object.toString().indexOf(";") > -1
042: || object.toString().indexOf("\"") > -1
043: || object.toString().indexOf("\n") > -1
044: || object.toString().indexOf("\r") > -1
045: || object.toString().indexOf("\t") > -1) {
046: String s = object.toString().replaceAll(
047: "\"", "\"\"");
048: buffer.append("\"" + s + "\"" + ";");
049: } else {
050: buffer.append(object.toString() + ";");
051: }
052: }
053: }
054: }
055: buffer.replace(buffer.length() - 1, buffer.length(), "\n"); //reemplaza el ultimo ; de mas por un fin de linea
056: stream.write(buffer.toString().getBytes());
057: }
058: System.gc();
059: return stream;
060: }
061:
062: private static String serializeDate(Object object) {
063: Date date = null;
064: if (object instanceof SharedDate) {
065: date = ((SharedDate) object).getDateEx().getDate();
066: } else if (object instanceof DateEx) {
067: date = ((DateEx) object).getDate();
068: } else if (object instanceof Date) {
069: date = (Date) object;
070: } else {
071: return null;
072: }
073: SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
074: return format.format(date);
075: }
076:
077: public static Matrix deserialize(
078: ReportGeneratorConfiguration configuration,
079: InputStream stream, ReportSourceDefinition definition)
080: throws IOException, InfoException {
081: Matrix result = DataSourceBuilder.buildMatrix(configuration,
082: definition);
083: String line;
084: int lineCount = 0;
085: while (!(line = readLine(stream)).equalsIgnoreCase("")) {
086: lineCount++;
087: result.add(getObjectArray(line, definition));
088: }
089: return result;
090: }
091:
092: private static String readLine(InputStream stream)
093: throws IOException {
094: byte[] bytes = new byte[1024];
095: String result = "";
096: int pos = 0;
097: int c;
098: boolean open = false;
099: while ((c = stream.read()) > -1) {
100: if (pos == 1024) {
101: result += new String(bytes, 0, pos);
102: pos = 0;
103: }
104: if (c == '\"') {
105: //Define si se abrieron o cerraron comillas
106: open = !open;
107: }
108: if (c == '\n' && !open) {
109: //bytes[pos] = (byte)c;
110: //pos++;
111: result += new String(bytes, 0, pos);
112: return result;
113: }
114: bytes[pos] = (byte) c;
115: pos++;
116: }
117: result += new String(bytes, 0, pos);
118: return result;
119: }
120:
121: private static Object[] getObjectArray(String line,
122: ReportSourceDefinition definition) {
123: //TODO optimizar pasando dimCount y arrayLen como parametros para calcularlo una sola vez
124: int dimCount = definition.getDimensionSourceDefinitions()
125: .getDimensionSourceDefinitionCount();
126: int arrayLen = definition.getMetricSourceDefinitions()
127: .getMetricSourceDefinitionCount()
128: + dimCount;
129: Object[] result = new Object[arrayLen];
130: int pos = 0;
131: //Cuando hay dos ;; significa que hay un valor NULL para la dimension.
132: //Al inicio, si empieza con ; el primer valor es null
133: boolean nullToken = true;
134: StringTokenizer tokenizer = new StringTokenizer(line, ";", true);
135: while (tokenizer.hasMoreTokens()) {
136: String token = tokenizer.nextToken();
137: if (token.equals(";")) {
138: if (nullToken) {
139: //Realiza el mismo comportamiento que el DefaultSQLDataSource.
140: result[pos] = null;
141: pos++;
142: } else {
143: nullToken = true;
144: }
145: continue;
146: }
147: nullToken = false;
148: token = token.trim();
149: if (((token.startsWith("\"") && !token.startsWith("\"\"")) || token
150: .startsWith("\"\"\""))
151: && tokenizer.hasMoreTokens()) {
152: token = token.substring(1, token.length());
153: if ((token.endsWith("\"") && (!token.endsWith("\"\"")))
154: || token.endsWith("\"\"\"")) {
155: token = token.substring(0, token.length() - 1);
156: } else {
157: while (tokenizer.hasMoreTokens()) {
158: String aux = tokenizer.nextToken();
159: token += aux;
160: if ((aux.endsWith("\"") && (!aux
161: .endsWith("\"\"")))
162: || aux.endsWith("\"\"\"")) {
163: token = token.substring(0,
164: token.length() - 1);
165: break;
166: }
167: }
168: }
169: }
170: token = cleanQuotes(token);
171: if (pos < dimCount) {
172: DimensionSourceDefinition dimensionDef = definition
173: .getDimensionSourceDefinitions()
174: .getDimensionSourceDefinition(pos);
175: result[pos] = getObjectFrom(token, dimensionDef
176: .getDataType());
177: } else {
178: //Este es el caso de las metricas. Siempre son float
179: result[pos] = SharedFloat.newFrom(Float.valueOf(token));
180: }
181: pos++;
182: }
183: return result;
184: }
185:
186: private static String cleanQuotes(String token) {
187: int first = token.indexOf("\"\"");
188: if (first > -1) {
189: return token.replaceAll("\"\"", "\"");
190: } else {
191: return token;
192: }
193: }
194:
195: private static Object getObjectFrom(String token,
196: ReportDataType dataType) {
197: switch (dataType.getType()) {
198: case ReportDataType.DATE_TYPE:
199: case ReportDataType.DATETIME_TYPE:
200: SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
201: Date date = null;
202: try {
203: date = format.parse(token);
204: } catch (Exception e) {
205: //No debería fallar la levantada de un Date, porque la misma aplicación la escribio con este formato
206: //Si falla, el objeto quedará null
207: e.printStackTrace();
208: }
209: return SharedDate.newFrom(new DateEx(date));
210: case ReportDataType.STRING_TYPE:
211: return SharedString.newFrom(token);
212: case ReportDataType.BOOLEAN_TYPE:
213: return new Boolean(token);
214: case ReportDataType.INTEGER_TYPE:
215: return SharedInteger.newFrom(Integer.valueOf(token));
216: case ReportDataType.FLOAT_TYPE:
217: return SharedFloat.newFrom(Float.valueOf(token));
218: }
219: return null;
220: }
221: }
|