package org.xmind.core.internal.dom; import static org.xmind.core.internal.zip.ArchiveConstants.PATH_REVISIONS; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xmind.core.Core; import org.xmind.core.IFileEntry; import org.xmind.core.IFileEntryFilter; import org.xmind.core.IManifest; import org.xmind.core.IRevisionManager; import org.xmind.core.IWorkbook; import org.xmind.core.internal.RevisionRepository; import org.xmind.core.internal.zip.ArchiveConstants; import org.xmind.core.util.DOMUtils; public class RevisionRepositoryImpl extends RevisionRepository { private static final Pattern REVISIONS_RESOURCE_DIR = Pattern .compile("Revisions/([^/]+)/"); //$NON-NLS-1$ private WorkbookImpl ownedWorkbook; private Map<String, RevisionManagerImpl> managers = new HashMap<String, RevisionManagerImpl>(); public RevisionRepositoryImpl(WorkbookImpl ownedWorkbook) { this.ownedWorkbook = ownedWorkbook; } public IRevisionManager getRevisionManager(String resourceId, String contentType) { if (resourceId == null) throw new IllegalArgumentException("Resource id is null"); //$NON-NLS-1$ return doGetRevisionManager(resourceId, contentType, true); } public IRevisionManager getRegisteredRevisionManager(String resourceId) { if (resourceId == null) throw new IllegalArgumentException("Resource id is null"); //$NON-NLS-1$ return doGetRevisionManager(resourceId, null, false); } private RevisionManagerImpl doGetRevisionManager(String resourceId, String contentType, boolean createIfNotFound) { RevisionManagerImpl manager = managers.get(resourceId); if (manager == null) { manager = loadRevisionManager(resourceId, contentType, createIfNotFound); if (manager != null) { manager.addNotify(ownedWorkbook); managers.put(resourceId, manager); } } return manager; } private RevisionManagerImpl loadRevisionManager(String resourceId, String contentType, boolean createIfNotFound) { String dirPath = PATH_REVISIONS + resourceId + "/"; //$NON-NLS-1$ String metaPath = dirPath + ArchiveConstants.REVISIONS_XML; IManifest manifest = ownedWorkbook.getManifest(); IFileEntry metaEntry = manifest.getFileEntry(metaPath); if (metaEntry != null) { RevisionManagerImpl manager = loadRevisionManager(resourceId, metaEntry, dirPath); if (manager != null) return manager; } if (!createIfNotFound) return null; Document doc = DOMUtils.createDocument(); Element ele = DOMUtils.createElement(doc, DOMConstants.TAG_REVISIONS); ele.setAttribute(DOMConstants.ATTR_RESOURCE_ID, resourceId); ele.setAttribute(DOMConstants.ATTR_MEDIA_TYPE, contentType); ele.setAttribute(DOMConstants.ATTR_NEXT_REVISION_NUMBER, "1"); //$NON-NLS-1$ manifest.createFileEntry(metaPath); return new RevisionManagerImpl(doc, ownedWorkbook, dirPath); } private RevisionManagerImpl loadRevisionManager(String resourceId, IFileEntry metaEntry, String path) { InputStream stream; try { stream = metaEntry.openInputStream(); } catch (IOException e) { Core.getLogger().log(e, "Failed to load document at " + metaEntry.getPath()); //$NON-NLS-1$ return null; } if (stream == null) return null; try { Document doc = DOMUtils.loadDocument(stream); return new RevisionManagerImpl(doc, ownedWorkbook, path); } catch (Throwable e) { Core.getLogger().log(e, "Failed to load document at " + metaEntry.getPath()); //$NON-NLS-1$ } return null; } public void setRevisionManager(String resourceId, IRevisionManager manager) { if (resourceId == null) throw new IllegalArgumentException("Resource id is null"); //$NON-NLS-1$ if (manager != null && !(manager instanceof RevisionManagerImpl)) throw new IllegalArgumentException( "Invalid type of revision manager"); //$NON-NLS-1$ if (manager != null && manager.getOwnedWorkbook() != getOwnedWorkbook()) throw new IllegalArgumentException( "Revision manager owned by another workbook"); //$NON-NLS-1$ RevisionManagerImpl newManager = (RevisionManagerImpl) manager; RevisionManagerImpl oldManager = doGetRevisionManager(resourceId, null, false); if (oldManager == newManager) return; if (oldManager != null) { oldManager.removeNotify(ownedWorkbook); managers.remove(oldManager); } if (newManager != null) { managers.put(resourceId, newManager); newManager.addNotify(ownedWorkbook); } } public Set<String> getRegisteredResourceIds() { Set<String> resourceIds = new HashSet<String>(); Iterator<IFileEntry> entryIter = ownedWorkbook.getManifest() .iterFileEntries(new IFileEntryFilter() { public boolean select(String path, String mediaType, boolean isDirectory) { return REVISIONS_RESOURCE_DIR.matcher(path).matches(); } }); while (entryIter.hasNext()) { IFileEntry entry = entryIter.next(); String path = entry.getPath(); Matcher m = REVISIONS_RESOURCE_DIR.matcher(path); if (m.matches()) { String resourceId = m.group(1); resourceIds.add(resourceId); } } return resourceIds; } public IWorkbook getOwnedWorkbook() { return ownedWorkbook; } public boolean isOrphan() { return false; } }