| /******************************************************************************* |
| * Copyright (c) 2013, 2014 École Polytechnique de Montréal |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Geneviève Bastien - Initial implementation and API |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.core.synchronization; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.FileChannel; |
| |
| import org.eclipse.tracecompass.internal.tmf.core.Activator; |
| |
| /** |
| * Class to fetch and save synchronization information between traces |
| * |
| * @author Geneviève Bastien |
| */ |
| public class SynchronizationBackend { |
| |
| private static final int SYNC_FILE_MAGIC_NUMBER = 0x0DECAF00; |
| |
| private static final int FILE_VERSION = 1; |
| |
| private static final int HEADER_SIZE = 20; |
| |
| private final File fSyncFile; |
| |
| /** |
| * Constructor |
| * |
| * @param syncFile |
| * The file containing synchronization information |
| * @throws IOException |
| * If the file couldn't be opened for some reason |
| */ |
| public SynchronizationBackend(File syncFile) throws IOException { |
| this(syncFile, true); |
| } |
| |
| /** |
| * Constructor with possibility to tell whether to throw errors on exception |
| * or not |
| * |
| * @param syncFile |
| * The file containing synchronization information |
| * @param throwErrors |
| * Whether to throw exceptions or not |
| * @throws IOException |
| * If the file couldn't be opened for some reason |
| */ |
| public SynchronizationBackend(File syncFile, boolean throwErrors) throws IOException { |
| /* |
| * Open the file ourselves, get the header information we need, then |
| * pass on the descriptor. |
| */ |
| int res; |
| |
| fSyncFile = syncFile; |
| |
| if (syncFile == null) { |
| return; |
| } |
| |
| if (!syncFile.exists()) { |
| if (throwErrors) { |
| throw new IOException("Selected synchronization file does not exist"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| if (syncFile.length() <= 0) { |
| if (throwErrors) { |
| throw new IOException("Invalid synchronization file selected, " + //$NON-NLS-1$ |
| "target file is empty"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| |
| try (FileInputStream fis = new FileInputStream(syncFile); |
| FileChannel fc = fis.getChannel();) { |
| ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE); |
| buffer.clear(); |
| fc.read(buffer); |
| buffer.flip(); |
| |
| /* |
| * Check the magic number,to make sure we're opening the right type |
| * of file |
| */ |
| res = buffer.getInt(); |
| if (res != SYNC_FILE_MAGIC_NUMBER) { |
| throw new IOException("Selected file does not" + //$NON-NLS-1$ |
| "look like a synchronization file"); //$NON-NLS-1$ |
| } |
| |
| res = buffer.getInt(); /* Major version number */ |
| if (res != FILE_VERSION) { |
| throw new IOException("Select synchronization file is of an older " //$NON-NLS-1$ |
| + "format. Synchronization will have to be computed again."); //$NON-NLS-1$ |
| } |
| |
| res = buffer.getInt(); /* Minor version number */ |
| } |
| } |
| |
| /** |
| * Opens an existing synchronization file |
| * |
| * @return The synchronization algorithm contained in the file |
| * @throws IOException |
| * Exception returned file functions |
| */ |
| public SynchronizationAlgorithm openExistingSync() throws IOException { |
| |
| if (fSyncFile == null) { |
| return null; |
| } |
| |
| try (/* Set the position after the header */ |
| FileInputStream fis = new FileInputStream(fSyncFile); |
| FileChannel fc = fis.getChannel().position(HEADER_SIZE); |
| /* Read the input stream */ |
| ObjectInputStream ois = new ObjectInputStream(fis);) { |
| |
| return (SynchronizationAlgorithm) ois.readObject(); |
| } catch (ClassNotFoundException e) { |
| return null; |
| } |
| |
| |
| } |
| |
| /** |
| * Saves the synchronization algorithm object to file |
| * |
| * @param syncAlgo |
| * The algorithm to save |
| * @throws FileNotFoundException |
| * propagate callee's exceptions |
| */ |
| public void saveSync(SynchronizationAlgorithm syncAlgo) throws FileNotFoundException { |
| |
| if (fSyncFile == null) { |
| return; |
| } |
| |
| /* Save the header of the file */ |
| try (FileOutputStream fos = new FileOutputStream(fSyncFile, false); |
| FileChannel fc = fos.getChannel();) { |
| |
| ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE); |
| buffer.clear(); |
| |
| fc.position(0); |
| |
| buffer.putInt(SYNC_FILE_MAGIC_NUMBER); |
| |
| buffer.putInt(FILE_VERSION); |
| |
| buffer.flip(); |
| int res = fc.write(buffer); |
| if (res > HEADER_SIZE) { |
| throw new IOException("Wrote more data than the header size"); //$NON-NLS-1$ |
| } |
| /* done writing the file header */ |
| |
| fc.position(HEADER_SIZE); |
| |
| try (ObjectOutputStream oos = new ObjectOutputStream(fos);) { |
| oos.writeObject(syncAlgo); |
| } |
| |
| } catch (FileNotFoundException e) { |
| /* Send this upwards */ |
| throw e; |
| } catch (IOException e) { |
| /* Handle other cases of IOException's */ |
| Activator.logError("Error saving trace synchronization data", e); //$NON-NLS-1$ |
| } |
| return; |
| |
| } |
| |
| } |