1 package com.trendmicro.grid.acl.ds.bclog;
2
3 import com.trendmicro.grid.acl.l0.datatypes.ProcessPackageDataSet;
4 import net.sf.tinyjee.streams.ByteBufferOutputStream;
5 import net.sf.tinyjee.streams.PositionOutputStream;
6 import net.sf.tinyjee.util.FileUtils;
7
8 import java.io.File;
9 import java.io.IOException;
10 import java.io.OutputStream;
11 import java.io.FilterOutputStream;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.jar.JarOutputStream;
16 import java.util.jar.Manifest;
17 import java.util.jar.Attributes;
18 import java.util.zip.CRC32;
19 import java.util.zip.CheckedOutputStream;
20 import java.util.zip.ZipEntry;
21 import java.util.zip.ZipOutputStream;
22
23
24
25
26
27
28
29 public class BinaryChangeLogFileWriter {
30
31 static final int ENTRIES_PER_SECTION = 1000;
32
33 private static final Map<String, byte[]> schemaFilesMap = new LinkedHashMap<String, byte[]>(8);
34
35 static {
36 try {
37 File tempFolder = File.createTempFile("~process-schema", ".temp");
38 if (!tempFolder.delete() || !tempFolder.mkdir())
39 throw new RuntimeException("Failed creating temp folder " + tempFolder);
40
41 try {
42 ByteBufferOutputStream buffer = new ByteBufferOutputStream();
43 List<File> schemaFiles = ProcessPackageDataSet.getXmlSerializer().generateSchema(tempFolder);
44 for (File schemaFile : schemaFiles) {
45 FileUtils.copy(schemaFile, buffer, true);
46 schemaFilesMap.put(schemaFile.getName(), buffer.toByteArray());
47 buffer.reset();
48 }
49 } finally {
50 if (FileUtils.removeFiles(tempFolder))
51 tempFolder.delete();
52 }
53
54
55 } catch (Exception e) {
56 throw new RuntimeException(e);
57 }
58 }
59
60 int entryIndex, sectionIndex;
61 CRC32 checksum = new CRC32();
62 ByteBufferOutputStream buffer = new ByteBufferOutputStream();
63 ZipOutputStream sectionOut, logOut;
64
65 public BinaryChangeLogFileWriter(OutputStream binaryLogStream, String...references) throws IOException {
66 if (references.length > 0) {
67 StringBuilder refs = new StringBuilder();
68 for (String reference : references) {
69 if (refs.length() > 0)
70 refs.append(",");
71 refs.append(reference);
72 }
73
74 Manifest mf = new Manifest();
75 mf.getMainAttributes().put(Attributes.Name.EXTENSION_LIST, refs.toString());
76 logOut = new JarOutputStream(binaryLogStream, mf);
77 } else
78 logOut = new ZipOutputStream(binaryLogStream);
79 }
80
81 public synchronized void flush() throws IOException {
82 if (sectionOut != null)
83 sectionOut.flush();
84 logOut.flush();
85 }
86
87 public synchronized void close() throws IOException {
88 if (sectionOut != null)
89 sectionOut.flush();
90 logOut.closeEntry();
91 logOut.close();
92 }
93
94 public synchronized void writeNextSection() throws IOException {
95 if (sectionOut != null) {
96 sectionOut.close();
97 logOut.closeEntry();
98 }
99
100 logOut.putNextEntry(new ZipEntry(String.format("section-%08d.zip", ++sectionIndex)));
101 sectionOut = new ZipOutputStream(new PositionOutputStream(logOut, false));
102
103
104 for (Map.Entry<String, byte[]> entry : schemaFilesMap.entrySet()) {
105 sectionOut.putNextEntry(createStoredEntry(entry.getKey(), 0, entry.getValue()));
106 sectionOut.write(entry.getValue());
107 sectionOut.closeEntry();
108 }
109
110 entryIndex = 0;
111 }
112
113
114
115
116
117
118
119 public synchronized void writeNext(ProcessPackageDataSet dataSet) throws IOException {
120 if (sectionOut == null || entryIndex >= ENTRIES_PER_SECTION)
121 writeNextSection();
122
123 buffer.reset();
124 checksum.reset();
125 try {
126 CheckedOutputStream cOut = new CheckedOutputStream(buffer, checksum);
127 ProcessPackageDataSet.getXmlSerializer().save(dataSet, cOut, true, 0);
128 cOut.close();
129 } catch (IOException e) {
130 throw e;
131 } catch (Exception e) {
132 throw new IOException(e);
133 }
134
135 entryIndex++;
136
137 sectionOut.putNextEntry(createStoredEntry("%08d.xml", entryIndex, checksum.getValue(), buffer.getLength()));
138 buffer.writeTo(sectionOut);
139 sectionOut.closeEntry();
140 buffer.reset();
141 }
142
143 private ZipEntry createStoredEntry(String namePattern, int nameIndex, byte[] data) {
144 checksum.reset();
145 checksum.update(data);
146 return createStoredEntry(namePattern, nameIndex, checksum.getValue(), data.length);
147 }
148
149 private ZipEntry createStoredEntry(String namePattern, int nameIndex, long crc32, long length) {
150 ZipEntry ze = new ZipEntry(String.format(namePattern, nameIndex));
151 ze.setMethod(ZipEntry.STORED);
152 ze.setCrc(crc32);
153 ze.setSize(length);
154 ze.setCompressedSize(length);
155 ze.setTime(System.currentTimeMillis());
156 return ze;
157 }
158 }