
org.xmind.core.internal.dom.WorkbookLoader 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.zip.ArchiveConstants.MANIFEST_XML;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;
import org.w3c.dom.Document;
import org.xmind.core.Core;
import org.xmind.core.CoreException;
import org.xmind.core.IChecksumStream;
import org.xmind.core.IEncryptionData;
import org.xmind.core.IEncryptionHandler;
import org.xmind.core.IFileEntry;
import org.xmind.core.IManifest;
import org.xmind.core.IRevision;
import org.xmind.core.ISheet;
import org.xmind.core.IWorkbook;
import org.xmind.core.internal.compatibility.Compatibility;
import org.xmind.core.internal.security.Crypto;
import org.xmind.core.internal.zip.ArchiveConstants;
import org.xmind.core.io.IInputSource;
import org.xmind.core.io.IOutputTarget;
import org.xmind.core.io.IStorage;
import org.xmind.core.marker.IMarkerSheet;
import org.xmind.core.style.IStyleSheet;
/**
* @author frankshaka
*
*/
public class WorkbookLoader extends XMLLoader {
/**
*
*/
private WorkbookBuilderImpl builder;
/**
*
*/
private IInputSource source;
/**
*
*/
private IStorage storage;
/**
*
*/
private IEncryptionHandler encryptionHandler;
/**
*
*/
private WorkbookImpl workbook = null;
/**
*
*/
private Set loadedEntries = new HashSet();
/**
*
*/
private ManifestImpl manifest = null;
/**
*
*/
private boolean ignoreCopy;
/**
*
*/
private String password = null;
/**
* Byte buffer for transfering entries.
*/
private byte[] byteBuffer = new byte[4096];
/**
*
* @param builder
* @param source
* @param storage
* @param encryptionHandler
*/
public WorkbookLoader(WorkbookBuilderImpl builder, IInputSource source,
IStorage storage, IEncryptionHandler encryptionHandler)
throws CoreException {
super();
this.builder = builder;
if (source == null && storage != null) {
source = storage.getInputSource();
this.ignoreCopy = true;
} else {
this.ignoreCopy = false;
}
this.source = source;
this.storage = storage;
this.encryptionHandler = encryptionHandler;
}
public IWorkbook load() throws IOException, CoreException {
password = null;
manifest = null;
try {
doLoad();
} finally {
manifest = null;
password = null;
}
return workbook;
}
/**
* The main loading process.
*
* @throws java.io.IOException
* @throws CoreException
*/
private void doLoad() throws IOException, CoreException {
loadManifest();
if (loadOldFormat())
return;
loadContents();
loadMeta();
loadStyleSheet();
loadMarkerSheet();
copyOtherStaff();
initWorkbook();
clearEncryptionData();
}
private void loadManifest() throws IOException, CoreException {
Document doc = forceLoadXML(MANIFEST_XML);
this.manifest = new ManifestImpl(doc);
}
private boolean loadOldFormat() throws IOException, CoreException {
IWorkbook compatible = Compatibility.loadCompatibleWorkbook(source,
this, storage);
if (compatible != null) {
workbook = (WorkbookImpl) compatible;
return true;
}
return false;
}
private void loadContents() throws IOException, CoreException {
Document doc = loadXMLFile(source, ArchiveConstants.CONTENT_XML);
workbook = new WorkbookImpl(doc);
workbook.setManifest(manifest);
}
private void loadMeta() throws IOException, CoreException {
Document doc = forceLoadXML(ArchiveConstants.META_XML);
workbook.setMeta(new MetaImpl(doc));
}
private void loadStyleSheet() throws IOException, CoreException {
try {
IStyleSheet styleSheet = ((StyleSheetBuilderImpl) Core
.getStyleSheetBuilder()).loadFromInputSource(source, this);
((StyleSheetImpl) styleSheet).setManifest(manifest);
workbook.setStyleSheet((StyleSheetImpl) styleSheet);
} catch (IOException e) {
throw e;
} catch (CoreException e) {
if (e.getType() != Core.ERROR_NO_SUCH_ENTRY)
throw e;
}
}
private void loadMarkerSheet() throws IOException, CoreException {
try {
IMarkerSheet markerSheet = ((MarkerSheetBuilderImpl) Core
.getMarkerSheetBuilder()).loadFromInputSource(source, this,
new WorkbookMarkerResourceProvider(workbook));
workbook.setMarkerSheet((MarkerSheetImpl) markerSheet);
} catch (IOException e) {
throw e;
} catch (CoreException e) {
if (e.getType() != Core.ERROR_NO_SUCH_ENTRY)
throw e;
}
}
private void copyOtherStaff() throws IOException, CoreException {
if (ignoreCopy || source == null || storage == null)
return;
if (!source.equals(storage.getInputSource())) {
IOutputTarget target = storage.getOutputTarget();
IManifest manifest = workbook.getManifest();
for (IFileEntry entry : manifest.getFileEntries()) {
if (!entry.isDirectory()) {
String entryPath = entry.getPath();
if (shouldLoadEntry(entryPath)) {
copyEntry(source, target, entryPath);
markLoaded(entryPath);
}
}
}
} else {
// Prefetch all file entries:
workbook.getManifest().getFileEntries();
}
}
private boolean shouldLoadEntry(String entryPath) {
return entryPath != null && !"".equals(entryPath) //$NON-NLS-1$
&& !hasBeenLoaded(entryPath);
}
private void copyEntry(IInputSource source, IOutputTarget target,
String entryPath) throws IOException, CoreException {
InputStream in = getInputStream(source, entryPath);
if (in == null)
return;
try {
long time = source.getEntryTime(entryPath);
if (time >= 0)
target.setEntryTime(entryPath, time);
OutputStream out = getOutputStream(target, entryPath);
try {
int numBytes;
while ((numBytes = in.read(byteBuffer)) > 0) {
out.write(byteBuffer, 0, numBytes);
}
if (!verifyChecksum(source, entryPath, in))
throw new CoreException(Core.ERROR_WRONG_PASSWORD);
} finally {
out.close();
}
} finally {
in.close();
}
}
private OutputStream getOutputStream(IOutputTarget target, String entryPath)
throws IOException {
if (!target.isEntryAvaialble(entryPath))
return null;
return target.openEntryStream(entryPath);
}
private void markLoaded(String entryPath) {
loadedEntries.add(entryPath);
}
private boolean hasBeenLoaded(String entryPath) {
return loadedEntries.contains(entryPath);
}
private void initWorkbook() throws IOException, CoreException {
if (storage != null) {
workbook.setTempStorage(storage);
}
initWorkbookContents(workbook);
workbook.setPassword(password);
}
private void initWorkbookContents(WorkbookImpl workbook) {
for (ISheet s : workbook.getSheets()) {
initSheet(s, workbook);
}
}
private void initSheet(ISheet sheet, WorkbookImpl wb) {
((SheetImpl) sheet).addNotify(wb);
// Prefetch all revisions of this sheet.
workbook.getRevisionRepository().getRevisionManager(sheet.getId(),
IRevision.SHEET);
}
private void clearEncryptionData() {
for (IFileEntry entry : manifest.getFileEntries()) {
entry.deleteEncryptionData();
}
}
private Document forceLoadXML(String entryPath) throws IOException,
CoreException {
try {
return loadXMLFile(source, entryPath);
} catch (Throwable e) {
if (e instanceof CoreException) {
CoreException coreEx = (CoreException) e;
if (coreEx.getType() == Core.ERROR_WRONG_PASSWORD
|| coreEx.getType() == Core.ERROR_CANCELLATION) {
throw coreEx;
}
}
//in case the file is damaged,
//try continue loading
Core.getLogger().log(e, "Faild to load " + entryPath); //$NON-NLS-1$
return createDocument();
}
}
private InputStream getInputStream(IInputSource source, String entryPath)
throws CoreException {
if (!source.hasEntry(entryPath))
return null;
InputStream in = source.getEntryStream(entryPath);
if (in == null)
return null;
if (manifest != null) {
IEncryptionData encData = manifest.getEncryptionData(entryPath);
if (encData != null) {
in = createDecryptedStream(in, encData);
}
}
return in;
}
private InputStream createDecryptedStream(InputStream in,
IEncryptionData encData) throws CoreException {
String password = getPassword();
if (password == null)
throw new CoreException(Core.ERROR_CANCELLATION);
return Crypto.createInputStream(in, false, encData, password);
}
private String getPassword() throws CoreException {
if (password == null) {
if (encryptionHandler != null) {
password = encryptionHandler.retrievePassword();
}
}
return password;
}
/*
* (non-Javadoc)
*
* @see
* org.xmind.core.internal.dom.XMLLoader#doLoadXMLFile(org.xmind.core.io
* .IInputSource, java.lang.String)
*/
protected Document doLoadXMLFile(IInputSource source, String entryPath)
throws IOException, CoreException {
InputStream stream = getInputStream(source, entryPath);
if (stream == null)
throw new CoreException(Core.ERROR_NO_SUCH_ENTRY, entryPath);
Document doc;
try {
doc = builder.getDocumentLoader().parse(stream);
} catch (Throwable error) {
if (!verifyChecksum(source, entryPath, stream))
throw new CoreException(Core.ERROR_WRONG_PASSWORD, error);
if (error instanceof IOException)
throw (IOException) error;
if (error instanceof CoreException)
throw (CoreException) error;
throw new CoreException(Core.ERROR_FAIL_PARSING_XML, error);
} finally {
stream.close();
}
if (!verifyChecksum(source, entryPath, stream))
throw new CoreException(Core.ERROR_WRONG_PASSWORD);
markLoaded(entryPath);
return doc;
}
private boolean verifyChecksum(IInputSource source, String entryName,
InputStream stream) throws IOException, CoreException {
if (stream instanceof IChecksumStream) {
if (manifest == null) {
throw new IllegalStateException(
"Manifest should not be encrypted"); //$NON-NLS-1$
}
IEncryptionData encData = manifest.getEncryptionData(entryName);
if (encData != null) {
String expectedChecksum = encData.getChecksum();
if (expectedChecksum != null) {
String actualChecksum;
actualChecksum = ((IChecksumStream) stream).getChecksum();
if (actualChecksum == null
|| !expectedChecksum.equals(actualChecksum)) {
return false;
}
}
}
}
return true;
}
public Document createDocument() {
return builder.createDocument();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy