You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/20 15:22:49 UTC
[35/51] [abbrv] [partial] incubator-taverna-workbench git commit:
taverna-workbench-* -> taverna-*
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-file-impl/pom.xml b/taverna-file-impl/pom.xml
new file mode 100644
index 0000000..bf0e019
--- /dev/null
+++ b/taverna-file-impl/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.workbench</groupId>
+ <artifactId>taverna-workbench</artifactId>
+ <version>3.1.0-incubating-SNAPSHOT</version>
+ </parent>
+ <artifactId>taverna-file-impl</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Taverna File opening implementation</name>
+ <description>
+ Implementation for doing file (i.e. workflow) open/save in the
+ workbench.
+ </description>
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-file-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-edits-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-helper-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-menu-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-workbench-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.engine</groupId>
+ <artifactId>taverna-observer</artifactId>
+ <version>${taverna.engine.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-app-configuration-api</artifactId>
+ <version>${taverna.osgi.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-api</artifactId>
+ <version>${taverna.language.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>${log4j.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>${commons.collections.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>com.springsource.org.apache.commons.lang</artifactId>
+ <version>${commons.lang.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>${commons.codec.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jdom</groupId>
+ <artifactId>com.springsource.org.jdom</artifactId>
+ <version>${jdom.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-edits-impl</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-wfbundle</artifactId>
+ <version>${taverna.language.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.taverna.language</groupId>
+ <artifactId>taverna-scufl2-t2flow</artifactId>
+ <version>${taverna.language.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowFromDataflowPersistenceHandler.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowFromDataflowPersistenceHandler.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowFromDataflowPersistenceHandler.java
new file mode 100644
index 0000000..86bc091
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowFromDataflowPersistenceHandler.java
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * @author alanrw
+ */
+public class DataflowFromDataflowPersistenceHandler extends
+ AbstractDataflowPersistenceHandler implements
+ DataflowPersistenceHandler {
+ private static final WorkflowBundleFileType WORKFLOW_BUNDLE_FILE_TYPE = new WorkflowBundleFileType();
+
+ @Override
+ public DataflowInfo openDataflow(FileType fileType, Object source)
+ throws OpenException {
+ if (!getOpenFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+
+ WorkflowBundle workflowBundle = (WorkflowBundle) source;
+ Date lastModified = null;
+ Object canonicalSource = null;
+ return new DataflowInfo(WORKFLOW_BUNDLE_FILE_TYPE, canonicalSource,
+ workflowBundle, lastModified);
+ }
+
+ @Override
+ public List<FileType> getOpenFileTypes() {
+ return Arrays.<FileType> asList(WORKFLOW_BUNDLE_FILE_TYPE);
+ }
+
+ @Override
+ public List<Class<?>> getOpenSourceTypes() {
+ return Arrays.<Class<?>> asList(Workflow.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowPersistenceHandlerRegistry.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowPersistenceHandlerRegistry.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowPersistenceHandlerRegistry.java
new file mode 100644
index 0000000..39117e9
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/DataflowPersistenceHandlerRegistry.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import static org.apache.commons.collections.map.LazyMap.decorate;
+import static org.apache.commons.lang.ClassUtils.getAllInterfaces;
+import static org.apache.commons.lang.ClassUtils.getAllSuperclasses;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+
+import org.apache.commons.collections.Factory;
+
+// TODO: Cache lookups / build one massive structure
+public class DataflowPersistenceHandlerRegistry {
+ private static final MapFactory MAP_FACTORY = new MapFactory();
+ private static final SetFactory SET_FACTORY = new SetFactory();
+
+ @SuppressWarnings("unchecked")
+ protected static List<Class<?>> findAllParentClasses(
+ final Class<?> sourceClass) {
+ List<Class<?>> superClasses = new ArrayList<>();
+ superClasses.add(sourceClass);
+ superClasses.addAll(getAllSuperclasses(sourceClass));
+ superClasses.addAll(getAllInterfaces(sourceClass));
+ return superClasses;
+ }
+
+ private Map<Class<?>, Set<DataflowPersistenceHandler>> openClassToHandlers;
+ private Map<Class<?>, Set<FileType>> openClassToTypes;
+ private Map<FileType, Map<Class<?>, Set<DataflowPersistenceHandler>>> openFileClassToHandler;
+ private Map<FileType, Set<DataflowPersistenceHandler>> openFileToHandler;
+ private Map<Class<?>, Set<DataflowPersistenceHandler>> saveClassToHandlers;
+ private Map<Class<?>, Set<FileType>> saveClassToTypes;
+ private Map<FileType, Map<Class<?>, Set<DataflowPersistenceHandler>>> saveFileClassToHandler;
+ private Map<FileType, Set<DataflowPersistenceHandler>> saveFileToHandler;
+
+ private List<DataflowPersistenceHandler> dataflowPersistenceHandlers;
+
+ public DataflowPersistenceHandlerRegistry() {
+ }
+
+ public Set<FileType> getOpenFileTypes() {
+ return getOpenFileClassToHandler().keySet();
+ }
+
+ public Set<FileType> getOpenFileTypesFor(Class<?> sourceClass) {
+ Set<FileType> fileTypes = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(sourceClass))
+ fileTypes.addAll(getOpenClassToTypes().get(candidateClass));
+ return fileTypes;
+ }
+
+ public Set<DataflowPersistenceHandler> getOpenHandlersFor(
+ Class<? extends Object> sourceClass) {
+ Set<DataflowPersistenceHandler> handlers = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(sourceClass))
+ handlers.addAll(getOpenClassToHandlers().get(candidateClass));
+ return handlers;
+ }
+
+ public Set<DataflowPersistenceHandler> getOpenHandlersFor(
+ FileType fileType, Class<? extends Object> sourceClass) {
+ Set<DataflowPersistenceHandler> handlers = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(sourceClass))
+ handlers.addAll(getOpenFileClassToHandler().get(fileType).get(
+ candidateClass));
+ return handlers;
+ }
+
+ public Set<DataflowPersistenceHandler> getOpenHandlersForType(
+ FileType fileType) {
+ return getOpenFileToHandler().get(fileType);
+ }
+
+ public synchronized Set<DataflowPersistenceHandler> getOpenHandlersForType(
+ FileType fileType, Class<?> sourceClass) {
+ Set<DataflowPersistenceHandler> handlers = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(sourceClass))
+ handlers.addAll(getOpenFileClassToHandler().get(fileType).get(
+ candidateClass));
+ return handlers;
+ }
+
+ public Set<FileType> getSaveFileTypes() {
+ return getSaveFileClassToHandler().keySet();
+ }
+
+ public Set<FileType> getSaveFileTypesFor(Class<?> destinationClass) {
+ Set<FileType> fileTypes = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(destinationClass))
+ fileTypes.addAll(getSaveClassToTypes().get(candidateClass));
+ return fileTypes;
+ }
+
+ public Set<DataflowPersistenceHandler> getSaveHandlersFor(
+ Class<? extends Object> destinationClass) {
+ Set<DataflowPersistenceHandler> handlers = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(destinationClass))
+ handlers.addAll(getSaveClassToHandlers().get(candidateClass));
+ return handlers;
+ }
+
+ public Set<DataflowPersistenceHandler> getSaveHandlersForType(
+ FileType fileType, Class<?> destinationClass) {
+ Set<DataflowPersistenceHandler> handlers = new LinkedHashSet<>();
+ for (Class<?> candidateClass : findAllParentClasses(destinationClass))
+ handlers.addAll(getSaveFileClassToHandler().get(fileType).get(
+ candidateClass));
+ return handlers;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private synchronized void createCollections() {
+ openFileClassToHandler = decorate(new HashMap(), MAP_FACTORY);
+ openFileToHandler = decorate(new HashMap(), SET_FACTORY);
+ openClassToTypes = decorate(new HashMap(), SET_FACTORY);
+ openClassToHandlers = decorate(new HashMap(), SET_FACTORY);
+
+ saveFileClassToHandler = decorate(new HashMap(), MAP_FACTORY);
+ saveFileToHandler = decorate(new HashMap(), SET_FACTORY);
+ saveClassToTypes = decorate(new HashMap(), SET_FACTORY);
+ saveClassToHandlers = decorate(new HashMap(), SET_FACTORY);
+ }
+
+ private Map<Class<?>, Set<DataflowPersistenceHandler>> getOpenClassToHandlers() {
+ return openClassToHandlers;
+ }
+
+ private synchronized Map<Class<?>, Set<FileType>> getOpenClassToTypes() {
+ return openClassToTypes;
+ }
+
+ private synchronized Map<FileType, Map<Class<?>, Set<DataflowPersistenceHandler>>> getOpenFileClassToHandler() {
+ return openFileClassToHandler;
+ }
+
+ private Map<FileType, Set<DataflowPersistenceHandler>> getOpenFileToHandler() {
+ return openFileToHandler;
+ }
+
+ private Map<Class<?>, Set<DataflowPersistenceHandler>> getSaveClassToHandlers() {
+ return saveClassToHandlers;
+ }
+
+ private synchronized Map<Class<?>, Set<FileType>> getSaveClassToTypes() {
+ return saveClassToTypes;
+ }
+
+ private synchronized Map<FileType, Map<Class<?>, Set<DataflowPersistenceHandler>>> getSaveFileClassToHandler() {
+ return saveFileClassToHandler;
+ }
+
+ /**
+ * Bind method for SpringDM.
+ *
+ * @param service
+ * @param properties
+ */
+ public void update(Object service, Map<?, ?> properties) {
+ if (dataflowPersistenceHandlers != null)
+ updateColletions();
+ }
+
+ public synchronized void updateColletions() {
+ createCollections();
+ for (DataflowPersistenceHandler handler : dataflowPersistenceHandlers) {
+ for (FileType openFileType : handler.getOpenFileTypes()) {
+ Set<DataflowPersistenceHandler> set = openFileToHandler
+ .get(openFileType);
+ set.add(handler);
+ for (Class<?> openClass : handler.getOpenSourceTypes()) {
+ openFileClassToHandler.get(openFileType).get(openClass)
+ .add(handler);
+ openClassToTypes.get(openClass).add(openFileType);
+ }
+ }
+ for (Class<?> openClass : handler.getOpenSourceTypes())
+ openClassToHandlers.get(openClass).add(handler);
+
+ for (FileType saveFileType : handler.getSaveFileTypes()) {
+ saveFileToHandler.get(saveFileType).add(handler);
+ for (Class<?> saveClass : handler.getSaveDestinationTypes()) {
+ saveFileClassToHandler.get(saveFileType).get(saveClass)
+ .add(handler);
+ saveClassToTypes.get(saveClass).add(saveFileType);
+ }
+ }
+ for (Class<?> openClass : handler.getSaveDestinationTypes())
+ saveClassToHandlers.get(openClass).add(handler);
+ }
+ }
+
+ public void setDataflowPersistenceHandlers(
+ List<DataflowPersistenceHandler> dataflowPersistenceHandlers) {
+ this.dataflowPersistenceHandlers = dataflowPersistenceHandlers;
+ }
+
+ private static class MapFactory implements Factory {
+ @Override
+ @SuppressWarnings("rawtypes")
+ public Object create() {
+ return decorate(new HashMap(), SET_FACTORY);
+ }
+ }
+
+ private static class SetFactory implements Factory {
+ @Override
+ public Object create() {
+ return new LinkedHashSet<Object>();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileDataflowInfo.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileDataflowInfo.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileDataflowInfo.java
new file mode 100644
index 0000000..89ae39c
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileDataflowInfo.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * Information about an open dataflow that was opened from or saved to a
+ * {@link File}.
+ *
+ * @see DataflowInfo
+ * @see FileManager
+ * @author Stian Soiland-Reyes
+ */
+public class FileDataflowInfo extends DataflowInfo {
+ private static Logger logger = Logger.getLogger(FileDataflowInfo.class);
+
+ public FileDataflowInfo(FileType fileType, File source,
+ WorkflowBundle workflowBundle) {
+ super(fileType, canonicalFile(source), workflowBundle,
+ lastModifiedFile(source));
+ }
+
+ protected static Date lastModifiedFile(File file) {
+ long lastModifiedLong = file.lastModified();
+ if (lastModifiedLong == 0)
+ return null;
+ return new Date(lastModifiedLong);
+ }
+
+ public static File canonicalFile(File file) {
+ try {
+ return file.getCanonicalFile();
+ } catch (IOException e) {
+ logger.warn("Could not find canonical file for " + file);
+ return file;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileManagerImpl.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileManagerImpl.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileManagerImpl.java
new file mode 100644
index 0000000..aadb3f1
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileManagerImpl.java
@@ -0,0 +1,601 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2010 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import static java.awt.GraphicsEnvironment.isHeadless;
+import static java.util.Collections.singleton;
+import static javax.swing.SwingUtilities.invokeAndWait;
+import static javax.swing.SwingUtilities.isEventDispatchThread;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.lang.observer.MultiCaster;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.edits.EditManager.AbstractDataflowEditEvent;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.events.ClosedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.ClosingDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.OpenedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.SavedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.file.exceptions.OverwriteException;
+import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
+import net.sf.taverna.t2.workbench.file.exceptions.UnsavedException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * Implementation of {@link FileManager}
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class FileManagerImpl implements FileManager {
+ private static Logger logger = Logger.getLogger(FileManagerImpl.class);
+ private static int nameIndex = 1;
+
+ /**
+ * The last blank workflowBundle created using #newDataflow() until it has
+ * been changed - when this variable will be set to null again. Used to
+ * automatically close unmodified blank workflowBundles on open.
+ */
+ private WorkflowBundle blankWorkflowBundle = null;
+ @SuppressWarnings("unused")
+ private EditManager editManager;
+ private EditManagerObserver editManagerObserver = new EditManagerObserver();
+ protected MultiCaster<FileManagerEvent> observers = new MultiCaster<>(this);
+ /**
+ * Ordered list of open WorkflowBundle
+ */
+ private LinkedHashMap<WorkflowBundle, OpenDataflowInfo> openDataflowInfos = new LinkedHashMap<>();
+ private DataflowPersistenceHandlerRegistry dataflowPersistenceHandlerRegistry;
+ private Scufl2Tools scufl2Tools = new Scufl2Tools();
+ private WorkflowBundle currentWorkflowBundle;
+
+ public DataflowPersistenceHandlerRegistry getPersistanceHandlerRegistry() {
+ return dataflowPersistenceHandlerRegistry;
+ }
+
+ public FileManagerImpl(EditManager editManager) {
+ this.editManager = editManager;
+ editManager.addObserver(editManagerObserver);
+ }
+
+ /**
+ * Add an observer to be notified of {@link FileManagerEvent}s, such as
+ * {@link OpenedDataflowEvent} and {@link SavedDataflowEvent}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void addObserver(Observer<FileManagerEvent> observer) {
+ observers.addObserver(observer);
+ }
+
+ @Override
+ public boolean canSaveWithoutDestination(WorkflowBundle workflowBundle) {
+ OpenDataflowInfo dataflowInfo = getOpenDataflowInfo(workflowBundle);
+ if (dataflowInfo.getSource() == null)
+ return false;
+ Set<?> handlers = getPersistanceHandlerRegistry()
+ .getSaveHandlersForType(
+ dataflowInfo.getFileType(),
+ dataflowInfo.getDataflowInfo().getCanonicalSource()
+ .getClass());
+ return !handlers.isEmpty();
+ }
+
+ @Override
+ public boolean closeDataflow(WorkflowBundle workflowBundle,
+ boolean failOnUnsaved) throws UnsavedException {
+ if (workflowBundle == null)
+ throw new NullPointerException("Dataflow can't be null");
+ ClosingDataflowEvent message = new ClosingDataflowEvent(workflowBundle);
+ observers.notify(message);
+ if (message.isAbortClose())
+ return false;
+ if ((failOnUnsaved && getOpenDataflowInfo(workflowBundle).isChanged()))
+ throw new UnsavedException(workflowBundle);
+ if (workflowBundle.equals(getCurrentDataflow())) {
+ // We'll need to change current workflowBundle
+ // Find best candidate to the left or right
+ List<WorkflowBundle> workflowBundles = getOpenDataflows();
+ int openIndex = workflowBundles.indexOf(workflowBundle);
+ if (openIndex == -1)
+ throw new IllegalArgumentException("Workflow was not opened "
+ + workflowBundle);
+
+ if (openIndex > 0)
+ setCurrentDataflow(workflowBundles.get(openIndex - 1));
+ else if (openIndex == 0 && workflowBundles.size() > 1)
+ setCurrentDataflow(workflowBundles.get(1));
+ else
+ // If it was the last one, start a new, empty workflowBundle
+ newDataflow();
+ }
+ if (workflowBundle == blankWorkflowBundle)
+ blankWorkflowBundle = null;
+ openDataflowInfos.remove(workflowBundle);
+ observers.notify(new ClosedDataflowEvent(workflowBundle));
+ return true;
+ }
+
+ @Override
+ public WorkflowBundle getCurrentDataflow() {
+ return currentWorkflowBundle;
+ }
+
+ @Override
+ public WorkflowBundle getDataflowBySource(Object source) {
+ for (Entry<WorkflowBundle, OpenDataflowInfo> infoEntry : openDataflowInfos
+ .entrySet()) {
+ OpenDataflowInfo info = infoEntry.getValue();
+ if (source.equals(info.getSource()))
+ return infoEntry.getKey();
+ }
+ // Not found
+ return null;
+ }
+
+ @Override
+ public String getDataflowName(WorkflowBundle workflowBundle) {
+ Object source = null;
+ if (isDataflowOpen(workflowBundle))
+ source = getDataflowSource(workflowBundle);
+ // Fallback
+ String name;
+ Workflow workflow = workflowBundle.getMainWorkflow();
+ if (workflow != null)
+ name = workflow.getName();
+ else
+ name = workflowBundle.getName();
+ if (source == null)
+ return name;
+ if (source instanceof File)
+ return ((File) source).getAbsolutePath();
+ else if (source instanceof URL)
+ return source.toString();
+
+ // Check if it has implemented a toString() method
+ Method toStringMethod = null;
+ Method toStringMethodFromObject = null;
+ try {
+ toStringMethod = source.getClass().getMethod("toString");
+ toStringMethodFromObject = Object.class.getMethod("toString");
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Source did not implement Object.toString() " + source);
+ }
+ if (!toStringMethod.equals(toStringMethodFromObject))
+ return source.toString();
+ return name;
+ }
+
+ @Override
+ public String getDefaultWorkflowName() {
+ return "Workflow" + (nameIndex++);
+ }
+
+ @Override
+ public Object getDataflowSource(WorkflowBundle workflowBundle) {
+ return getOpenDataflowInfo(workflowBundle).getSource();
+ }
+
+ @Override
+ public FileType getDataflowType(WorkflowBundle workflowBundle) {
+ return getOpenDataflowInfo(workflowBundle).getFileType();
+ }
+
+ @Override
+ public List<Observer<FileManagerEvent>> getObservers() {
+ return observers.getObservers();
+ }
+
+ /**
+ * Get the {@link OpenDataflowInfo} for the given WorkflowBundle
+ *
+ * @throws NullPointerException
+ * if the WorkflowBundle was <code>null</code>
+ * @throws IllegalArgumentException
+ * if the WorkflowBundle was not open.
+ * @param workflowBundle
+ * WorkflowBundle which information is to be found
+ * @return The {@link OpenDataflowInfo} describing the WorkflowBundle
+ */
+ protected synchronized OpenDataflowInfo getOpenDataflowInfo(
+ WorkflowBundle workflowBundle) {
+ if (workflowBundle == null)
+ throw new NullPointerException("Dataflow can't be null");
+ OpenDataflowInfo info = openDataflowInfos.get(workflowBundle);
+ if (info == null)
+ throw new IllegalArgumentException("Workflow was not opened "
+ + workflowBundle);
+ return info;
+ }
+
+ @Override
+ public List<WorkflowBundle> getOpenDataflows() {
+ return new ArrayList<>(openDataflowInfos.keySet());
+ }
+
+ @Override
+ public List<FileFilter> getOpenFileFilters() {
+ List<FileFilter> fileFilters = new ArrayList<>();
+
+ Set<FileType> fileTypes = getPersistanceHandlerRegistry()
+ .getOpenFileTypes();
+ if (!fileTypes.isEmpty())
+ fileFilters.add(new MultipleFileTypes(fileTypes,
+ "All supported workflows"));
+ for (FileType fileType : fileTypes)
+ fileFilters.add(new FileTypeFileFilter(fileType));
+ return fileFilters;
+ }
+
+ @Override
+ public List<FileFilter> getOpenFileFilters(Class<?> sourceClass) {
+ List<FileFilter> fileFilters = new ArrayList<>();
+ for (FileType fileType : getPersistanceHandlerRegistry()
+ .getOpenFileTypesFor(sourceClass))
+ fileFilters.add(new FileTypeFileFilter(fileType));
+ return fileFilters;
+ }
+
+ @Override
+ public List<FileFilter> getSaveFileFilters() {
+ List<FileFilter> fileFilters = new ArrayList<>();
+ for (FileType fileType : getPersistanceHandlerRegistry()
+ .getSaveFileTypes())
+ fileFilters.add(new FileTypeFileFilter(fileType));
+ return fileFilters;
+ }
+
+ @Override
+ public List<FileFilter> getSaveFileFilters(Class<?> destinationClass) {
+ List<FileFilter> fileFilters = new ArrayList<>();
+ for (FileType fileType : getPersistanceHandlerRegistry()
+ .getSaveFileTypesFor(destinationClass))
+ fileFilters.add(new FileTypeFileFilter(fileType));
+ return fileFilters;
+ }
+
+ @Override
+ public boolean isDataflowChanged(WorkflowBundle workflowBundle) {
+ return getOpenDataflowInfo(workflowBundle).isChanged();
+ }
+
+ @Override
+ public boolean isDataflowOpen(WorkflowBundle workflowBundle) {
+ return openDataflowInfos.containsKey(workflowBundle);
+ }
+
+ @Override
+ public WorkflowBundle newDataflow() {
+ WorkflowBundle workflowBundle = new WorkflowBundle();
+ workflowBundle.setMainWorkflow(new Workflow());
+ workflowBundle.getMainWorkflow().setName(getDefaultWorkflowName());
+ workflowBundle.setMainProfile(new Profile());
+ scufl2Tools.setParents(workflowBundle);
+ blankWorkflowBundle = null;
+ openDataflowInternal(workflowBundle);
+ blankWorkflowBundle = workflowBundle;
+ observers.notify(new OpenedDataflowEvent(workflowBundle));
+ return workflowBundle;
+ }
+
+ @Override
+ public void openDataflow(WorkflowBundle workflowBundle) {
+ openDataflowInternal(workflowBundle);
+ observers.notify(new OpenedDataflowEvent(workflowBundle));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public WorkflowBundle openDataflow(FileType fileType, Object source)
+ throws OpenException {
+ if (isHeadless())
+ return performOpenDataflow(fileType, source);
+
+ OpenDataflowRunnable r = new OpenDataflowRunnable(this, fileType,
+ source);
+ if (isEventDispatchThread()) {
+ r.run();
+ } else
+ try {
+ invokeAndWait(r);
+ } catch (InterruptedException | InvocationTargetException e) {
+ throw new OpenException("Opening was interrupted", e);
+ }
+ OpenException thrownException = r.getException();
+ if (thrownException != null)
+ throw thrownException;
+ return r.getDataflow();
+ }
+
+ public WorkflowBundle performOpenDataflow(FileType fileType, Object source)
+ throws OpenException {
+ DataflowInfo dataflowInfo;
+ WorkflowBundle workflowBundle;
+ dataflowInfo = openDataflowSilently(fileType, source);
+ workflowBundle = dataflowInfo.getDataflow();
+ openDataflowInternal(workflowBundle);
+ getOpenDataflowInfo(workflowBundle).setOpenedFrom(dataflowInfo);
+ observers.notify(new OpenedDataflowEvent(workflowBundle));
+ return workflowBundle;
+ }
+
+ @Override
+ public DataflowInfo openDataflowSilently(FileType fileType, Object source)
+ throws OpenException {
+ Set<DataflowPersistenceHandler> handlers;
+ Class<? extends Object> sourceClass = source.getClass();
+
+ boolean unknownFileType = (fileType == null);
+ if (unknownFileType)
+ handlers = getPersistanceHandlerRegistry().getOpenHandlersFor(
+ sourceClass);
+ else
+ handlers = getPersistanceHandlerRegistry().getOpenHandlersFor(
+ fileType, sourceClass);
+ if (handlers.isEmpty())
+ throw new OpenException("Unsupported file type or class "
+ + fileType + " " + sourceClass);
+
+ Throwable lastException = null;
+ for (DataflowPersistenceHandler handler : handlers) {
+ Collection<FileType> fileTypes;
+ if (unknownFileType)
+ fileTypes = handler.getOpenFileTypes();
+ else
+ fileTypes = singleton(fileType);
+ for (FileType candidateFileType : fileTypes) {
+ if (unknownFileType && (source instanceof File))
+ /*
+ * If source is file but fileType was not explicitly set
+ * from the open workflow dialog - check the file extension
+ * and decide which handler to use based on that (so that we
+ * do not loop though all handlers)
+ */
+ if (!((File) source).getPath().endsWith(
+ candidateFileType.getExtension()))
+ continue;
+
+ try {
+ DataflowInfo openDataflow = handler.openDataflow(
+ candidateFileType, source);
+ WorkflowBundle workflowBundle = openDataflow.getDataflow();
+ logger.info("Loaded workflow: " + workflowBundle.getName()
+ + " " + workflowBundle.getGlobalBaseURI()
+ + " from " + source + " using " + handler);
+ return openDataflow;
+ } catch (OpenException ex) {
+ logger.warn("Could not open workflow " + source + " using "
+ + handler + " of type " + candidateFileType);
+ lastException = ex;
+ }
+ }
+ }
+ throw new OpenException("Could not open workflow " + source + "\n",
+ lastException);
+ }
+
+ /**
+ * Mark the WorkflowBundle as opened, and close the blank WorkflowBundle if
+ * needed.
+ *
+ * @param workflowBundle
+ * WorkflowBundle that has been opened
+ */
+ protected void openDataflowInternal(WorkflowBundle workflowBundle) {
+ if (workflowBundle == null)
+ throw new NullPointerException("Dataflow can't be null");
+ if (isDataflowOpen(workflowBundle))
+ throw new IllegalArgumentException("Workflow is already open: "
+ + workflowBundle);
+
+ openDataflowInfos.put(workflowBundle, new OpenDataflowInfo());
+ setCurrentDataflow(workflowBundle);
+ if (openDataflowInfos.size() == 2 && blankWorkflowBundle != null)
+ /*
+ * Behave like a word processor and close the blank WorkflowBundle
+ * when another workflow has been opened
+ */
+ try {
+ closeDataflow(blankWorkflowBundle, true);
+ } catch (UnsavedException e) {
+ logger.error("Blank workflow was modified "
+ + "and could not be closed");
+ }
+ }
+
+ @Override
+ public void removeObserver(Observer<FileManagerEvent> observer) {
+ observers.removeObserver(observer);
+ }
+
+ @Override
+ public void saveDataflow(WorkflowBundle workflowBundle,
+ boolean failOnOverwrite) throws SaveException {
+ if (workflowBundle == null)
+ throw new NullPointerException("Dataflow can't be null");
+ OpenDataflowInfo lastSave = getOpenDataflowInfo(workflowBundle);
+ if (lastSave.getSource() == null)
+ throw new SaveException("Can't save without source "
+ + workflowBundle);
+ saveDataflow(workflowBundle, lastSave.getFileType(),
+ lastSave.getSource(), failOnOverwrite);
+ }
+
+ @Override
+ public void saveDataflow(WorkflowBundle workflowBundle, FileType fileType,
+ Object destination, boolean failOnOverwrite) throws SaveException {
+ DataflowInfo savedDataflow = saveDataflowSilently(workflowBundle,
+ fileType, destination, failOnOverwrite);
+ getOpenDataflowInfo(workflowBundle).setSavedTo(savedDataflow);
+ observers.notify(new SavedDataflowEvent(workflowBundle));
+ }
+
+ @Override
+ public DataflowInfo saveDataflowSilently(WorkflowBundle workflowBundle,
+ FileType fileType, Object destination, boolean failOnOverwrite)
+ throws SaveException, OverwriteException {
+ Set<DataflowPersistenceHandler> handlers;
+
+ Class<? extends Object> destinationClass = destination.getClass();
+ if (fileType != null)
+ handlers = getPersistanceHandlerRegistry().getSaveHandlersForType(
+ fileType, destinationClass);
+ else
+ handlers = getPersistanceHandlerRegistry().getSaveHandlersFor(
+ destinationClass);
+
+ SaveException lastException = null;
+ for (DataflowPersistenceHandler handler : handlers) {
+ if (failOnOverwrite) {
+ OpenDataflowInfo openDataflowInfo = getOpenDataflowInfo(workflowBundle);
+ if (handler.wouldOverwriteDataflow(workflowBundle, fileType,
+ destination, openDataflowInfo.getDataflowInfo()))
+ throw new OverwriteException(destination);
+ }
+ try {
+ DataflowInfo savedDataflow = handler.saveDataflow(
+ workflowBundle, fileType, destination);
+ savedDataflow.getDataflow();
+ logger.info("Saved workflow: " + workflowBundle.getName() + " "
+ + workflowBundle.getGlobalBaseURI() + " to "
+ + savedDataflow.getCanonicalSource() + " using "
+ + handler);
+ return savedDataflow;
+ } catch (SaveException ex) {
+ logger.warn("Could not save to " + destination + " using "
+ + handler);
+ lastException = ex;
+ }
+ }
+
+ if (lastException == null)
+ throw new SaveException("Unsupported file type or class "
+ + fileType + " " + destinationClass);
+ throw new SaveException("Could not save to " + destination + ":\n"
+ + lastException.getLocalizedMessage(), lastException);
+ }
+
+ @Override
+ public void setCurrentDataflow(WorkflowBundle workflowBundle) {
+ setCurrentDataflow(workflowBundle, false);
+ }
+
+ @Override
+ public void setCurrentDataflow(WorkflowBundle workflowBundle,
+ boolean openIfNeeded) {
+ currentWorkflowBundle = workflowBundle;
+ if (!isDataflowOpen(workflowBundle)) {
+ if (!openIfNeeded)
+ throw new IllegalArgumentException("Workflow is not open: "
+ + workflowBundle);
+ openDataflow(workflowBundle);
+ return;
+ }
+ observers.notify(new SetCurrentDataflowEvent(workflowBundle));
+ }
+
+ @Override
+ public void setDataflowChanged(WorkflowBundle workflowBundle,
+ boolean isChanged) {
+ getOpenDataflowInfo(workflowBundle).setIsChanged(isChanged);
+ if (blankWorkflowBundle == workflowBundle)
+ blankWorkflowBundle = null;
+ }
+
+ @Override
+ public Object getCanonical(Object source) throws IllegalArgumentException,
+ URISyntaxException, IOException {
+ Object canonicalSource = source;
+
+ if (source instanceof URL) {
+ URL url = ((URL) source);
+ if (url.getProtocol().equalsIgnoreCase("file"))
+ canonicalSource = new File(url.toURI());
+ }
+
+ if (canonicalSource instanceof File)
+ canonicalSource = ((File) canonicalSource).getCanonicalFile();
+ return canonicalSource;
+ }
+
+ public void setDataflowPersistenceHandlerRegistry(
+ DataflowPersistenceHandlerRegistry dataflowPersistenceHandlerRegistry) {
+ this.dataflowPersistenceHandlerRegistry = dataflowPersistenceHandlerRegistry;
+ }
+
+ /**
+ * Observe the {@link EditManager} for changes to open workflowBundles. A
+ * change of an open workflow would set it as changed using
+ * {@link FileManagerImpl#setDataflowChanged(Dataflow, boolean)}.
+ *
+ * @author Stian Soiland-Reyes
+ *
+ */
+ private final class EditManagerObserver implements
+ Observer<EditManagerEvent> {
+ @Override
+ public void notify(Observable<EditManagerEvent> sender,
+ EditManagerEvent message) throws Exception {
+ if (message instanceof AbstractDataflowEditEvent) {
+ AbstractDataflowEditEvent dataflowEdit = (AbstractDataflowEditEvent) message;
+ WorkflowBundle workflowBundle = dataflowEdit.getDataFlow();
+ /**
+ * TODO: on undo/redo - keep last event or similar to determine
+ * if workflow was saved before. See
+ * FileManagerTest#isChangedWithUndo().
+ */
+ setDataflowChanged(workflowBundle, true);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileTypeFileFilter.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileTypeFileFilter.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileTypeFileFilter.java
new file mode 100644
index 0000000..6416163
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/FileTypeFileFilter.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.workbench.file.FileType;
+
+public class FileTypeFileFilter extends FileFilter {
+ private final FileType fileType;
+
+ public FileTypeFileFilter(FileType fileType) {
+ this.fileType = fileType;
+ }
+
+ @Override
+ public String getDescription() {
+ return fileType.getDescription();
+ }
+
+ @Override
+ public boolean accept(File file) {
+ if (file.isDirectory())
+ // Don't grey out directories
+ return true;
+ if (fileType.getExtension() == null)
+ return false;
+ return file.getName().toLowerCase()
+ .endsWith("." + fileType.getExtension());
+ }
+
+ public FileType getFileType() {
+ return fileType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/MultipleFileTypes.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/MultipleFileTypes.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/MultipleFileTypes.java
new file mode 100644
index 0000000..c398805
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/MultipleFileTypes.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+import java.util.Set;
+
+import javax.swing.filechooser.FileFilter;
+
+import net.sf.taverna.t2.workbench.file.FileType;
+
+public class MultipleFileTypes extends FileFilter {
+ private String description;
+ private final Set<FileType> fileTypes;
+
+ public MultipleFileTypes(Set<FileType> fileTypes, String description) {
+ this.fileTypes = fileTypes;
+ this.description = description;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public boolean accept(File file) {
+ if (file.isDirectory())
+ return true;
+
+ String lowerFileName = file.getName().toLowerCase();
+ for (FileType fileType : fileTypes) {
+ if (fileType.getExtension() == null)
+ continue;
+ if (lowerFileName.endsWith(fileType.getExtension()))
+ return true;
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInProgressDialog.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInProgressDialog.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInProgressDialog.java
new file mode 100644
index 0000000..dc08cff
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInProgressDialog.java
@@ -0,0 +1,88 @@
+
+/*******************************************************************************
+ * Copyright (C) 2009 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import static java.awt.BorderLayout.CENTER;
+import static net.sf.taverna.t2.workbench.MainWindow.getMainWindow;
+import static net.sf.taverna.t2.workbench.icons.WorkbenchIcons.workingIcon;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog;
+
+/**
+ * Dialog that is popped up while we are opening a workflow.
+ *
+ * @author Alex Nenadic
+ * @author Alan R Williams
+ */
+@SuppressWarnings("serial")
+public class OpenDataflowInProgressDialog extends HelpEnabledDialog {
+ private boolean userCancelled = false;
+
+ public OpenDataflowInProgressDialog() {
+ super(getMainWindow(), "Opening workflow", true);
+ setResizable(false);
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+ JPanel panel = new JPanel(new BorderLayout());
+ panel.setBorder(new EmptyBorder(10,10,10,10));
+
+ JPanel textPanel = new JPanel();
+ JLabel text = new JLabel(workingIcon);
+ text.setText("Opening workflow...");
+ text.setBorder(new EmptyBorder(10,0,10,0));
+ textPanel.add(text);
+ panel.add(textPanel, CENTER);
+
+/*
+ * Cancellation does not work when opening
+
+ // Cancel button
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ userCancelled = true;
+ setVisible(false);
+ dispose();
+ }
+ });
+ JPanel cancelButtonPanel = new JPanel();
+ cancelButtonPanel.add(cancelButton);
+ panel.add(cancelButtonPanel, BorderLayout.SOUTH);
+*/
+ setContentPane(panel);
+ setPreferredSize(new Dimension(300, 100));
+
+ pack();
+ }
+
+ public boolean hasUserCancelled() {
+ return userCancelled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInfo.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInfo.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInfo.java
new file mode 100644
index 0000000..4a4a1e3
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowInfo.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.util.Date;
+
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.FileType;
+
+/**
+ * Information about an open dataflow.
+ *
+ * @author Stian Soiland-Reyes
+ */
+public class OpenDataflowInfo {
+ private DataflowInfo dataflowInfo;
+ private boolean isChanged;
+ private Date openedAt;
+
+ public OpenDataflowInfo() {
+ }
+
+ public FileType getFileType() {
+ if (dataflowInfo == null)
+ return null;
+ return dataflowInfo.getFileType();
+ }
+
+ public Date getLastModified() {
+ if (dataflowInfo == null)
+ return null;
+ return dataflowInfo.getLastModified();
+ }
+
+ public Date getOpenedAtDate() {
+ return openedAt;
+ }
+
+ public Object getSource() {
+ if (dataflowInfo == null)
+ return null;
+ return dataflowInfo.getCanonicalSource();
+ }
+
+ public boolean isChanged() {
+ return isChanged;
+ }
+
+ public void setIsChanged(boolean isChanged) {
+ this.isChanged = isChanged;
+ }
+
+ public synchronized void setOpenedFrom(DataflowInfo dataflowInfo) {
+ setDataflowInfo(dataflowInfo);
+ setOpenedAt(new Date());
+ setIsChanged(false);
+ }
+
+ public synchronized void setSavedTo(DataflowInfo dataflowInfo) {
+ setDataflowInfo(dataflowInfo);
+ setIsChanged(false);
+ }
+
+ private void setDataflowInfo(DataflowInfo dataflowInfo) {
+ this.dataflowInfo = dataflowInfo;
+ }
+
+ private void setOpenedAt(Date openedAt) {
+ this.openedAt = openedAt;
+ }
+
+ public DataflowInfo getDataflowInfo() {
+ return dataflowInfo;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowRunnable.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowRunnable.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowRunnable.java
new file mode 100644
index 0000000..9d687b8
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowRunnable.java
@@ -0,0 +1,71 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.file.impl;
+
+import static java.lang.Thread.sleep;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+import net.sf.taverna.t2.workbench.ui.SwingWorkerCompletionWaiter;
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+/**
+ * @author alanrw
+ */
+public class OpenDataflowRunnable implements Runnable {
+ private final FileManagerImpl fileManager;
+ private final FileType fileType;
+ private final Object source;
+ private WorkflowBundle dataflow;
+ private OpenException e;
+
+ public OpenDataflowRunnable(FileManagerImpl fileManager, FileType fileType,
+ Object source) {
+ this.fileManager = fileManager;
+ this.fileType = fileType;
+ this.source = source;
+ }
+
+ @Override
+ public void run() {
+ OpenDataflowSwingWorker openDataflowSwingWorker = new OpenDataflowSwingWorker(
+ fileType, source, fileManager);
+ OpenDataflowInProgressDialog dialog = new OpenDataflowInProgressDialog();
+ openDataflowSwingWorker
+ .addPropertyChangeListener(new SwingWorkerCompletionWaiter(
+ dialog));
+ openDataflowSwingWorker.execute();
+
+ /*
+ * Give a chance to the SwingWorker to finish so we do not have to
+ * display the dialog
+ */
+ try {
+ sleep(500);
+ } catch (InterruptedException e) {
+ this.e = new OpenException("Opening was interrupted");
+ }
+ if (!openDataflowSwingWorker.isDone())
+ dialog.setVisible(true); // this will block the GUI
+ boolean userCancelled = dialog.hasUserCancelled(); // see if user cancelled the dialog
+
+ if (userCancelled) {
+ // Stop the OpenDataflowSwingWorker if it is still working
+ openDataflowSwingWorker.cancel(true);
+ dataflow = null;
+ this.e = new OpenException("Opening was cancelled");
+ // exit
+ return;
+ }
+ dataflow = openDataflowSwingWorker.getDataflow();
+ this.e = openDataflowSwingWorker.getException();
+ }
+
+ public WorkflowBundle getDataflow() {
+ return dataflow;
+ }
+
+ public OpenException getException() {
+ return this.e;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowSwingWorker.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowSwingWorker.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowSwingWorker.java
new file mode 100644
index 0000000..4cbd2f8
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/OpenDataflowSwingWorker.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (C) 2009 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import javax.swing.SwingWorker;
+
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+
+public class OpenDataflowSwingWorker extends
+ SwingWorker<WorkflowBundle, Object> {
+ @SuppressWarnings("unused")
+ private Logger logger = Logger.getLogger(OpenDataflowSwingWorker.class);
+ private FileType fileType;
+ private Object source;
+ private FileManagerImpl fileManagerImpl;
+ private WorkflowBundle workflowBundle;
+ private OpenException e = null;
+
+ public OpenDataflowSwingWorker(FileType fileType, Object source,
+ FileManagerImpl fileManagerImpl) {
+ this.fileType = fileType;
+ this.source = source;
+ this.fileManagerImpl = fileManagerImpl;
+ }
+
+ @Override
+ protected WorkflowBundle doInBackground() throws Exception {
+ try {
+ workflowBundle = fileManagerImpl.performOpenDataflow(fileType,
+ source);
+ } catch (OpenException e) {
+ this.e = e;
+ }
+ return workflowBundle;
+ }
+
+ public WorkflowBundle getDataflow() {
+ return workflowBundle;
+ }
+
+ public OpenException getException() {
+ return e;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2DataflowOpener.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2DataflowOpener.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2DataflowOpener.java
new file mode 100644
index 0000000..bf37faf
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2DataflowOpener.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.io.ReaderException;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+
+public class T2DataflowOpener extends AbstractDataflowPersistenceHandler
+ implements DataflowPersistenceHandler {
+ private static final T2FlowFileType T2_FLOW_FILE_TYPE = new T2FlowFileType();
+ private static Logger logger = Logger.getLogger(T2DataflowOpener.class);
+
+ private WorkflowBundleIO workflowBundleIO;
+
+ @SuppressWarnings("resource")
+ @Override
+ public DataflowInfo openDataflow(FileType fileType, Object source)
+ throws OpenException {
+ if (!getOpenFileTypes().contains(fileType))
+ throw new OpenException("Unsupported file type "
+ + fileType);
+ InputStream inputStream;
+ Date lastModified = null;
+ Object canonicalSource = source;
+ if (source instanceof InputStream)
+ inputStream = (InputStream) source;
+ else if (source instanceof File)
+ try {
+ inputStream = new FileInputStream((File) source);
+ } catch (FileNotFoundException e) {
+ throw new OpenException("Could not open file " + source + ":\n" + e.getLocalizedMessage(), e);
+ }
+ else if (source instanceof URL) {
+ URL url = ((URL) source);
+ try {
+ URLConnection connection = url.openConnection();
+ connection.setRequestProperty("Accept", "text/xml");
+ inputStream = connection.getInputStream();
+ if (connection.getLastModified() != 0)
+ lastModified = new Date(connection.getLastModified());
+ } catch (IOException e) {
+ throw new OpenException("Could not open connection to URL "
+ + source+ ":\n" + e.getLocalizedMessage(), e);
+ }
+ try {
+ if (url.getProtocol().equalsIgnoreCase("file"))
+ canonicalSource = new File(url.toURI());
+ } catch (URISyntaxException e) {
+ logger.warn("Invalid file URI created from " + url);
+ }
+ } else {
+ throw new OpenException("Unsupported source type "
+ + source.getClass());
+ }
+
+ final WorkflowBundle workflowBundle;
+ try {
+ workflowBundle = openDataflowStream(inputStream);
+ } finally {
+ try {
+ if (!(source instanceof InputStream))
+ // We created the stream, we'll close it
+ inputStream.close();
+ } catch (IOException ex) {
+ logger.warn("Could not close inputstream " + inputStream, ex);
+ }
+ }
+ if (canonicalSource instanceof File)
+ return new FileDataflowInfo(T2_FLOW_FILE_TYPE,
+ (File) canonicalSource, workflowBundle);
+ return new DataflowInfo(T2_FLOW_FILE_TYPE, canonicalSource,
+ workflowBundle, lastModified);
+ }
+
+ protected WorkflowBundle openDataflowStream(InputStream workflowXMLstream)
+ throws OpenException {
+ WorkflowBundle workflowBundle;
+ try {
+ workflowBundle = workflowBundleIO.readBundle(workflowXMLstream, null);
+ } catch (ReaderException e) {
+ throw new OpenException("Could not read the workflow", e);
+ } catch (IOException e) {
+ throw new OpenException("Could not open the workflow file for parsing", e);
+ } catch (Exception e) {
+ throw new OpenException("Error while opening workflow", e);
+ }
+
+ return workflowBundle;
+ }
+
+ @Override
+ public List<FileType> getOpenFileTypes() {
+ return Arrays.<FileType> asList(new T2FlowFileType());
+ }
+
+ @Override
+ public List<Class<?>> getOpenSourceTypes() {
+ return Arrays.<Class<?>> asList(InputStream.class, URL.class,
+ File.class);
+ }
+
+ public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) {
+ this.workflowBundleIO = workflowBundleIO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FileFilter.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FileFilter.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FileFilter.java
new file mode 100644
index 0000000..62b5892
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FileFilter.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+public class T2FileFilter extends FileFilter {
+ @Override
+ public boolean accept(final File file) {
+ return file.getName().toLowerCase().endsWith(".t2flow");
+ }
+
+ @Override
+ public String getDescription() {
+ return "Taverna 2 workflows";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FlowFileType.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FlowFileType.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FlowFileType.java
new file mode 100644
index 0000000..a2774e4
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/T2FlowFileType.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import net.sf.taverna.t2.workbench.file.FileType;
+
+public class T2FlowFileType extends FileType {
+ public static final String APPLICATION_VND_TAVERNA_T2FLOW_XML = "application/vnd.taverna.t2flow+xml";
+
+ @Override
+ public String getDescription() {
+ return "Taverna 2 workflow";
+ }
+
+ @Override
+ public String getExtension() {
+ return "t2flow";
+ }
+
+ @Override
+ public String getMimeType() {
+ return APPLICATION_VND_TAVERNA_T2FLOW_XML;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileFilter.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileFilter.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileFilter.java
new file mode 100644
index 0000000..d272b41
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileFilter.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+public class WorkflowBundleFileFilter extends FileFilter {
+ @Override
+ public boolean accept(final File file) {
+ return file.getName().toLowerCase().endsWith(".wfbundle");
+ }
+
+ @Override
+ public String getDescription() {
+ return "Taverna 3 workflows";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileType.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileType.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileType.java
new file mode 100644
index 0000000..09b30b0
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleFileType.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import net.sf.taverna.t2.workbench.file.FileType;
+
+public class WorkflowBundleFileType extends FileType {
+ public static final String APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE = "application/vnd.taverna.scufl2.workflow-bundle";
+
+ @Override
+ public String getDescription() {
+ return "Taverna 3 workflow";
+ }
+
+ @Override
+ public String getExtension() {
+ return "wfbundle";
+ }
+
+ @Override
+ public String getMimeType() {
+ return APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleOpener.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleOpener.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleOpener.java
new file mode 100644
index 0000000..7c54f7e
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleOpener.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.OpenException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.io.ReaderException;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+
+public class WorkflowBundleOpener extends AbstractDataflowPersistenceHandler
+ implements DataflowPersistenceHandler {
+ private static final WorkflowBundleFileType WF_BUNDLE_FILE_TYPE = new WorkflowBundleFileType();
+ private static Logger logger = Logger.getLogger(WorkflowBundleOpener.class);
+ private WorkflowBundleIO workflowBundleIO;
+
+ @SuppressWarnings("resource")
+ @Override
+ public DataflowInfo openDataflow(FileType fileType, Object source)
+ throws OpenException {
+ if (!getOpenFileTypes().contains(fileType))
+ throw new OpenException("Unsupported file type " + fileType);
+ InputStream inputStream;
+ Date lastModified = null;
+ Object canonicalSource = source;
+ if (source instanceof InputStream) {
+ inputStream = (InputStream) source;
+ } else if (source instanceof File) {
+ try {
+ inputStream = new FileInputStream((File) source);
+ } catch (FileNotFoundException e) {
+ throw new OpenException("Could not open file " + source + ":\n"
+ + e.getLocalizedMessage(), e);
+ }
+ } else if (source instanceof URL) {
+ URL url = ((URL) source);
+ try {
+ URLConnection connection = url.openConnection();
+ connection.setRequestProperty("Accept", "application/zip");
+ inputStream = connection.getInputStream();
+ if (connection.getLastModified() != 0)
+ lastModified = new Date(connection.getLastModified());
+ } catch (IOException e) {
+ throw new OpenException("Could not open connection to URL "
+ + source + ":\n" + e.getLocalizedMessage(), e);
+ }
+ try {
+ if (url.getProtocol().equalsIgnoreCase("file"))
+ canonicalSource = new File(url.toURI());
+ } catch (URISyntaxException e) {
+ logger.warn("Invalid file URI created from " + url);
+ }
+ } else
+ throw new OpenException("Unsupported source type "
+ + source.getClass());
+
+ final WorkflowBundle workflowBundle;
+ try {
+ workflowBundle = openDataflowStream(inputStream);
+ } finally {
+ // We created the stream, we'll close it
+ try {
+ if (!(source instanceof InputStream))
+ inputStream.close();
+ } catch (IOException ex) {
+ logger.warn("Could not close inputstream " + inputStream, ex);
+ }
+ }
+ if (canonicalSource instanceof File)
+ return new FileDataflowInfo(WF_BUNDLE_FILE_TYPE,
+ (File) canonicalSource, workflowBundle);
+ return new DataflowInfo(WF_BUNDLE_FILE_TYPE, canonicalSource,
+ workflowBundle, lastModified);
+ }
+
+ protected WorkflowBundle openDataflowStream(InputStream inputStream)
+ throws OpenException {
+ WorkflowBundle workflowBundle;
+ try {
+ workflowBundle = workflowBundleIO.readBundle(inputStream, null);
+ } catch (ReaderException e) {
+ throw new OpenException("Could not read the workflow", e);
+ } catch (IOException e) {
+ throw new OpenException("Could not open the workflow for parsing",
+ e);
+ } catch (Exception e) {
+ throw new OpenException("Error while opening workflow", e);
+ }
+
+ return workflowBundle;
+ }
+
+ @Override
+ public List<FileType> getOpenFileTypes() {
+ return Arrays.<FileType> asList(WF_BUNDLE_FILE_TYPE);
+ }
+
+ @Override
+ public List<Class<?>> getOpenSourceTypes() {
+ return Arrays.<Class<?>> asList(InputStream.class, URL.class,
+ File.class);
+ }
+
+ public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) {
+ this.workflowBundleIO = workflowBundleIO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/52fd79dd/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleSaver.java
----------------------------------------------------------------------
diff --git a/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleSaver.java b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleSaver.java
new file mode 100644
index 0000000..f6b7108
--- /dev/null
+++ b/taverna-file-impl/src/main/java/net/sf/taverna/t2/workbench/file/impl/WorkflowBundleSaver.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program 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; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.file.impl;
+
+import static net.sf.taverna.t2.workbench.file.impl.WorkflowBundleFileType.APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import net.sf.taverna.t2.workbench.file.AbstractDataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.DataflowInfo;
+import net.sf.taverna.t2.workbench.file.DataflowPersistenceHandler;
+import net.sf.taverna.t2.workbench.file.FileType;
+import net.sf.taverna.t2.workbench.file.exceptions.SaveException;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.io.WorkflowBundleIO;
+
+public class WorkflowBundleSaver extends AbstractDataflowPersistenceHandler
+ implements DataflowPersistenceHandler {
+ private static final WorkflowBundleFileType WF_BUNDLE_FILE_TYPE = new WorkflowBundleFileType();
+ private static Logger logger = Logger.getLogger(WorkflowBundleSaver.class);
+ private WorkflowBundleIO workflowBundleIO;
+
+ @Override
+ public DataflowInfo saveDataflow(WorkflowBundle workflowBundle, FileType fileType,
+ Object destination) throws SaveException {
+ if (!getSaveFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+ OutputStream outStream;
+ if (destination instanceof File)
+ try {
+ outStream = new FileOutputStream((File) destination);
+ } catch (FileNotFoundException e) {
+ throw new SaveException("Can't create workflow file "
+ + destination + ":\n" + e.getLocalizedMessage(), e);
+ }
+ else if (destination instanceof OutputStream)
+ outStream = (OutputStream) destination;
+ else
+ throw new SaveException("Unsupported destination type "
+ + destination.getClass());
+
+ try {
+ saveDataflowToStream(workflowBundle, outStream);
+ } finally {
+ try {
+ // Only close if we opened the stream
+ if (!(destination instanceof OutputStream))
+ outStream.close();
+ } catch (IOException e) {
+ logger.warn("Could not close stream", e);
+ }
+ }
+
+ if (destination instanceof File)
+ return new FileDataflowInfo(WF_BUNDLE_FILE_TYPE, (File) destination,
+ workflowBundle);
+ return new DataflowInfo(WF_BUNDLE_FILE_TYPE, destination, workflowBundle);
+ }
+
+ protected void saveDataflowToStream(WorkflowBundle workflowBundle,
+ OutputStream fileOutStream) throws SaveException {
+ try {
+ workflowBundleIO.writeBundle(workflowBundle, fileOutStream,
+ APPLICATION_VND_TAVERNA_SCUFL2_WORKFLOW_BUNDLE);
+ } catch (Exception e) {
+ throw new SaveException("Can't write workflow:\n"
+ + e.getLocalizedMessage(), e);
+ }
+ }
+
+ @Override
+ public List<FileType> getSaveFileTypes() {
+ return Arrays.<FileType> asList(WF_BUNDLE_FILE_TYPE);
+ }
+
+ @Override
+ public List<Class<?>> getSaveDestinationTypes() {
+ return Arrays.<Class<?>> asList(File.class, OutputStream.class);
+ }
+
+ @Override
+ public boolean wouldOverwriteDataflow(WorkflowBundle workflowBundle, FileType fileType,
+ Object destination, DataflowInfo lastDataflowInfo) {
+ if (!getSaveFileTypes().contains(fileType))
+ throw new IllegalArgumentException("Unsupported file type "
+ + fileType);
+ if (!(destination instanceof File))
+ return false;
+
+ File file;
+ try {
+ file = ((File) destination).getCanonicalFile();
+ } catch (IOException e) {
+ return false;
+ }
+ if (!file.exists())
+ return false;
+ if (lastDataflowInfo == null)
+ return true;
+ Object lastDestination = lastDataflowInfo.getCanonicalSource();
+ if (!(lastDestination instanceof File))
+ return true;
+ File lastFile = (File) lastDestination;
+ if (!lastFile.getAbsoluteFile().equals(file))
+ return true;
+
+ Date lastModified = new Date(file.lastModified());
+ if (lastModified.equals(lastDataflowInfo.getLastModified()))
+ return false;
+ return true;
+ }
+
+ public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) {
+ this.workflowBundleIO = workflowBundleIO;
+ }
+}