
org.xmind.core.internal.dom.WorkbookSaver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xmindjbehaveplugin Show documentation
Show all versions of xmindjbehaveplugin Show documentation
Plugin that manages JBehave stories storage in XMind mindmap file, which allows design jBehave tests right after the brainstorm
The newest version!
/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.core.internal.dom;
import static org.xmind.core.internal.dom.DOMConstants.ATTR_ID;
import static org.xmind.core.internal.dom.DOMConstants.TAG_SHEET;
import static org.xmind.core.internal.zip.ArchiveConstants.CONTENT_XML;
import static org.xmind.core.internal.zip.ArchiveConstants.MANIFEST_XML;
import static org.xmind.core.internal.zip.ArchiveConstants.META_XML;
import static org.xmind.core.internal.zip.ArchiveConstants.PATH_MARKER_SHEET;
import static org.xmind.core.internal.zip.ArchiveConstants.PATH_REVISIONS;
import static org.xmind.core.internal.zip.ArchiveConstants.REVISIONS_XML;
import static org.xmind.core.internal.zip.ArchiveConstants.STYLES_XML;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.zip.ZipOutputStream;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xmind.core.Core;
import org.xmind.core.CoreException;
import org.xmind.core.IAdaptable;
import org.xmind.core.IChecksumStream;
import org.xmind.core.IEncryptionData;
import org.xmind.core.IFileEntry;
import org.xmind.core.IManifest;
import org.xmind.core.IRevision;
import org.xmind.core.IRevisionManager;
import org.xmind.core.internal.InternalCore;
import org.xmind.core.internal.security.Crypto;
import org.xmind.core.internal.zip.ArchiveConstants;
import org.xmind.core.internal.zip.ZipStreamOutputTarget;
import org.xmind.core.io.DirectoryOutputTarget;
import org.xmind.core.io.ICloseableOutputTarget;
import org.xmind.core.io.IInputSource;
import org.xmind.core.io.IOutputTarget;
import org.xmind.core.marker.IMarkerSheet;
import org.xmind.core.style.IStyleSheet;
import org.xmind.core.util.DOMUtils;
/**
* @author Frank Shaka
*
*/
public class WorkbookSaver {
private static class WorkbookSaveSession {
/**
* The workbook to save.
*/
private final WorkbookImpl workbook;
/**
* The multi-entry output target to save to.
*/
private final IOutputTarget target;
/**
* Entry paths that have been saved.
*/
private Set savedEntries = new HashSet();
/**
* DOM transformer factory, lazy created.
*/
private TransformerFactory transformerFactory = null;
/**
* Constructs a new WorkbookSaveSession.
*
* @param workbook
* @param target
*/
public WorkbookSaveSession(WorkbookImpl workbook, IOutputTarget target) {
this.workbook = workbook;
this.target = target;
}
/**
* The main saving process.
*
* @throws java.io.IOException
* @throws CoreException
*/
public synchronized void save() throws IOException, CoreException {
try {
try {
saveMeta();
saveContent();
saveMarkerSheet();
saveStyleSheet();
if (!workbook.isSkipRevisionsWhenSaving()) {
saveRevisions();
}
copyOtherStaff();
saveManifest();
} finally {
clearEncryptionData();
}
} finally {
if (target instanceof ICloseableOutputTarget) {
((ICloseableOutputTarget) target).close();
}
}
}
private void saveManifest() throws IOException, CoreException {
saveDOM(workbook.getManifest(), target, MANIFEST_XML);
}
private void saveStyleSheet() throws IOException, CoreException {
IStyleSheet styleSheet = workbook.getStyleSheet();
if (!styleSheet.isEmpty()) {
saveDOM(styleSheet, target, STYLES_XML);
}
}
private void saveMarkerSheet() throws IOException, CoreException {
IMarkerSheet markerSheet = workbook.getMarkerSheet();
if (!markerSheet.isEmpty()) {
saveDOM(markerSheet, target, PATH_MARKER_SHEET);
}
}
private void saveRevisions() throws IOException, CoreException {
Iterator sheets = DOMUtils.childElementIterByTag(
workbook.getWorkbookElement(), TAG_SHEET);
while (sheets.hasNext()) {
Element sheetEle = sheets.next();
String sheetId = sheetEle.getAttribute(ATTR_ID);
IRevisionManager manager = workbook.getRevisionRepository()
.getRevisionManager(sheetId, IRevision.SHEET);
String path = PATH_REVISIONS + sheetId + "/" + REVISIONS_XML; //$NON-NLS-1$
saveDOM(manager, target, path);
}
}
private void saveContent() throws IOException, CoreException {
saveDOM(workbook, target, CONTENT_XML);
}
private void saveMeta() throws IOException, CoreException {
saveDOM(workbook.getMeta(), target, META_XML);
}
private void copyOtherStaff() throws IOException, CoreException {
IInputSource source = workbook.getTempStorage().getInputSource();
IManifest manifest = workbook.getManifest();
for (IFileEntry entry : manifest.getFileEntries()) {
if (!entry.isDirectory()) {
String entryPath = entry.getPath();
if (shouldSaveEntry(entryPath)) {
copyEntry(source, target, entryPath);
markSaved(entryPath);
}
}
}
}
private synchronized void copyEntry(IInputSource source,
IOutputTarget target, String entryPath) throws IOException,
CoreException {
InputStream in = getInputStream(source, entryPath);
if (in == null) {
Core.getLogger().log(
"Save workbook: failed to copy entry, input stream not avaiable: " //$NON-NLS-1$
+ entryPath);
return; // Entry source not found.
}
try {
long time = source.getEntryTime(entryPath);
if (time >= 0) {
target.setEntryTime(entryPath, time);
}
OutputStream out = getOutputStream(target, entryPath);
try {
int numBytes;
byte[] byteBuffer = new byte[4096];
while ((numBytes = in.read(byteBuffer)) > 0) {
out.write(byteBuffer, 0, numBytes);
}
recordChecksum(entryPath, out);
} finally {
out.close();
}
} finally {
in.close();
}
}
private boolean shouldSaveEntry(String entryPath) {
return entryPath != null
&& !"".equals(entryPath) //$NON-NLS-1$
&& !MANIFEST_XML.equals(entryPath)
&& !hasBeenSaved(entryPath)
&& !(workbook.isSkipRevisionsWhenSaving() && entryPath
.startsWith(ArchiveConstants.PATH_REVISIONS));
}
private void clearEncryptionData() {
for (IFileEntry entry : workbook.getManifest().getFileEntries()) {
entry.deleteEncryptionData();
}
}
private void saveDOM(IAdaptable domAdapter, IOutputTarget target,
String entryPath) throws IOException, CoreException {
Node node = (Node) domAdapter.getAdapter(Node.class);
if (node == null) {
Core.getLogger().log(
"SaveWorkbook: No DOM node available for entry: " //$NON-NLS-1$
+ entryPath);
return;
}
if (transformerFactory == null) {
try {
transformerFactory = TransformerFactory.newInstance();
} catch (TransformerFactoryConfigurationError error) {
throw new CoreException(
Core.ERROR_FAIL_ACCESS_XML_TRANSFORMER,
"Failed to obtain XML transformer factory.", error); //$NON-NLS-1$
}
}
Transformer transformer;
try {
transformer = transformerFactory.newTransformer();
} catch (TransformerConfigurationException error) {
throw new CoreException(Core.ERROR_FAIL_ACCESS_XML_TRANSFORMER,
"Failed to create XML transformer for DOM entry '" //$NON-NLS-1$
+ entryPath + "'.", error); //$NON-NLS-1$
}
OutputStream out = getOutputStream(target, entryPath);
try {
transformer.transform(new DOMSource(node),
new StreamResult(out));
} catch (TransformerException e) {
throw new IOException(e.getLocalizedMessage(), e);
} finally {
out.close();
}
recordChecksum(entryPath, out);
markSaved(entryPath);
}
private void recordChecksum(String entryPath, Object checksumProvider)
throws IOException {
if (checksumProvider instanceof IChecksumStream) {
IEncryptionData encData = workbook.getManifest()
.getEncryptionData(entryPath);
if (encData != null && encData.getChecksumType() != null) {
String checksum = ((IChecksumStream) checksumProvider)
.getChecksum();
if (checksum != null) {
encData.setAttribute(checksum,
DOMConstants.ATTR_CHECKSUM);
}
}
}
}
private InputStream getInputStream(IInputSource source, String entryPath) {
if (source.hasEntry(entryPath)) {
return source.getEntryStream(entryPath);
}
return null;
}
private OutputStream getOutputStream(IOutputTarget target,
String entryPath) throws IOException, CoreException {
OutputStream out = target.openEntryStream(entryPath);
String password = workbook.getPassword();
if (password == null)
return out;
IFileEntry entry = workbook.getManifest().getFileEntry(entryPath);
if (entry == null)
return out;
if (ignoresEncryption(entry, entryPath))
return out;
IEncryptionData encData = entry.createEncryptionData();
return Crypto.creatOutputStream(out, true, encData, password);
}
private boolean ignoresEncryption(IFileEntry entry, String entryPath) {
return MANIFEST_XML.equals(entryPath)
|| ((FileEntryImpl) entry).isIgnoreEncryption();
}
private boolean hasBeenSaved(String entryPath) {
return savedEntries.contains(entryPath);
}
private void markSaved(String entryPath) {
savedEntries.add(entryPath);
}
}
/**
* The workbook to save.
*/
private final WorkbookImpl workbook;
/**
* The last target saved to.
*/
private IOutputTarget lastTarget;
/**
* (Optional) The absolute path representing a ZIP file target
*/
private String file;
/**
* Whether to skip revisions when saving.
*/
private boolean skipRevisions = false;
/**
* @param workbook
* @param file
*/
public WorkbookSaver(WorkbookImpl workbook, String file) {
super();
this.workbook = workbook;
this.file = file;
}
/**
* @return the file path
*/
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
/**
* @param skipRevisions
* the skipRevisions to set
*/
public void setSkipRevisions(boolean skipRevisions) {
this.skipRevisions = skipRevisions;
}
public boolean isSkipRevisions() {
return skipRevisions;
}
/**
*
* @throws java.io.IOException
* @throws CoreException
*/
public synchronized void save() throws IOException, CoreException {
doSave(this.lastTarget);
}
/**
*
* @param output
* @throws java.io.IOException
* @throws CoreException
*/
public synchronized void save(OutputStream output) throws IOException,
CoreException {
doSave(new ZipStreamOutputTarget(new ZipOutputStream(output)));
}
public synchronized void save(String file) throws IOException,
CoreException {
if (new File(file).isDirectory()) {
doSave(new DirectoryOutputTarget(file));
} else {
FileOutputStream fout = new FileOutputStream(file);
try {
ZipOutputStream stream = new ZipOutputStream(fout);
try {
doSave(new ZipStreamOutputTarget(stream));
} finally {
stream.close();
}
} finally {
fout.close();
}
}
this.file = file;
}
public synchronized void save(IOutputTarget target) throws IOException,
CoreException {
doSave(target);
this.lastTarget = target;
}
/**
*
* @param target
* @throws java.io.IOException
* @throws CoreException
*/
private synchronized void doSave(IOutputTarget target) throws IOException,
CoreException {
if (target == null)
throw new FileNotFoundException("No target to save."); //$NON-NLS-1$
if (InternalCore.DEBUG_WORKBOOK_SAVE)
Core.getLogger().log(
"WorkbookSaver: About to save workbook to output target " //$NON-NLS-1$
+ target.toString());
new WorkbookSaveSession(workbook, target).save();
if (InternalCore.DEBUG_WORKBOOK_SAVE)
Core.getLogger().log(
"WorkbookSaver: Finished saving workbook to output target " //$NON-NLS-1$
+ target.toString());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy