/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* 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 org.constellation.sos.io.filesystem;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.xml.MarshallerPool;
import org.constellation.generic.database.Automatic;
import org.constellation.metadata.io.MetadataIoException;
import org.constellation.sos.factory.SMLFactory;
import org.constellation.sos.io.SensorWriter;
import org.constellation.ws.CstlServiceException;
import org.geotoolkit.sml.xml.AbstractSensorML;
import org.geotoolkit.sml.xml.SensorMLMarshallerPool;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.geotoolkit.ows.xml.OWSExceptionCode.NO_APPLICABLE_CODE;
/**
* A sensorML Writer working on a fileSystem.
*
* @author Guilhem Legal (Geomatys)
*/
public class FileSensorWriter implements SensorWriter {
/**
* use for debugging purpose
*/
protected static final Logger LOGGER = Logging.getLogger("org.constellation.sos");
/**
* A JAXB unmarshaller used to unmarshall the xml generated by the XMLWriter.
*/
private final MarshallerPool marshallerPool;
/**
* The directory where the data file are stored
*/
private final File dataDirectory;
/**
* Contains the files written during a transaction.
* If the transaction is aborted, all these files will be deleted.
*/
private List<File> uncommittedFiles;
/**
* The base identifier of all the sensor.
*/
private final String sensorIdBase;
public FileSensorWriter(final Automatic configuration, final Map<String, Object> properties) throws MetadataIoException {
if (configuration == null) {
throw new MetadataIoException("The sensor configuration object is null", NO_APPLICABLE_CODE);
}
this.sensorIdBase = (String) properties.get(SMLFactory.SENSOR_ID_BASE);
uncommittedFiles = new ArrayList<>();
if (configuration.getDataDirectory() == null) {
throw new MetadataIoException("The sensor data directory is null", NO_APPLICABLE_CODE);
}
this.dataDirectory = configuration.getDataDirectory();
this.marshallerPool = SensorMLMarshallerPool.getInstance();
if (marshallerPool == null) {
throw new MetadataIoException("Unable to initialize the fileSensorWriter JAXB context", NO_APPLICABLE_CODE);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean writeSensor(String id, final AbstractSensorML sensor) throws CstlServiceException {
try {
final Marshaller marshaller = marshallerPool.acquireMarshaller();
id = id.replace(":", "-");
final File currentFile = new File(dataDirectory, id + ".xml");
if (!currentFile.exists()) {
final boolean create = currentFile.createNewFile();
if (!create) {
throw new CstlServiceException("the service was unable to create a new file:" + currentFile.getName(), NO_APPLICABLE_CODE);
}
} else {
LOGGER.log(Level.WARNING, "we overwrite the file: {0}", currentFile.getPath());
}
marshaller.marshal(sensor, currentFile);
marshallerPool.recycle(marshaller);
} catch (JAXBException ex) {
String msg = ex.getMessage();
if (msg == null && ex.getCause() != null) {
msg = ex.getCause().getMessage();
}
throw new CstlServiceException("the service has throw a JAXB Exception:" + msg,
ex, NO_APPLICABLE_CODE);
} catch (IOException ex) {
String msg = ex.getMessage();
if (msg == null && ex.getCause() != null) {
msg = ex.getCause().getMessage();
}
throw new CstlServiceException("the service has throw a IO Exception:" + msg,
ex, NO_APPLICABLE_CODE);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean deleteSensor(String id) throws CstlServiceException {
id = id.replace(":", "-");
final File currentFile = new File(dataDirectory, id + ".xml");
boolean delete = false;
if (currentFile.exists()) {
delete = currentFile.delete();
} else {
LOGGER.log(Level.WARNING, "unable to find a file {0} to remove", currentFile.getName());
return false;
}
if (!delete) {
throw new CstlServiceException("the service was unable to delete the file:" + currentFile.getName(), NO_APPLICABLE_CODE);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public int replaceSensor(String id, final AbstractSensorML sensor) throws CstlServiceException {
try {
final Marshaller marshaller = marshallerPool.acquireMarshaller();
id = id.replace(":", "-");
final File currentFile = new File(dataDirectory, id + ".xml");
marshaller.marshal(sensor, currentFile);
marshallerPool.recycle(marshaller);
return 1;//AbstractMetadataWriter.REPLACED;
} catch (JAXBException ex) {
String msg = ex.getMessage();
if (msg == null && ex.getCause() != null) {
msg = ex.getCause().getMessage();
}
throw new CstlServiceException("the service has throw a JAXB Exception:" + msg,
ex, NO_APPLICABLE_CODE);
}
}
/**
* {@inheritDoc}
*/
@Override
public void startTransaction() throws CstlServiceException {
uncommittedFiles = new ArrayList<>();
}
/**
* {@inheritDoc}
*/
@Override
public void abortTransaction() throws CstlServiceException {
for (File f: uncommittedFiles) {
final boolean delete = f.delete();
if (!delete) {
LOGGER.log(Level.WARNING, "unable to delete the file:{0}", f.getName());
}
}
uncommittedFiles = new ArrayList<>();
}
/**
* {@inheritDoc}
*/
@Override
public void endTransaction() throws CstlServiceException {
uncommittedFiles = new ArrayList<>();
}
/**
* {@inheritDoc}
*/
@Override
public int getNewSensorId() throws CstlServiceException {
int maxID = 0;
if (dataDirectory != null) {
for (File f : dataDirectory.listFiles()) {
String id = f.getName();
id = id.substring(0, id.indexOf(".xml"));
if (id.startsWith(sensorIdBase)) {
id = id.substring(id.indexOf(sensorIdBase) + sensorIdBase.length());
try {
final int curentID = Integer.parseInt(id);
if (curentID > maxID) {
maxID = curentID;
}
} catch (NumberFormatException ex) {
throw new CstlServiceException("unable to parse the identifier:" + id, ex, NO_APPLICABLE_CODE);
}
}
}
}
return maxID + 1;
}
/**
* {@inheritDoc}
*/
@Override
public void destroy() {
if (uncommittedFiles != null) {
uncommittedFiles.clear();
}
}
/**
* {@inheritDoc}
*/
@Override
public String getInfos() {
return "Constellation Filesystem Sensor Writer 0.9";
}
}