Index: main/plugin-odf/plugin.xml
===================================================================
--- main/plugin-odf/plugin.xml (revision 19862)
+++ main/plugin-odf/plugin.xml (working copy)
@@ -4514,4 +4514,13 @@
+
+
+
+
+
+
+
Index: main/plugin-odf/src/org/ametys/odf/io/importers/ODFImporter.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/importers/ODFImporter.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/importers/ODFImporter.java (revision 0)
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2012 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ametys.odf.io.importers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Workspace;
+
+import org.apache.avalon.framework.component.Component;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.xml.sax.SAXException;
+
+import org.ametys.cms.content.archive.ArchiveConstants;
+import org.ametys.cms.io.handlers.ImportAmetysObjectHandler;
+import org.ametys.cms.io.handlers.ImportWorkflowHandler;
+import org.ametys.cms.io.importers.AmetysImporter;
+import org.ametys.cms.io.importers.BinaryPropertiesImporter;
+import org.ametys.cms.io.importers.ImportReferenceTracker;
+import org.ametys.cms.io.importers.WorkflowImporter;
+import org.ametys.odf.Init;
+import org.ametys.odf.orgunit.OrgUnit;
+import org.ametys.odf.orgunit.OrgUnitFactory;
+import org.ametys.odf.orgunit.RootOrgUnitProvider;
+import org.ametys.odf.workflow.CreateOrgUnitFunction;
+import org.ametys.plugins.repository.AmetysObject;
+import org.ametys.plugins.repository.AmetysObjectIterable;
+import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.plugins.repository.ModifiableAmetysObject;
+import org.ametys.plugins.repository.ModifiableTraversableAmetysObject;
+import org.ametys.plugins.repository.TraversableAmetysObject;
+import org.ametys.plugins.repository.lock.LockableAmetysObject;
+import org.ametys.plugins.repository.provider.AbstractRepository;
+import org.ametys.runtime.config.Config;
+
+/**
+ * ODF importer
+ */
+public class ODFImporter extends AmetysImporter implements Component, Serviceable
+{
+ /** Avalon role. */
+ public static final String ROLE = ODFImporter.class.getName();
+
+ // Key used to configure the importers
+ /** configuration key of the odf root node importer */
+ public static final String ODF_ROOT_NODE_PROPERTIES = "odfRootNode";
+ /** configuration key of the workflow importer */
+ public static final String WORKFLOWS_PROPERTIES = "workflows";
+ /** configuration key of the binary properties importer */
+ public static final String BINARY_PROPERTIES = "binary";
+
+ /** The Ametys object resolver */
+ protected AmetysObjectResolver _resolver;
+
+ /** JCR Repository */
+ protected Repository _repository;
+
+ /** The root orgunit provider */
+ protected RootOrgUnitProvider _rootOUProvider;
+
+ /** The workflow importer */
+ protected WorkflowImporter _workflowImporter;
+
+ /** The odf root node importer */
+ protected ODFRootNodeImporter _odfRootNodeImporter;
+
+ /** The binary properties importer */
+ protected BinaryPropertiesImporter _binaryPropertiesImporter;
+
+ /** Map containing the properties for each exporter used during the global import */
+ protected Map _importerProperties = new HashMap();
+
+ @Override
+ public void service(ServiceManager manager) throws ServiceException
+ {
+ _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
+ _repository = (Repository) manager.lookup(AbstractRepository.ROLE);
+ _rootOUProvider = (RootOrgUnitProvider) manager.lookup(RootOrgUnitProvider.ROLE);
+ _workflowImporter = (WorkflowImporter) manager.lookup(WorkflowImporter.ROLE);
+ _odfRootNodeImporter = (ODFRootNodeImporter) manager.lookup(ODFRootNodeImporter.ROLE);
+ _binaryPropertiesImporter = (BinaryPropertiesImporter) manager.lookup(BinaryPropertiesImporter.ROLE);
+ }
+
+ /**
+ * Proceed the import of the odf into the default workspace.
+ * @param importerProperties
+ * @return The imported node
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ public Node doImport(Map importerProperties) throws RepositoryException, SAXException, IOException
+ {
+ Session session = null;
+
+ try
+ {
+ session = _repository.login();
+ return _doImportInternal(importerProperties, session, session);
+ }
+ finally
+ {
+ if (session != null)
+ {
+ session.logout();
+ }
+ }
+ }
+
+ /**
+ * Proceed the import of a odf into the archive workspace.
+ * @param importerProperties
+ * @return The imported node
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ public Node doImportArchives(Map importerProperties) throws RepositoryException, SAXException, IOException
+ {
+ Session defaultSession = null;
+ Session archiveSession = null;
+
+ try
+ {
+ archiveSession = _getArchiveSession();
+ defaultSession = _repository.login();
+ return _doImportInternal(importerProperties, archiveSession, defaultSession);
+ }
+ finally
+ {
+ if (archiveSession != null)
+ {
+ archiveSession.logout();
+ }
+
+ if (defaultSession != null)
+ {
+ defaultSession.logout();
+ }
+ }
+ }
+
+ /**
+ * Internal method where the import is actually done.
+ * @param importerProperties
+ * @param importSession
+ * @param defaultSession
+ * @return The imported node
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ protected Node _doImportInternal(Map importerProperties, Session importSession, Session defaultSession) throws RepositoryException, SAXException, IOException
+ {
+ // unlock and remove the ODF.
+ _deleteActualODFRootNode(importSession);
+
+ // import workflow
+ ImportReferenceTracker referenceTracker = new ImportReferenceTracker();
+ ImportWorkflowHandler importWorkflowHandler = _importWorkflow(importSession, defaultSession, importerProperties.get(WORKFLOWS_PROPERTIES), referenceTracker);
+
+ // import odf root node
+ ImportAmetysObjectHandler importOdfHandler = _importODFRootNode(importSession, importerProperties.get(ODF_ROOT_NODE_PROPERTIES), importWorkflowHandler.getIdMapping(), referenceTracker);
+ Node odfRootNode = importOdfHandler.getImportedNode();
+
+ // adjust references
+ _adjustReferenceProperties(odfRootNode, referenceTracker);
+
+ // workflows and odf root node are now imported, a save is possible.
+ importSession.save();
+ defaultSession.save();
+
+ // import binary properties
+ _importBinaryProperties(importSession, importerProperties.get(BINARY_PROPERTIES));
+
+ // adjust versionable nodes
+ _adjustVersionableNodes(odfRootNode, importOdfHandler.getExportDate());
+
+ _updateRootOrgunit(importSession);
+
+ // final save
+ importSession.save();
+
+ return odfRootNode;
+ }
+
+ /**
+ * Import the workflow from the given input stream.
+ * @param importSession
+ * @param defaultSession
+ * @param properties
+ * @param referenceTracker
+ * @return ImportWorkflowHandler
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ protected ImportWorkflowHandler _importWorkflow(Session importSession, Session defaultSession, Properties properties, ImportReferenceTracker referenceTracker) throws RepositoryException, SAXException, IOException
+ {
+ InputStream inputStream = (InputStream) properties.get(WorkflowImporter.INPUT_STREAM_PROPERTY);
+ return _workflowImporter.doImport(importSession, defaultSession, inputStream, referenceTracker);
+ }
+
+ /**
+ * Import the odf root node from a given input stream.
+ * @param session
+ * @param properties
+ * @param workflowIdMapping
+ * @param referenceTracker
+ * @return ImportAmetysObjectHandler
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ protected ImportAmetysObjectHandler _importODFRootNode(Session session, Properties properties, Map workflowIdMapping, ImportReferenceTracker referenceTracker) throws RepositoryException, SAXException, IOException
+ {
+ InputStream inputStream = (InputStream) properties.get(ODFRootNodeImporter.INPUT_STREAM_PROPERTY);
+ return _odfRootNodeImporter.doImport(session, inputStream, workflowIdMapping, referenceTracker);
+ }
+
+ /**
+ * Import the binary properties
+ * @param importSession
+ * @param properties
+ * @throws RepositoryException
+ */
+ protected void _importBinaryProperties(Session importSession, Properties properties) throws RepositoryException
+ {
+ List importDataList = (List) properties.get(BinaryPropertiesImporter.IMPORT_DATA_LIST_PROPERTY);
+ _binaryPropertiesImporter.doImport(importSession, importDataList);
+ }
+
+ /**
+ * Retrieve a session bound to the 'archives' workspace. Create and
+ * initialize the 'archives' workspace if necessary.
+ *
+ * @return
+ * @throws RepositoryException
+ */
+ private Session _getArchiveSession() throws RepositoryException
+ {
+ try
+ {
+ return _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE);
+ }
+ catch (NoSuchWorkspaceException e)
+ {
+ _repository.login().getWorkspace().createWorkspace(ArchiveConstants.ARCHIVE_WORKSPACE);
+
+ Session archiveSession = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE);
+ archiveSession.getRootNode().addNode(AmetysObjectResolver.ROOT_REPO, AmetysObjectResolver.ROOT_TYPE);
+ return archiveSession;
+ }
+ }
+
+ /**
+ * Delete the actual odf root node if existing.
+ * @param session The session in which the job will be done
+ * @throws RepositoryException
+ */
+ protected void _deleteActualODFRootNode(Session session) throws RepositoryException
+ {
+ Node ametysRootNode = session.getRootNode().getNode(AmetysObjectResolver.ROOT_REPO);
+ TraversableAmetysObject root = _resolver.resolve(ametysRootNode, false);
+
+ if (root.hasChild(Init._ODF_ROOT_NODE))
+ {
+ ModifiableTraversableAmetysObject odfRootAmetysObject = root.getChild(Init._ODF_ROOT_NODE);
+ _deleteAmetysObject(odfRootAmetysObject);
+ }
+ }
+
+ private void _deleteAmetysObject(AmetysObject ametysObject)
+ {
+ // unlock
+ if (ametysObject instanceof LockableAmetysObject)
+ {
+ LockableAmetysObject lockableObject = (LockableAmetysObject) ametysObject;
+ if (lockableObject.isLocked())
+ {
+ lockableObject.unlock();
+ }
+ }
+
+ // recursive call to children
+ if (ametysObject instanceof TraversableAmetysObject)
+ {
+ AmetysObjectIterable children = ((TraversableAmetysObject) ametysObject).getChildren();
+ for (AmetysObject child : children)
+ {
+ _deleteAmetysObject(child);
+ }
+ }
+
+ // remove
+ if (ametysObject instanceof ModifiableAmetysObject)
+ {
+ ((ModifiableAmetysObject) ametysObject).remove();
+ }
+ }
+
+ /**
+ * Update the root orgunit at the end of the import (default workspace only)
+ * @param importSession
+ * @throws RepositoryException
+ */
+ protected void _updateRootOrgunit(Session importSession) throws RepositoryException
+ {
+ Workspace importWorkspace = importSession.getWorkspace();
+ boolean isArchiveWS = ArchiveConstants.ARCHIVE_WORKSPACE.equals(importWorkspace.getName());
+
+ if (!isArchiveWS)
+ {
+ Node ametysRootNode = importSession.getRootNode().getNode(AmetysObjectResolver.ROOT_REPO);
+ TraversableAmetysObject ametysRoot = _resolver.resolve(ametysRootNode, false);
+
+ String rootOUPath = Init._ODF_ROOT_NODE + '/' + Init._ODF_CONTENTS_ROOT_NODE + '/' + CreateOrgUnitFunction.CONTENT_NAME_PREFIX + OrgUnitFactory._ODF_ORGUNIT_ROOT_NODE;
+ OrgUnit rootOU = ametysRoot.getChild(rootOUPath);
+
+ // Set root id
+ _rootOUProvider.setRootId(rootOU.getId());
+
+ // Set UAI from config
+ rootOU.setUAICode(Config.getInstance().getValueAsString("odf.root-orgunit.uaiCode"));
+ }
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/importers/ODFRootNodeImporter.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/importers/ODFRootNodeImporter.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/importers/ODFRootNodeImporter.java (revision 0)
@@ -0,0 +1,62 @@
+package org.ametys.odf.io.importers;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.xml.sax.SAXException;
+
+import org.ametys.cms.io.handlers.ImportAmetysObjectHandler;
+import org.ametys.cms.io.importers.ImportReferenceTracker;
+import org.ametys.cms.io.importers.JcrImporter;
+import org.ametys.plugins.repository.AmetysObjectResolver;
+
+/**
+ * ODF root node importer using the JCR Import.
+ */
+public class ODFRootNodeImporter extends JcrImporter
+{
+ /** Avalon role. */
+ public static final String ROLE = ODFRootNodeImporter.class.getName();
+
+ /** import input stream property */
+ public static final String INPUT_STREAM_PROPERTY = "inputStream";
+
+ @Override
+ public void service(ServiceManager manager) throws ServiceException
+ {
+ super.service(manager);
+ }
+
+ /**
+ * Import the odf root node from an inputstream.
+ * @param session The session in which the import will be done
+ * @param inputStream
+ * @param workflowIdMapping
+ * @param referenceTracker
+ * @return the importWorkflowHandler
+ * @throws RepositoryException
+ * @throws SAXException
+ * @throws IOException
+ */
+ public ImportAmetysObjectHandler doImport(Session session, InputStream inputStream, Map workflowIdMapping, ImportReferenceTracker referenceTracker) throws RepositoryException, SAXException, IOException
+ {
+ Node ametysRootNode = session.getRootNode().getNode(AmetysObjectResolver.ROOT_REPO);
+
+ // Get the import handler
+ int uuidBehavior = ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW; // An exception will be thrown if there is an identifier collision.
+ ImportAmetysObjectHandler importHandlerProxy = new ImportAmetysObjectHandler(ametysRootNode, referenceTracker, workflowIdMapping);
+
+ // Performing the import.
+ importNode(ametysRootNode, uuidBehavior, inputStream, importHandlerProxy);
+
+ return importHandlerProxy;
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/exporters/ODFExporter.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/exporters/ODFExporter.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/exporters/ODFExporter.java (revision 0)
@@ -0,0 +1,271 @@
+package org.ametys.odf.io.exporters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.xml.sax.ContentHandler;
+
+import org.ametys.cms.io.exporters.AmetysExporter;
+import org.ametys.cms.io.exporters.BinaryPropertiesExporter;
+import org.ametys.cms.io.exporters.JcrExportListener;
+import org.ametys.cms.io.exporters.LogExporter;
+import org.ametys.cms.io.exporters.WorkflowExporter;
+
+/**
+ * Configurable ODF Exporter. Exports its content into
+ * ContentHandler
and/or OutputStream
+ */
+public class ODFExporter extends AmetysExporter
+{
+ // Key used to configure the exporters
+ /** configuration key of the odf root node exporter */
+ public static final String ODF_ROOT_NODE_PROPERTIES = "odfRootNode";
+ /** configuration key of the workflow exporter */
+ public static final String WORKFLOWS_PROPERTIES = "workflows";
+ /** configuration key of the binary properties exporter */
+ public static final String BINARY_PROPERTIES = "binary";
+ /** configuration key of the logs exporter */
+ public static final String LOGS_PROPERTIES = "logs";
+
+ /** The odf root node */
+ protected final Node _odfRootNode;
+
+ /**
+ * Ctor
+ * @param odfRootNode
+ */
+ public ODFExporter(Node odfRootNode)
+ {
+ _odfRootNode = odfRootNode;
+ }
+
+ @Override
+ protected void _exportInternal() throws IOException
+ {
+ try
+ {
+ final Session session = _odfRootNode.getSession();
+
+ // Export the odf root node
+ onODFRootNodeExportStart();
+ ODFRootNodeExporter odfRootNodeExporter = _exportODFRootNode();
+ onODFRootNodeExportEnd();
+
+ // Export workflow nodes
+ onWorkflowsExportStart(odfRootNodeExporter.getWorkflowRefs());
+ _exportWorkflows(odfRootNodeExporter);
+ onWorkflowsExportEnd(odfRootNodeExporter.getWorkflowRefs());
+
+ // Export the binary properties
+ onBinaryPropertiesExportStart(odfRootNodeExporter.getBinaryProperties());
+ _exportBinaryProperties(odfRootNodeExporter);
+ onBinaryPropertiesExportEnd(odfRootNodeExporter.getBinaryProperties());
+
+ // Export log file
+ onLogExportStart(odfRootNodeExporter.getExternalReferences());
+ _exportLog(odfRootNodeExporter);
+ onLogExportEnd(odfRootNodeExporter.getExternalReferences());
+
+ // Do not save changes.
+ session.refresh(false);
+ }
+ catch (Exception e)
+ {
+ _logger.error("Unable to export the ODF", e);
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Export the ODF root node.
+ * @return The exporter used to export the ODF root node, which is a {@link ODFRootNodeExporter}
+ * @throws Exception
+ */
+ protected ODFRootNodeExporter _exportODFRootNode() throws Exception
+ {
+ Properties props = _getODFRootNodeProperties();
+ ODFRootNodeExporter exporter = new ODFRootNodeExporter(_odfRootNode, (ContentHandler) props.get(CONTENT_HANDLER_PROPERTY));
+
+ JcrExportListener listener = (JcrExportListener) props.get(LISTENER_PROPERTY);
+ exporter.setListener(listener);
+
+ exporter.export(true); // skip binary, they will be exported later.
+
+ return exporter;
+ }
+
+ /**
+ * Export the workflow nodes which references have been collected during the
+ * export of the odf root node.
+ *
+ * @param odfRootNodeExporter The exporter used to export the odf root node.
+ * @throws Exception
+ */
+ protected void _exportWorkflows(ODFRootNodeExporter odfRootNodeExporter) throws Exception
+ {
+ Properties props = _getWorkflowProperties();
+
+ final Session session = _odfRootNode.getSession();
+ WorkflowExporter exporter = new WorkflowExporter(odfRootNodeExporter.getWorkflowRefs(), session, (ContentHandler) props.get(CONTENT_HANDLER_PROPERTY));
+ JcrExportListener listener = (JcrExportListener) props.get(LISTENER_PROPERTY);
+ exporter.setListener(listener);
+
+ exporter.export();
+ }
+
+ /**
+ * Export the binary properties (jcr) that have been collected during the
+ * export of the odf root node.
+ *
+ * @param odfRootNodeExporter The exporter used to export the odf root node.
+ * @throws Exception
+ */
+ protected void _exportBinaryProperties(ODFRootNodeExporter odfRootNodeExporter) throws Exception
+ {
+ Properties props = _getBinaryPropertiesProperties();
+
+ BinaryPropertiesExporter exporter = new BinaryPropertiesExporter(_odfRootNode.getParent(), odfRootNodeExporter.getBinaryProperties(), (OutputStream) props.get(OUTPUT_STREAM_PROPERTY));
+ JcrExportListener listener = (JcrExportListener) props.get(LISTENER_PROPERTY);
+ exporter.setListener(listener);
+
+ exporter.export();
+ }
+
+ /**
+ * Export some logs
+ * @param odfRootNodeExporter
+ * @throws RepositoryException
+ * @see LogExporter
+ */
+ protected void _exportLog(ODFRootNodeExporter odfRootNodeExporter) throws RepositoryException
+ {
+ Properties props = _getLogProperties();
+
+ final Session session = _odfRootNode.getSession();
+ LogExporter exporter = new LogExporter(odfRootNodeExporter.getExternalReferences(), session, (OutputStream) props.get(OUTPUT_STREAM_PROPERTY));
+
+ exporter.export();
+ }
+
+ /**
+ * Retrieves the properties of the ODF root node exporter.
+ * @return these configured properties
+ */
+ protected Properties _getODFRootNodeProperties()
+ {
+ return _internalCheckAndGetProperties(ODF_ROOT_NODE_PROPERTIES, Arrays.asList(CONTENT_HANDLER_PROPERTY), Arrays.asList(LISTENER_PROPERTY));
+ }
+
+ /**
+ * Retrieves the properties of the workflow exporter.
+ * @return these configured properties
+ */
+ protected Properties _getWorkflowProperties()
+ {
+ return _internalCheckAndGetProperties(WORKFLOWS_PROPERTIES, Arrays.asList(CONTENT_HANDLER_PROPERTY), Arrays.asList(LISTENER_PROPERTY));
+ }
+
+ /**
+ * Retrieves the properties of the binary property exporter.
+ * @return these configured properties
+ */
+ protected Properties _getBinaryPropertiesProperties()
+ {
+ return _internalCheckAndGetProperties(BINARY_PROPERTIES, Arrays.asList(OUTPUT_STREAM_PROPERTY), Arrays.asList(LISTENER_PROPERTY));
+ }
+
+ /**
+ * Retrieves the properties of the log exporter.
+ * @return these configured properties
+ */
+ protected Properties _getLogProperties()
+ {
+ return _internalCheckAndGetProperties(LOGS_PROPERTIES, Arrays.asList(OUTPUT_STREAM_PROPERTY), Collections.EMPTY_LIST);
+ }
+
+ // ------- Empty listener methods ----------------------------------------<
+ /**
+ * onODFRootNodeExportStart listener
+ * @throws Exception
+ */
+ public void onODFRootNodeExportStart() throws Exception
+ {
+ // Nothing by default
+ }
+ /**
+ * onODFRootNodeExportEnd listener
+ * @throws Exception
+ */
+ public void onODFRootNodeExportEnd() throws Exception
+ {
+ // Nothing by default
+ }
+
+ /**
+ * onWorkflowsExportStart listener
+ * @param workflowRefs
+ * @throws Exception
+ */
+ public void onWorkflowsExportStart(Set workflowRefs) throws Exception
+ {
+ // Nothing by default
+ }
+ /**
+ * onWorkflowsExportEnd listener
+ * @param workflowRefs
+ * @throws Exception
+ */
+ public void onWorkflowsExportEnd(Set workflowRefs) throws Exception
+ {
+ // Nothing by default
+ }
+
+ /**
+ * onBinaryPropertiesExportStart listener
+ * @param binaryMap
+ * @throws Exception
+ */
+ public void onBinaryPropertiesExportStart(Map> binaryMap) throws Exception
+ {
+ // Nothing by default
+ }
+ /**
+ * onBinaryPropertiesExportEnd listener
+ * @param binaryMap
+ * @throws Exception
+ */
+ public void onBinaryPropertiesExportEnd(Map> binaryMap) throws Exception
+ {
+ // Nothing by default
+ }
+
+ /**
+ * onLogExportStart listener
+ * @param externalReferences
+ * @throws Exception
+ */
+ public void onLogExportStart(Map> externalReferences) throws Exception
+ {
+ // Nothing by default
+ }
+ /**
+ * onLogExportEnd listener
+ * @param externalReferences
+ * @throws Exception
+ */
+ public void onLogExportEnd(Map> externalReferences) throws Exception
+ {
+ // Nothing by default
+ }
+
+}
Index: main/plugin-odf/src/org/ametys/odf/io/exporters/ODFRootNodeExporter.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/exporters/ODFRootNodeExporter.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/exporters/ODFRootNodeExporter.java (revision 0)
@@ -0,0 +1,97 @@
+package org.ametys.odf.io.exporters;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.Node;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.xml.sax.ContentHandler;
+
+import org.ametys.cms.io.exporters.JcrExporter;
+import org.ametys.cms.io.exporters.WorkflowExporter;
+import org.ametys.odf.io.handlers.ExportODFHandler;
+import org.ametys.runtime.util.LoggerFactory;
+
+/**
+ * ODFRootNodeExporter is used to export the root node of the ODF. It has some getter
+ * methods that may be used by other exporters (e.g. {@link WorkflowExporter}).
+ */
+public class ODFRootNodeExporter extends JcrExporter
+{
+ /** logger */
+ protected final Logger _logger = LoggerFactory.getLoggerFor(ODFRootNodeExporter.class);
+
+ /** The odf root node */
+ protected final Node _odfRootNode;
+ /** The export handler */
+ protected final ExportODFHandler _exportODFHandler;
+
+ /**
+ * Ctor
+ * @param odfRootNode
+ * @param contentHandler
+ */
+ public ODFRootNodeExporter(Node odfRootNode, ContentHandler contentHandler)
+ {
+ _odfRootNode = odfRootNode;
+ _exportODFHandler = new ExportODFHandler(contentHandler, odfRootNode);
+ }
+
+ /**
+ * Export method. This is where the job is actually done.
+ * @param skipBinary
+ * @throws Exception
+ */
+ public void export(boolean skipBinary) throws Exception
+ {
+ try
+ {
+ exportNode(_odfRootNode, _exportODFHandler, skipBinary, true);
+ }
+ catch (Exception e)
+ {
+ // Log and re-throw
+ _logger.error("Unable to export the ODF", e);
+ throw e;
+ }
+ }
+
+ /**
+ * Retrieves the workflow identifiers.
+ * @return the workflow identifiers
+ */
+ public Set getWorkflowRefs()
+ {
+ return _exportODFHandler.getWorkflowRefs();
+ }
+
+ /**
+ * Retrieves the binary properties.
+ * @return the binaryProperties
+ */
+ public Map> getBinaryProperties()
+ {
+ return _exportODFHandler.getBinaryProperties();
+ }
+
+ /**
+ * Retrieves the resources.
+ * @return the resources
+ */
+ public Set getResources()
+ {
+ return _exportODFHandler.getResources();
+ }
+
+ /**
+ * Retrieves the external references
+ * @return the externalReferences
+ */
+ public Map> getExternalReferences()
+ {
+ return _exportODFHandler.getExternalReferences();
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/UploadODFAction.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/UploadODFAction.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/UploadODFAction.java (revision 0)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2012 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ametys.odf.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.acting.ServiceableAction;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.servlet.multipart.Part;
+import org.apache.cocoon.servlet.multipart.PartOnDisk;
+import org.apache.cocoon.servlet.multipart.RejectedPart;
+import org.apache.commons.io.FileUtils;
+
+import org.ametys.runtime.cocoon.JSonReader;
+
+/**
+ * This action receives a form with the "importfile" file.
+ * This file must be a zip archive containing serialized data representing the ODF.
+ */
+public class UploadODFAction extends ServiceableAction
+{
+ @Override
+ public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
+ {
+ Request request = ObjectModelHelper.getRequest(objectModel);
+ Map result = new LinkedHashMap();
+
+ try
+ {
+ // Checking file
+ Part part = (Part) request.get("importfile");
+ if (part instanceof RejectedPart || part == null)
+ {
+ result.put("success", false);
+ result.put("error", "rejected");
+ }
+ else
+ {
+ // Getting file
+ PartOnDisk uploadedFilePart = (PartOnDisk) part;
+ File uploadedFile = uploadedFilePart.getFile();
+
+ // Copy the file into the default tmp dir.
+ File tmpFile = _copyToTmpDir(uploadedFile);
+
+ result.put("tmpFilePath", tmpFile.getPath());
+ result.put("success", true);
+ }
+ }
+ catch (Exception e)
+ {
+ getLogger().error("Unable to upload the ODF", e);
+ result.put("success", false);
+
+ Map ex = new HashMap();
+ ex.put("message", e.getMessage());
+
+ result.put("error", ex);
+ }
+
+ request.setAttribute(JSonReader.MAP_TO_READ, result);
+ return EMPTY_MAP;
+ }
+
+ /**
+ * Copy the uploaded file in a temporary directory.
+ * @param uploadedFile the uploaded file
+ * @return the copied file instance
+ * @throws IOException
+ */
+ protected File _copyToTmpDir(File uploadedFile) throws IOException
+ {
+ File destFile = File.createTempFile("odf", ".zip");
+ FileUtils.copyFile(uploadedFile, destFile);
+ return destFile;
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/ExportODFArchiver.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/ExportODFArchiver.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/ExportODFArchiver.java (revision 0)
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2012 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ametys.odf.io;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.reading.ServiceableReader;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.UnicodeExtraFieldPolicy;
+import org.apache.commons.lang.StringUtils;
+import org.apache.xml.serializer.OutputPropertiesFactory;
+import org.xml.sax.SAXException;
+
+import org.ametys.cms.content.archive.ArchiveConstants;
+import org.ametys.cms.io.IOConstants;
+import org.ametys.cms.io.IOUtils;
+import org.ametys.cms.io.exporters.AmetysExporter;
+import org.ametys.cms.io.exporters.DefaultJcrExportListener;
+import org.ametys.cms.io.exporters.LogExporter;
+import org.ametys.odf.Init;
+import org.ametys.odf.io.exporters.ODFExporter;
+import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.plugins.repository.provider.AbstractRepository;
+import org.ametys.runtime.util.IgnoreRootHandler;
+
+/**
+ * Generate a ZIP Archive of the ODF.
+ */
+public class ExportODFArchiver extends ServiceableReader
+{
+ /** The final transformer handler */
+ protected TransformerHandler _transformerHandler;
+
+ /** The Zip stream where entries will be written */
+ protected ZipArchiveOutputStream _zipOutput;
+
+ /** The Ametys object resolver */
+ protected AmetysObjectResolver _resolver;
+
+ /** JCR Repository */
+ protected Repository _repository;
+
+ @Override
+ public void service(ServiceManager sManager) throws ServiceException
+ {
+ super.service(sManager);
+ _resolver = (AmetysObjectResolver) sManager.lookup(AmetysObjectResolver.ROLE);
+ _repository = (Repository) sManager.lookup(AbstractRepository.ROLE);
+ }
+
+ @Override
+ public String getMimeType()
+ {
+ return "application/zip";
+ }
+
+ @Override
+ public void generate() throws IOException, SAXException, ProcessingException
+ {
+ try
+ {
+ // Create a ZIP OutputStream that writes into the reader OutputStream
+ _zipOutput = new ZipArchiveOutputStream(out);
+ _zipOutput.setCreateUnicodeExtraFields(UnicodeExtraFieldPolicy.ALWAYS);
+ _zipOutput.setEncoding("UTF-8");
+
+ // Parameterize the handlers
+ _initializeTransformerHandler();
+
+ // Export the ODF into the ZIP Archive.
+ _exportODF();
+ _exportArchives();
+ }
+ finally
+ {
+ if (_zipOutput != null)
+ {
+ _zipOutput.finish();
+ _zipOutput.close();
+ }
+ }
+ }
+
+ private void _exportODF() throws IOException, ProcessingException
+ {
+ Session session = null;
+ try
+ {
+ session = _repository.login();
+ Node odfRootNode = session.getRootNode().getNode(AmetysObjectResolver.ROOT_REPO + '/' + Init._ODF_ROOT_NODE);
+
+ _exportInternal(odfRootNode);
+ }
+ catch (RepositoryException e)
+ {
+ getLogger().error("Unable to perfom the export of the ODF", e);
+ throw new ProcessingException(e);
+ }
+ finally
+ {
+ if (session != null)
+ {
+ session.logout();
+ }
+ }
+ }
+
+ private void _exportArchives() throws IOException, ProcessingException
+ {
+ Session session = null;
+ try
+ {
+ session = _repository.login(ArchiveConstants.ARCHIVE_WORKSPACE);
+
+ try
+ {
+ Node odfRootNode = session.getRootNode().getNode(AmetysObjectResolver.ROOT_REPO + '/' + Init._ODF_ROOT_NODE);
+
+ _exportInternal(odfRootNode, IOConstants.ARCHIVES_DIR);
+ }
+ catch (PathNotFoundException e)
+ {
+ // Nothing to export
+ }
+ }
+ catch (NoSuchWorkspaceException e)
+ {
+ // Nothing to export
+ }
+ catch (RepositoryException e)
+ {
+ getLogger().error("Unable to perfom the export of the ODF in the 'archives' workspace. ", e);
+ throw new ProcessingException(e);
+ }
+ finally
+ {
+ if (session != null)
+ {
+ session.logout();
+ }
+ }
+ }
+
+ private void _exportInternal(Node odfRootNode) throws IOException
+ {
+ _exportInternal(odfRootNode, StringUtils.EMPTY);
+ }
+
+ private void _exportInternal(Node odfRootNode, final String baseEntryName) throws IOException
+ {
+ ODFExporter odfExporter = new ArchiveODFExporter(baseEntryName, odfRootNode);
+
+ // Configure export
+ // odf root node
+ Properties props = new Properties();
+ props.put(AmetysExporter.CONTENT_HANDLER_PROPERTY, _transformerHandler);
+ odfExporter.setProperties(ODFExporter.ODF_ROOT_NODE_PROPERTIES, props);
+
+ // workflows
+ props = new Properties();
+ props.put(AmetysExporter.CONTENT_HANDLER_PROPERTY, new IgnoreRootHandler(_transformerHandler));
+ odfExporter.setProperties(ODFExporter.WORKFLOWS_PROPERTIES, props);
+
+ // binary properties
+ props = new Properties();
+ props.put(AmetysExporter.OUTPUT_STREAM_PROPERTY, _zipOutput);
+ props.put(AmetysExporter.LISTENER_PROPERTY, new BinaryPropertyExportListener(baseEntryName));
+ odfExporter.setProperties(ODFExporter.BINARY_PROPERTIES, props);
+
+ // logs
+ props = new Properties();
+ props.put(AmetysExporter.OUTPUT_STREAM_PROPERTY, _zipOutput);
+ odfExporter.setProperties(ODFExporter.LOGS_PROPERTIES, props);
+
+ // Run the export.
+ odfExporter.export();
+ }
+
+ private void _initializeTransformerHandler() throws ProcessingException
+ {
+ try
+ {
+ _transformerHandler = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler();
+ }
+ catch (Exception e)
+ {
+ getLogger().error("Unable to export the odf", e);
+ throw new ProcessingException(e);
+ }
+
+ // create the format of result
+ final Properties properties = new Properties();
+ properties.put(OutputKeys.METHOD, "xml");
+ properties.put(OutputKeys.INDENT, "yes");
+ properties.put(OutputKeys.ENCODING, "UTF-8");
+ properties.put(OutputKeys.OMIT_XML_DECLARATION, "no");
+ properties.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "4");
+
+ _transformerHandler.getTransformer().setOutputProperties(properties);
+
+ // create the result where to write
+ StreamResult sResult = new StreamResult(_zipOutput);
+ _transformerHandler.setResult(sResult);
+ }
+
+ @Override
+ public void recycle()
+ {
+ this._transformerHandler = null;
+ _zipOutput = null;
+ }
+
+ /**
+ * ArchiveODFExporter
+ */
+ protected class ArchiveODFExporter extends ODFExporter
+ {
+ /** Prefix of the name of the created entries */
+ protected final String _baseEntryName;
+
+ /**
+ * Ctor
+ * @param baseEntryName
+ * @param odfRootNode
+ */
+ public ArchiveODFExporter(String baseEntryName, Node odfRootNode)
+ {
+ super(odfRootNode);
+ _baseEntryName = baseEntryName;
+ }
+
+ @Override
+ public void onODFRootNodeExportStart() throws Exception
+ {
+ if (StringUtils.isNotEmpty(_baseEntryName))
+ {
+ // Create base folder entry.
+ ZipArchiveEntry baseDir = new ZipArchiveEntry(_baseEntryName);
+ _zipOutput.putArchiveEntry(baseDir);
+ _zipOutput.closeArchiveEntry();
+ }
+
+ String entryName = _baseEntryName + IOODFConstants.ODF_FILE_NAME;
+ _zipOutput.putArchiveEntry(new ZipArchiveEntry(entryName));
+ }
+
+ @Override
+ public void onODFRootNodeExportEnd() throws Exception
+ {
+ _zipOutput.closeArchiveEntry();
+ }
+
+ @Override
+ public void onWorkflowsExportStart(Set workflowRefs) throws Exception
+ {
+ if (!workflowRefs.isEmpty())
+ {
+ String entryName = _baseEntryName + IOConstants.WORKFLOWS_FILE_NAME;
+ _zipOutput.putArchiveEntry(new ZipArchiveEntry(entryName));
+
+ // Root element creation.
+ _transformerHandler.startDocument();
+ XMLUtils.startElement(_transformerHandler, IOConstants.WORKFLOW_FILE_ROOT_NODE);
+ }
+ }
+
+ @Override
+ public void onWorkflowsExportEnd(Set workflowRefs) throws Exception
+ {
+ if (!workflowRefs.isEmpty())
+ {
+ // End of the root element
+ XMLUtils.endElement(_transformerHandler, IOConstants.WORKFLOW_FILE_ROOT_NODE);
+ _transformerHandler.endDocument();
+
+ _zipOutput.closeArchiveEntry();
+ }
+ }
+
+ @Override
+ public void onBinaryPropertiesExportStart(Map> binaryMap) throws Exception
+ {
+ if (!binaryMap.isEmpty())
+ {
+ String entryName = _baseEntryName + IOConstants.BINARY_DIR;
+ _zipOutput.putArchiveEntry(new ZipArchiveEntry(entryName));
+ _zipOutput.closeArchiveEntry();
+ }
+ }
+
+ @Override
+ public void onLogExportStart(Map> externalReferences) throws Exception
+ {
+ if (!externalReferences.isEmpty())
+ {
+ ZipArchiveEntry entryDir = new ZipArchiveEntry(_baseEntryName + LogExporter.LOG_FILE_NAME);
+ _zipOutput.putArchiveEntry(entryDir);
+ }
+ }
+
+ @Override
+ public void onLogExportEnd(Map> externalReferences) throws Exception
+ {
+ if (!externalReferences.isEmpty())
+ {
+ _zipOutput.closeArchiveEntry();
+ }
+ }
+ }
+
+ /**
+ * BinaryPropertyExportListener
+ */
+ protected class BinaryPropertyExportListener extends DefaultJcrExportListener
+ {
+ /** Prefix of the name of the created entries */
+ protected final String _baseEntryName;
+
+ /**
+ * Ctor
+ * @param baseEntryName
+ */
+ public BinaryPropertyExportListener(String baseEntryName)
+ {
+ _baseEntryName = baseEntryName;
+ }
+
+ @Override
+ public void onBeforeBinaryPropertyExport(Property property) throws RepositoryException, IOException
+ {
+ String entryName = _getEntryName(property);
+ _zipOutput.putArchiveEntry(new ZipArchiveEntry(entryName));
+ }
+
+ @Override
+ public void onAfterBinaryPropertyExport(Property property) throws IOException
+ {
+ _zipOutput.closeArchiveEntry();
+ }
+
+ /**
+ * Get the entry name in the archive for a given property.
+ * @param property
+ * @return The name of the entry.
+ * @throws RepositoryException
+ */
+ protected String _getEntryName(Property property) throws RepositoryException
+ {
+ final String name = property.getName();
+ final String parentIdentifier = property.getParent().getIdentifier();
+ final String hashPath = StringUtils.join(IOUtils.getHashedName(parentIdentifier), '/') + '/';
+
+ String entryPath = IOConstants.BINARY_DIR + hashPath + parentIdentifier + '/';
+ entryPath += IOUtils.encodeZipEntryName(name);
+
+ return _baseEntryName + entryPath;
+ }
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/IOODFConstants.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/IOODFConstants.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/IOODFConstants.java (revision 0)
@@ -0,0 +1,19 @@
+package org.ametys.odf.io;
+
+import org.ametys.cms.io.IOConstants;
+
+/**
+ * Collection of constants used in the import/export of a site
+ */
+public final class IOODFConstants
+{
+ /** Archive odf filename */
+ public static final String ODF_FILE_NAME = "odf" + IOConstants.SYSTEM_VIEW_EXT;
+
+ /**
+ * Private constructor to prevent instantiation of this class.
+ */
+ private IOODFConstants()
+ {
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/handlers/ExportODFHandler.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/handlers/ExportODFHandler.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/handlers/ExportODFHandler.java (revision 0)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ametys.odf.io.handlers;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.xml.sax.ContentHandler;
+
+import org.ametys.cms.io.handlers.ExportAmetysObjectHandler;
+
+/**
+ * "Proxy" handler used to export an ametys object.
+ */
+public class ExportODFHandler extends ExportAmetysObjectHandler
+{
+ /**
+ * Ctor inheritance
+ * @param contentHandler The {@link ContentHandler} to be wrapped.
+ * @param parentNode The node from which the import/export is relative
+ */
+ public ExportODFHandler(final ContentHandler contentHandler, Node parentNode)
+ {
+ super(contentHandler, parentNode);
+ }
+
+ @Override
+ protected boolean _isExternal(Item referencedItem) throws RepositoryException
+ {
+ String refItemPath = referencedItem.getPath();
+ String odfRootNodePath = _parentNode.getPath();
+
+ // To be considered as external, referenced item should not belong to the odf root node.
+ return !refItemPath.startsWith(odfRootNodePath);
+ }
+}
Index: main/plugin-odf/src/org/ametys/odf/io/ImportODFAction.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/io/ImportODFAction.java (revision 0)
+++ main/plugin-odf/src/org/ametys/odf/io/ImportODFAction.java (revision 0)
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2012 Anyware Services
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.ametys.odf.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.cocoon.acting.ServiceableAction;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Redirector;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.xml.sax.SAXException;
+
+import org.ametys.cms.io.IOConstants;
+import org.ametys.cms.io.IOUtils;
+import org.ametys.cms.io.importers.BinaryPropertiesImporter;
+import org.ametys.cms.io.importers.WorkflowImporter;
+import org.ametys.odf.io.importers.ODFImporter;
+import org.ametys.odf.io.importers.ODFRootNodeImporter;
+
+/**
+ * This action import the odf from a zip file located in "java.io.tmpdir"
+ */
+public class ImportODFAction extends ServiceableAction
+{
+ /** The odf importer */
+ protected ODFImporter _odfImporter;
+
+ @Override
+ public void service(ServiceManager smanager) throws ServiceException
+ {
+ super.service(smanager);
+ _odfImporter = (ODFImporter) smanager.lookup(ODFImporter.ROLE);
+ }
+
+ @Override
+ public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
+ {
+ Map result = new LinkedHashMap();
+ Request request = ObjectModelHelper.getRequest(objectModel);
+
+// String tmpFilePath = request.getParameter("tmpFilePath");
+ // TODO remove this, only for test purpose.
+ String tmpFilePath = "C:\\home\\work\\interne\\io-odf\\odf.zip";
+ boolean deleteFile = new Boolean(StringUtils.defaultString(request.getParameter("deleteFile"), "false"));
+
+ File tmpArchiveFile = null;
+ ZipFile odfZipFile = null;
+ try
+ {
+ tmpArchiveFile = new File(tmpFilePath);
+ odfZipFile = new ZipFile(tmpArchiveFile, "UTF-8", true);
+
+ _importODFFromZip(odfZipFile);
+
+ result.put("success", true);
+ }
+ catch (Exception e)
+ {
+ String msg = "Unable to import ODF";
+ getLogger().error(msg, e);
+
+ msg += "\nError message : " + e;
+ result.put("success", false);
+ result.put("error", msg);
+ }
+ finally
+ {
+ if (odfZipFile != null)
+ {
+ odfZipFile.close();
+ }
+
+ if (deleteFile)
+ {
+ FileUtils.deleteQuietly(tmpArchiveFile);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Traverse the zip archive and import data on the fly.
+ * @param odfZipFile The ZipFile of the archive
+ * @throws IOException
+ * @throws SAXException
+ * @throws RepositoryException
+ */
+ private void _importODFFromZip(ZipFile odfZipFile) throws IOException, SAXException, RepositoryException
+ {
+ ZipArchiveEntry entry = null;
+
+ // Traverse the odf zip archive to class entries by workspace (default or archives).
+ Set archivesEntries = new HashSet();
+ Set defaultEntries = new HashSet();
+ for (Enumeration entries = odfZipFile.getEntries(); entries.hasMoreElements();)
+ {
+ entry = entries.nextElement();
+ if (!entry.isDirectory())
+ {
+ String entryName = entry.getName();
+ if (entryName.startsWith(IOConstants.ARCHIVES_DIR))
+ {
+ archivesEntries.add(entry);
+ }
+ else
+ {
+ defaultEntries.add(entry);
+ }
+ }
+ }
+
+ // Import the odf (default + archives workspace)
+ _importODF(odfZipFile, defaultEntries);
+ _importArchives(odfZipFile, archivesEntries);
+ }
+
+ private void _importODF(ZipFile odfZipFile, Set defaultEntries) throws IOException, RepositoryException, SAXException
+ {
+ _importODF(odfZipFile, defaultEntries, false);
+ }
+
+ private void _importArchives(ZipFile odfZipFile, Set archivesEntries) throws IOException, RepositoryException, SAXException
+ {
+ if (archivesEntries.isEmpty())
+ {
+ return;
+ }
+
+ _importODF(odfZipFile, archivesEntries, true);
+ }
+
+ private void _importODF(ZipFile odfZipFile, Set entries, boolean isArchivesWS) throws IOException, RepositoryException, SAXException
+ {
+ String baseEntryName = isArchivesWS ? IOConstants.ARCHIVES_DIR : StringUtils.EMPTY;
+
+ // Configure odf root node import
+ Map odfImporterProperties = new HashMap();
+ Properties props = new Properties();
+ ZipArchiveEntry odfEntry = odfZipFile.getEntry(baseEntryName + IOODFConstants.ODF_FILE_NAME);
+ props.put(ODFRootNodeImporter.INPUT_STREAM_PROPERTY, odfZipFile.getInputStream(odfEntry));
+ odfImporterProperties.put(ODFImporter.ODF_ROOT_NODE_PROPERTIES, props);
+
+ // Configure workflow import
+ props = new Properties();
+ ZipArchiveEntry workflowEntry = odfZipFile.getEntry(baseEntryName + IOConstants.WORKFLOWS_FILE_NAME);
+ props.put(WorkflowImporter.INPUT_STREAM_PROPERTY, odfZipFile.getInputStream(workflowEntry));
+ odfImporterProperties.put(ODFImporter.WORKFLOWS_PROPERTIES, props);
+
+ // Configure binary properties import
+ Collection dataEntries = _getBinaryPropertyEntries(entries);
+ props = _getBinaryDataProperties(odfZipFile, dataEntries);
+ odfImporterProperties.put(ODFImporter.BINARY_PROPERTIES, props);
+
+ // Run the import
+ if (isArchivesWS)
+ {
+ _odfImporter.doImportArchives(odfImporterProperties);
+ }
+ else
+ {
+ _odfImporter.doImport(odfImporterProperties);
+ }
+ }
+
+ private Collection _getBinaryPropertyEntries(Set entries)
+ {
+ // Traverse the collection of entry to filter entries that represent a binary property
+ return CollectionUtils.select(entries, new Predicate()
+ {
+ @Override
+ public boolean evaluate(Object object)
+ {
+ String entryName = ((ZipArchiveEntry) object).getName();
+ return entryName.startsWith(IOConstants.BINARY_DIR);
+ }
+ });
+ }
+
+ /**
+ * Retrieves the Properties
needed to configure the
+ * BinaryPropertyImporter
used in the import.
+ *
+ * @param odfZipFile
+ * @param dataEntries Entries representing a binary property to import.
+ * @return A Properties
object to pass the to odf importer.
+ * @throws IOException
+ * @see BinaryPropertiesImporter
+ */
+ protected Properties _getBinaryDataProperties(ZipFile odfZipFile, Collection dataEntries) throws IOException
+ {
+ List importDataList = new ArrayList();
+
+ // Iterate through all data entries, and populate the import data list.
+ for (ZipArchiveEntry binaryEntry : dataEntries)
+ {
+ String[] splittedEntryName = StringUtils.split(binaryEntry.getName(), '/');
+ int len = splittedEntryName.length;
+ String identifier = splittedEntryName[len - 2];
+ String propertyName = IOUtils.decodeZipEntryName(splittedEntryName[len - 1]);
+
+ importDataList.add(new BinaryPropertiesImporter.ImportData(identifier, propertyName, odfZipFile.getInputStream(binaryEntry)));
+ }
+
+ Properties props = new Properties();
+ props.put(BinaryPropertiesImporter.IMPORT_DATA_LIST_PROPERTY, importDataList);
+
+ return props;
+ }
+}
Index: main/plugin-odf/sitemap.xmap
===================================================================
--- main/plugin-odf/sitemap.xmap (revision 19862)
+++ main/plugin-odf/sitemap.xmap (working copy)
@@ -82,6 +82,9 @@
+
+
+
@@ -108,6 +111,10 @@
+
+
+
+
@@ -252,6 +259,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+