Commit | Line | Data |
---|---|---|
e73a4ba5 GB |
1 | /******************************************************************************* |
2 | * Copyright (c) 2013 École Polytechnique de Montréal | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Geneviève Bastien - Initial implementation and API | |
11 | *******************************************************************************/ | |
12 | ||
2bdf0193 | 13 | package org.eclipse.tracecompass.tmf.core.synchronization; |
e73a4ba5 GB |
14 | |
15 | import java.io.File; | |
16 | import java.io.FileInputStream; | |
17 | import java.io.FileNotFoundException; | |
18 | import java.io.FileOutputStream; | |
19 | import java.io.IOException; | |
20 | import java.io.ObjectInputStream; | |
21 | import java.io.ObjectOutputStream; | |
22 | import java.nio.ByteBuffer; | |
23 | import java.nio.channels.FileChannel; | |
24 | ||
2bdf0193 | 25 | import org.eclipse.tracecompass.internal.tmf.core.Activator; |
e73a4ba5 GB |
26 | |
27 | /** | |
28 | * Class to fetch and save synchronization information between traces | |
29 | * | |
30 | * @author Geneviève Bastien | |
31 | * @since 3.0 | |
32 | */ | |
33 | public class SynchronizationBackend { | |
34 | ||
35 | private static final int SYNC_FILE_MAGIC_NUMBER = 0x0DECAF00; | |
36 | ||
37 | private static final int FILE_VERSION = 1; | |
38 | ||
39 | private static final int HEADER_SIZE = 20; | |
40 | ||
41 | private final File fSyncFile; | |
42 | ||
43 | /** | |
44 | * Constructor | |
45 | * | |
46 | * @param syncFile | |
47 | * The file containing synchronization information | |
48 | * @throws IOException | |
49 | * If the file couldn't be opened for some reason | |
50 | */ | |
51 | public SynchronizationBackend(File syncFile) throws IOException { | |
52 | this(syncFile, true); | |
53 | } | |
54 | ||
55 | /** | |
56 | * Constructor with possibility to tell whether to throw errors on exception | |
57 | * or not | |
58 | * | |
59 | * @param syncFile | |
60 | * The file containing synchronization information | |
61 | * @param throwErrors | |
62 | * Whether to throw exceptions or not | |
63 | * @throws IOException | |
64 | * If the file couldn't be opened for some reason | |
65 | */ | |
66 | public SynchronizationBackend(File syncFile, boolean throwErrors) throws IOException { | |
67 | /* | |
68 | * Open the file ourselves, get the header information we need, then | |
69 | * pass on the descriptor. | |
70 | */ | |
71 | int res; | |
72 | ||
73 | fSyncFile = syncFile; | |
74 | ||
75 | if (syncFile == null) { | |
76 | return; | |
77 | } | |
78 | ||
79 | if (!syncFile.exists()) { | |
80 | if (throwErrors) { | |
81 | throw new IOException("Selected synchronization file does not exist"); //$NON-NLS-1$ | |
82 | } | |
83 | return; | |
84 | } | |
85 | if (syncFile.length() <= 0) { | |
86 | if (throwErrors) { | |
87 | throw new IOException("Invalid synchronization file selected, " + //$NON-NLS-1$ | |
88 | "target file is empty"); //$NON-NLS-1$ | |
89 | } | |
90 | return; | |
91 | } | |
92 | ||
a4524c1b AM |
93 | try (FileInputStream fis = new FileInputStream(syncFile); |
94 | FileChannel fc = fis.getChannel();) { | |
95 | ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE); | |
96 | buffer.clear(); | |
97 | fc.read(buffer); | |
98 | buffer.flip(); | |
e73a4ba5 | 99 | |
a4524c1b AM |
100 | /* |
101 | * Check the magic number,to make sure we're opening the right type | |
102 | * of file | |
103 | */ | |
104 | res = buffer.getInt(); | |
105 | if (res != SYNC_FILE_MAGIC_NUMBER) { | |
106 | throw new IOException("Selected file does not" + //$NON-NLS-1$ | |
107 | "look like a synchronization file"); //$NON-NLS-1$ | |
108 | } | |
e73a4ba5 | 109 | |
a4524c1b AM |
110 | res = buffer.getInt(); /* Major version number */ |
111 | if (res != FILE_VERSION) { | |
112 | throw new IOException("Select synchronization file is of an older " //$NON-NLS-1$ | |
113 | + "format. Synchronization will have to be computed again."); //$NON-NLS-1$ | |
114 | } | |
e73a4ba5 | 115 | |
a4524c1b AM |
116 | res = buffer.getInt(); /* Minor version number */ |
117 | } | |
e73a4ba5 GB |
118 | } |
119 | ||
120 | /** | |
121 | * Opens an existing synchronization file | |
122 | * | |
123 | * @return The synchronization algorithm contained in the file | |
124 | * @throws IOException | |
125 | * Exception returned file functions | |
126 | */ | |
127 | public SynchronizationAlgorithm openExistingSync() throws IOException { | |
128 | ||
129 | if (fSyncFile == null) { | |
130 | return null; | |
131 | } | |
132 | ||
a4524c1b AM |
133 | try (/* Set the position after the header */ |
134 | FileInputStream fis = new FileInputStream(fSyncFile); | |
135 | FileChannel fc = fis.getChannel().position(HEADER_SIZE); | |
136 | /* Read the input stream */ | |
137 | ObjectInputStream ois = new ObjectInputStream(fis);) { | |
e73a4ba5 | 138 | |
a4524c1b | 139 | return (SynchronizationAlgorithm) ois.readObject(); |
e73a4ba5 | 140 | } catch (ClassNotFoundException e) { |
a4524c1b | 141 | return null; |
e73a4ba5 | 142 | } |
e73a4ba5 | 143 | |
e73a4ba5 | 144 | |
e73a4ba5 GB |
145 | } |
146 | ||
147 | /** | |
148 | * Saves the synchronization algorithm object to file | |
149 | * | |
150 | * @param syncAlgo | |
151 | * The algorithm to save | |
152 | * @throws FileNotFoundException | |
153 | * propagate callee's exceptions | |
154 | */ | |
155 | public void saveSync(SynchronizationAlgorithm syncAlgo) throws FileNotFoundException { | |
156 | ||
157 | if (fSyncFile == null) { | |
158 | return; | |
159 | } | |
160 | ||
a4524c1b AM |
161 | /* Save the header of the file */ |
162 | try (FileOutputStream fos = new FileOutputStream(fSyncFile, false); | |
163 | FileChannel fc = fos.getChannel();) { | |
e73a4ba5 | 164 | |
a4524c1b AM |
165 | ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE); |
166 | buffer.clear(); | |
e73a4ba5 | 167 | |
e73a4ba5 GB |
168 | fc.position(0); |
169 | ||
170 | buffer.putInt(SYNC_FILE_MAGIC_NUMBER); | |
171 | ||
172 | buffer.putInt(FILE_VERSION); | |
173 | ||
174 | buffer.flip(); | |
a4524c1b | 175 | int res = fc.write(buffer); |
e73a4ba5 GB |
176 | assert (res <= HEADER_SIZE); |
177 | /* done writing the file header */ | |
178 | ||
179 | fc.position(HEADER_SIZE); | |
180 | ||
a4524c1b AM |
181 | try (ObjectOutputStream oos = new ObjectOutputStream(fos);) { |
182 | oos.writeObject(syncAlgo); | |
183 | } | |
e73a4ba5 | 184 | |
a4524c1b AM |
185 | } catch (FileNotFoundException e) { |
186 | /* Send this upwards */ | |
187 | throw e; | |
e73a4ba5 | 188 | } catch (IOException e) { |
a4524c1b | 189 | /* Handle other cases of IOException's */ |
e73a4ba5 | 190 | Activator.logError("Error saving trace synchronization data", e); //$NON-NLS-1$ |
e73a4ba5 GB |
191 | } |
192 | return; | |
193 | ||
194 | } | |
195 | ||
196 | } |