/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.data.mapinfo.mif; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.data.FeatureStoreRuntimeException; import org.geotoolkit.data.FeatureWriter; import java.io.*; import java.util.UUID; import java.util.logging.Level; import org.apache.sis.util.ArgumentChecks; import org.opengis.feature.Feature; import org.opengis.feature.FeatureType; /** * An iterator to write features into MIF/MID files. * * @author Alexis Manin (Geomatys) * Date : 06/03/13 */ public class MIFFeatureWriter implements FeatureWriter { private final MIFManager master; private MIFFeatureReader reader; private final FeatureType writeType; private Feature currentFeature; private int featureCount = 0; private File tmpMifFile; private FileWriter tmpMifWriter; private File tmpMidFile; private FileWriter tmpMidWriter; public MIFFeatureWriter(MIFManager parent, MIFFeatureReader readingIterator) throws DataStoreException { ArgumentChecks.ensureNonNull("File manager", parent); ArgumentChecks.ensureNonNull("MIF reader", readingIterator); master = parent; reader = readingIterator; writeType = reader.getFeatureType(); // Initialize temp containers try { tmpMidFile = File.createTempFile(UUID.randomUUID().toString(), ".mid"); tmpMifFile = File.createTempFile(UUID.randomUUID().toString(), ".mif"); tmpMidFile.deleteOnExit(); tmpMifFile.deleteOnExit(); tmpMifWriter = new FileWriter(tmpMifFile); tmpMidWriter = new FileWriter(tmpMidFile); } catch (IOException e) { throw new DataStoreException("Unable to initialize Feature writer.", e); } } @Override public FeatureType getFeatureType() { return writeType; } @Override public Feature next() throws FeatureStoreRuntimeException { if (reader == null) { throw new FeatureStoreRuntimeException("Writer has been closed"); } // we have to write the current feature back into the stream if (currentFeature != null) { write(); } // is there another? If so, return it if (reader.hasNext()) { try { return currentFeature = reader.next(); } catch (IllegalArgumentException iae) { throw new FeatureStoreRuntimeException("Error in reading", iae); } } // reader has no more elements, switch to append mode. try { currentFeature = writeType.newInstance(); return currentFeature; } catch (IllegalArgumentException iae) { throw new FeatureStoreRuntimeException("Error creating empty Feature", iae); } } @Override public boolean hasNext() throws FeatureStoreRuntimeException { if (reader == null) { throw new FeatureStoreRuntimeException("Writer has been closed"); } return reader.hasNext(); } @Override public void remove() throws FeatureStoreRuntimeException { if (reader == null) { throw new FeatureStoreRuntimeException("Writer has been closed."); } if (currentFeature == null) { throw new FeatureStoreRuntimeException("The feature writer does not point on any feature."); } // mark current feature as null, so it won't be rewritten to the stream currentFeature = null; } @Override public void write() throws FeatureStoreRuntimeException { if (currentFeature == null) { throw new FeatureStoreRuntimeException("There's no feature to write (null value)."); } if (reader == null) { throw new FeatureStoreRuntimeException("Writer has been closed"); } try { final String mifGeom = MIFUtils.buildMIFGeometry(currentFeature); tmpMifWriter.write(mifGeom); } catch (Exception e) { throw new FeatureStoreRuntimeException("A problem occurred while building geometry.", e); } try { if (master.getBaseType() != null && master.getBaseType().getProperties(true).size()> 0) { final String midAttributes = master.buildMIDAttributes(currentFeature); tmpMidWriter.write(midAttributes); } } catch (Exception e) { throw new FeatureStoreRuntimeException("A problem occurred while building MID attributes.", e); } currentFeature = null; } @Override public void close() throws FeatureStoreRuntimeException { if (reader == null) { throw new FeatureStoreRuntimeException("Writer has already been closed"); } // make sure to write the last feature... if (currentFeature != null) { write(); } reader.close(); reader = null; try { tmpMidWriter.close(); tmpMidWriter = null; } catch (Exception e) { MIFManager.LOGGER.log(Level.WARNING, "Temporary MIF data writer can't be closed", e); } try { tmpMifWriter.close(); tmpMifWriter = null; } catch (Exception e) { MIFManager.LOGGER.log(Level.WARNING, "Temporary MIF data writer can't be closed", e); } try { flush(); } catch(Exception ex) { throw new FeatureStoreRuntimeException("Data flushing impossible, there's a possibility of data loss."); } finally { tmpMidFile.delete(); tmpMifFile.delete(); } } /** * In case someone doesn't close me. */ @Override protected void finalize() { if (reader != null) { try { close(); } catch (Exception e) { MIFManager.LOGGER.log(Level.WARNING, "Can't close MIF feature writer", e); } } } /** * Update the real MIF file. */ private void flush() throws IOException { try { master.flushData(this); } catch (DataStoreException e) { throw new IOException("A problem have been encountered while writing file header."); } } /** * Get input stream to temporary geometry data. * @return A {@link FileInputStream} pointing to the temporary file containing MIF geometry. * @throws FileNotFoundException If we can't retrieve the temp data. */ public InputStream getMIFTempStore() throws FileNotFoundException { return new FileInputStream(tmpMifFile); } /** * Get input stream to temporary attribute data. * @return A {@link FileInputStream} pointing to the temporary file containing MID attributes. * @throws FileNotFoundException If we can't retrieve the temp data. */ public InputStream getMIDTempStore() throws FileNotFoundException { return new FileInputStream(tmpMidFile); } }