/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.repository.local;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.ports.metadata.AttributeMetaData;
import com.rapidminer.operator.ports.metadata.ExampleSetMetaData;
import com.rapidminer.operator.ports.metadata.MetaData;
import com.rapidminer.operator.tools.ExampleSetToStream;
import com.rapidminer.operator.tools.IOObjectSerializer;
import com.rapidminer.operator.tools.RMObjectInputStream;
import com.rapidminer.repository.Folder;
import com.rapidminer.repository.IOObjectEntry;
import com.rapidminer.repository.RepositoryException;
import com.rapidminer.tools.ProgressListener;
/** Stores IOObject in a file. Either as IOO serialized files using
* {@link ExampleSetToStream} where appropriate.
*
* @author Simon Fischer
*
*/
public class SimpleIOObjectEntry extends SimpleDataEntry implements IOObjectEntry {
private static final String PROPERTY_IOOBJECT_CLASS = "ioobject-class";
private SoftReference<MetaData> metaData = null;
private Class<? extends IOObject> dataObjectClass = null;
SimpleIOObjectEntry(String name, SimpleFolder containingFolder, LocalRepository repository) {
super(name, containingFolder, repository);
}
private File getDataFile() {
return new File(((SimpleFolder)getContainingFolder()).getFile(), getName()+".ioo");
}
protected File getMetaDataFile() {
return new File(((SimpleFolder)getContainingFolder()).getFile(), getName()+".md");
}
@Override
public IOObject retrieveData(ProgressListener l) throws RepositoryException {
if (l != null) {
l.setTotal(100);
l.setCompleted(10);
}
File dataFile = getDataFile();
if (dataFile.exists()) {
try {
return (IOObject)IOObjectSerializer.getInstance().deserialize(new BufferedInputStream(new FileInputStream(dataFile)));
} catch (Exception e) {
throw new RepositoryException("Cannot load data from '"+dataFile+"': "+e, e);
}
} else {
throw new RepositoryException("File '"+dataFile+" does not exist'.");
}
}
@Override
public MetaData retrieveMetaData() throws RepositoryException {
if (metaData != null) {
MetaData storedData = metaData.get();
if (storedData != null) {
return storedData;
}
}
// otherwise metaData == null OR get() == null -> re-read
MetaData readObject;
File metaDataFile = getMetaDataFile();
if (metaDataFile.exists()) {
ObjectInputStream objectIn = null;
try {
objectIn = new RMObjectInputStream(new FileInputStream(metaDataFile));
readObject = (MetaData)objectIn.readObject();
this.metaData = new SoftReference<MetaData>(readObject);
if (readObject instanceof ExampleSetMetaData) {
for (AttributeMetaData amd : ((ExampleSetMetaData)readObject).getAllAttributes()) {
if (amd.isNominal()) {
amd.shrinkValueSet();
}
}
}
objectIn.close();
} catch (Exception e) {
throw new RepositoryException("Cannot load meta data from '"+metaDataFile+"': "+e, e);
} finally {
if (objectIn != null) {
try {
objectIn.close();
} catch (IOException e) { }
}
}
} else {
throw new RepositoryException("Meta data file '"+metaDataFile+" does not exist'.");
}
return readObject;
}
@Override
public void storeData(IOObject data, Operator callingOperator, ProgressListener l) throws RepositoryException {
if (l != null) {
l.setTotal(100);
l.setCompleted(10);
}
MetaData md = MetaData.forIOObject(data);
// Serialize Non-ExampleSets as IOO
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(getDataFile()));
IOObjectSerializer.getInstance().serialize(out, data);
if (l != null) {
l.setCompleted(75);
}
} catch (Exception e) {
throw new RepositoryException("Cannot store data at '"+getDataFile()+"': "+e, e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) { }
}
}
// Save MetaData
ObjectOutputStream mdOut = null;
try {
mdOut = new ObjectOutputStream(new FileOutputStream(getMetaDataFile()));
mdOut.writeObject(md);
mdOut.close();
if (l != null) {
l.setCompleted(90);
}
} catch (Exception e) {
throw new RepositoryException("Cannot store data at '"+getMetaDataFile()+"': "+e, e);
} finally {
if (mdOut != null) {
try {
mdOut.close();
} catch (IOException e) { }
}
if (l != null) {
l.setCompleted(100);
l.complete();
}
}
this.metaData = new SoftReference<MetaData>(md);
putProperty(PROPERTY_IOOBJECT_CLASS, data.getClass().getName());
}
@Override
public String getType() {
return IOObjectEntry.TYPE_NAME;
}
@Override
public String getDescription() {
if (metaData != null) {
MetaData md = metaData.get();
if (md != null) {
return md.getDescription();
} else {
return "Simple entry.";
}
} else {
return "Simple entry.";
}
}
@Override
public long getSize() {
if (getDataFile().exists()) {
return getDataFile().length();
} else {
return 0;
}
}
@Override
public void delete() throws RepositoryException {
if (getDataFile().exists()) {
getDataFile().delete();
}
if (getMetaDataFile().exists()) {
getMetaDataFile().delete();
}
super.delete();
}
@Override
public boolean rename(String newName) {
renameFile(getDataFile(), newName);
renameFile(getMetaDataFile(), newName);
return super.rename(newName);
}
@Override
public boolean move(Folder newParent) {
moveFile(getDataFile(), ((SimpleFolder)newParent).getFile());
moveFile(getMetaDataFile(), ((SimpleFolder)newParent).getFile());
return super.move(newParent);
};
@Override
public long getDate() {
return getDataFile().lastModified();
}
@Override
public boolean willBlock() {
return (metaData == null) || (metaData.get() == null);
}
@SuppressWarnings("unchecked")
@Override
public Class<? extends IOObject> getObjectClass() {
if (dataObjectClass == null) {
// first try from properties file
String className = getProperty(PROPERTY_IOOBJECT_CLASS);
if (className != null) {
try {
dataObjectClass = (Class<? extends IOObject>) Class.forName(className);
return dataObjectClass;
} catch (ClassNotFoundException e) {
return null;
}
} else {
// if not yet defined, retrieve it from meta data and store in properties
try {
dataObjectClass = retrieveMetaData().getObjectClass();
if (dataObjectClass != null) {
putProperty(PROPERTY_IOOBJECT_CLASS, dataObjectClass.getName());
}
return dataObjectClass;
} catch (RepositoryException e) {
return null;
}
}
}
return dataObjectClass;
}
}