/* * Copyright (c) 2010 The Jackson Laboratory * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This software 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. If not, see <http://www.gnu.org/licenses/>. */ package org.jax.maanova.project; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.swing.filechooser.FileFilter; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import org.jax.maanova.jaxbgenerated.JMaanovaProjectMetadata; import org.jax.r.CleanEnvironmentCommand; import org.jax.r.RUtilities; import org.jax.r.jriutilities.RInterface; import org.jax.r.jriutilities.RInterfaceFactory; import org.jax.r.jriutilities.SilentRCommand; import org.jax.util.ConfigurationUtilities; import org.jax.util.io.FileChooserExtensionFilter; import org.jax.util.io.FileUtilities; import org.jax.util.project.ProjectManager; /** * The project manager for J/maanova * @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A> */ public class MaanovaProjectManager extends ProjectManager { /** * File extension used for j-maanova project files */ public static final String MAANOVA_PROJECT_EXTENSION = "jmaanova"; private static final FileFilter MAANOVA_PROJECT_FILE_FILTER = new FileChooserExtensionFilter( MAANOVA_PROJECT_EXTENSION, "J/maanova Project (*.jmaanova)"); private static final MaanovaProjectManager instance = new MaanovaProjectManager( RInterfaceFactory.getRInterfaceInstance()); private static final Logger LOG = Logger.getLogger( MaanovaProjectManager.class.getName()); private final RInterface rInterface; /** * the file name that is used for project metadata */ private static final String PROJECT_METADATA_FILENAME_1_0_0 = "project-metadata-1.0.0.xml"; /** * the file name that is used for R data */ private static final String PROJECT_R_DATA_FILENAME = "maanova-data.RData"; /** * the temporary directory name that we use for short-term storage of * project data (in the long term, project data is stored in a * zip file... usually with a .jmaanova extension) */ private static final String TEMP_PROJECT_DIR_NAME = "temp-proj"; /** * the jaxb context for marshalling and unmarshalling */ private JAXBContext jaxbContext; /** * Constructor * @param rInterface * the R interface to use */ public MaanovaProjectManager(final RInterface rInterface) { this.rInterface = rInterface; try { this.jaxbContext = JAXBContext.newInstance( JMaanovaProjectMetadata.class); } catch(JAXBException ex) { LOG.log(Level.SEVERE, "failed to initialize project manager", ex); } this.createNewActiveProject(); } /** * {@inheritDoc} */ @Override public MaanovaProject createNewActiveProject() { // clear the current r data this.rInterface.evaluateCommand(new SilentRCommand( new CleanEnvironmentCommand())); this.setActiveProjectFile(null); this.setActiveProjectModified(false); MaanovaProject newProject = new MaanovaProject(this.rInterface); this.setActiveProject(newProject); return newProject; } /** * Getter for the instance. * @return the instance */ public static MaanovaProjectManager getInstance() { return MaanovaProjectManager.instance; } /** * {@inheritDoc} */ @Override public FileFilter getProjectFileFilter() { return MAANOVA_PROJECT_FILE_FILTER; } /** * {@inheritDoc} */ @Override public void refreshProjectDataStructures() { this.getActiveProject().getDataModel().updateAll(); } /** * {@inheritDoc} */ @Override public MaanovaProject getActiveProject() { return (MaanovaProject)super.getActiveProject(); } /** * {@inheritDoc} */ @Override public boolean saveActiveProject(File projectFile) { try { File tempProjDir = this.getCleanedTempProjectDir(); if(tempProjDir == null) { return false; } else { try { // create temp r data file File rDataFile = new File(tempProjDir, PROJECT_R_DATA_FILENAME); String saveDataCommandString = "save(list = ls(), file = " + RUtilities.javaStringToRString(rDataFile.getAbsolutePath()) + ")"; this.rInterface.evaluateCommand( new SilentRCommand(saveDataCommandString)); // create temp metadata file FileOutputStream configFileOut = new FileOutputStream( new File(tempProjDir, PROJECT_METADATA_FILENAME_1_0_0)); Marshaller marshaller = this.jaxbContext.createMarshaller(); marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.marshal( this.getActiveProject().getMetadata(), configFileOut); configFileOut.close(); // zip up the directory and save it to the file ZipOutputStream zipOut = new ZipOutputStream( new FileOutputStream(projectFile)); FileUtilities.compressDirectoryToZip( tempProjDir, zipOut); zipOut.close(); // update and notify this.setActiveProjectFile(projectFile); this.setActiveProjectModified(false); } finally { // blow away the temp dir FileUtilities.recursiveDelete(tempProjDir); } return true; } } catch(Exception ex) { LOG.log(Level.SEVERE, "caught exception saving project data", ex); return false; } } /** * Get a clean version of the temporary project directory. * @return * return the project directory */ private File getCleanedTempProjectDir() { try { ConfigurationUtilities configurationUtilities = new ConfigurationUtilities(); File configDir = configurationUtilities.getBaseDirectory(); File tempProjDir = new File(configDir, TEMP_PROJECT_DIR_NAME); if(tempProjDir.exists()) { if(LOG.isLoggable(Level.FINE)) { LOG.fine( "Temporary project directory already exists: " + tempProjDir); } if(!FileUtilities.recursiveDelete(tempProjDir)) { return null; } } if(tempProjDir.mkdir()) { return tempProjDir; } else { LOG.warning( "Failed to create temporary project directory"); return null; } } catch(Exception ex) { LOG.log(Level.SEVERE, "failed to clean temporary project directory", ex); return null; } } /** * {@inheritDoc} */ @Override public boolean loadActiveProject(File projectFile) { try { File tempProjDir = this.getCleanedTempProjectDir(); if(tempProjDir == null) { return false; } else { try { // expand project file to temp dir ZipInputStream zipIn = new ZipInputStream( new FileInputStream(projectFile)); FileUtilities.unzipToDirectory( zipIn, tempProjDir); // clear the current r data this.rInterface.evaluateCommand(new SilentRCommand( "rm(list=ls())")); // load the r data File rDataFile = new File(tempProjDir, PROJECT_R_DATA_FILENAME); this.rInterface.evaluateCommandNoReturn(new SilentRCommand( new CleanEnvironmentCommand())); String loadDataCommandString = "load(" + RUtilities.javaStringToRString(rDataFile.getAbsolutePath()) + ")"; this.rInterface.evaluateCommand(new SilentRCommand( loadDataCommandString)); // load the meta data InputStream configFileIn = new FileInputStream(new File( tempProjDir, PROJECT_METADATA_FILENAME_1_0_0)); Unmarshaller unmarshaller = this.jaxbContext.createUnmarshaller(); JMaanovaProjectMetadata jaxbProjectMetatata = (JMaanovaProjectMetadata)unmarshaller.unmarshal(configFileIn); // create the project MaanovaProject newProject = new MaanovaProject( this.rInterface, jaxbProjectMetatata); // update and notify this.setActiveProjectFile(projectFile); this.setActiveProjectModified(false); this.setActiveProject(newProject); } finally { // blow away the temp dir FileUtilities.recursiveDelete(tempProjDir); } return true; } } catch(Exception ex) { LOG.log(Level.SEVERE, "caught exception loading project data", ex); return false; } } }