/* * #! * % * Copyright (C) 2014 - 2016 Humboldt-Universität zu Berlin * % * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #_ */ package de.hub.cs.dbis.lrb.toll; 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.util.LinkedList; import java.util.Queue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import storm.lrb.model.TollEntry; /** * A {@link TollDataStore} that uses a file for storage including all disadvantages. Use only in a very simple topology * as the file I/O can easily produce a performance bottleneck. * * @author richter */ public class FileTollDataStore implements TollDataStore { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(FileTollDataStore.class); private final File histFile; private boolean firstWriteDone = false; /** * Creates a {@code FileTollDataStore} using a temporary file * * @throws java.io.IOException * if the creation of the temporary file fails */ public FileTollDataStore() throws IOException { this.histFile = File.createTempFile("aeolus-lrb", null); } /** * Creates a {@code FileTollDataStore} reading from {@code histFile}. * * @param histFile */ public FileTollDataStore(File histFile) { this.histFile = histFile; } /** * * @param histFilePath * @throws FileNotFoundException * if the file denoted by {@code histFilePath} doesn't exist * @throws IllegalArgumentException * if {@code histFilePath} is {@code null} or empty. */ public FileTollDataStore(String histFilePath) throws FileNotFoundException { if(histFilePath == null) { throw new IllegalArgumentException("histFilePath mustn't be null."); } if(histFilePath.isEmpty()) { throw new IllegalArgumentException("no filename for historic data given."); } this.histFile = new File(histFilePath); } @Override public Integer retrieveToll(int xWay, int day, int vehicleIdentifier) { ObjectInputStream objectInputStream = null; try { FileInputStream is = new FileInputStream(this.histFile); objectInputStream = new ObjectInputStream(is); Object nextObject = objectInputStream.readObject(); while(nextObject != null) { TollEntry next = (TollEntry)nextObject; if(next.getxWay() == xWay && next.getADay() == day && next.getVehicleIdentifier() == vehicleIdentifier) { return next.getToll(); } } objectInputStream.close(); is.close(); } catch(IOException ex) { throw new RuntimeException(ex); } catch(ClassNotFoundException ex) { throw new RuntimeException(ex); } finally { if(objectInputStream != null) { try { objectInputStream.close(); } catch(IOException e) { LOG.error("Could not close file input stream of " + this.histFile, e); } } } return null; } @Override public void storeToll(int xWay, int day, int vehicleIdentifier, int toll) { try { if(!this.firstWriteDone) { FileOutputStream os = new FileOutputStream(this.histFile, true // append ); ObjectOutputStream objectOutputStream = new ObjectOutputStream(os); objectOutputStream.writeObject(null); objectOutputStream.flush(); objectOutputStream.close(); os.flush(); os.close(); this.firstWriteDone = true; } FileInputStream is = new FileInputStream(this.histFile); ObjectInputStream objectInputStream = new ObjectInputStream(is); File tmpStoreFile = File.createTempFile("aeolus-lrb", null); FileOutputStream os = new FileOutputStream(tmpStoreFile); ObjectOutputStream objectOutputStream = new ObjectOutputStream(os); Object nextObject = objectInputStream.readObject(); Queue<Object> tmpStore = new LinkedList<Object>(); while(nextObject != null) { tmpStore.add(nextObject); if(tmpStore.size() > 1000) { while(!tmpStore.isEmpty()) { objectOutputStream.writeObject(tmpStore.poll()); } } nextObject = objectInputStream.readObject(); } TollEntry newTollEntry = new TollEntry(vehicleIdentifier, xWay, day, toll); objectOutputStream.writeObject(newTollEntry); objectOutputStream.writeObject(null); objectInputStream.close(); objectOutputStream.close(); is.close(); os.close(); this.histFile.delete(); tmpStoreFile.renameTo(this.histFile); } catch(IOException ex) { throw new RuntimeException(ex); } catch(ClassNotFoundException ex) { throw new RuntimeException(ex); } } @Override public Integer removeEntry(int xWay, int day, int vehicleIdentifier) { Integer retValue = null; try { FileInputStream is = new FileInputStream(this.histFile); ObjectInputStream objectInputStream = new ObjectInputStream(is); File tmpStoreFile = File.createTempFile("aeolus-lrb", null); FileOutputStream os = new FileOutputStream(tmpStoreFile); ObjectOutputStream objectOutputStream = new ObjectOutputStream(os); Object nextObject = objectInputStream.readObject(); Queue<Object> tmpStore = new LinkedList<Object>(); while(nextObject != null) { TollEntry next = (TollEntry)nextObject; if(!(next.getxWay() == xWay && next.getADay() == day && next.getVehicleIdentifier() == vehicleIdentifier)) { tmpStore.add(nextObject); if(tmpStore.size() > 1000) { while(!tmpStore.isEmpty()) { objectOutputStream.writeObject(tmpStore.poll()); } } } else { retValue = next.getToll(); } nextObject = objectInputStream.readObject(); } objectOutputStream.writeObject(null); objectInputStream.close(); objectOutputStream.close(); is.close(); os.close(); this.histFile.delete(); tmpStoreFile.renameTo(this.histFile); } catch(IOException ex) { throw new RuntimeException(ex); } catch(ClassNotFoundException ex) { throw new RuntimeException(ex); } return retValue; } }