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 @@ + + + + + + + + + + + + + + + + + + + +