| /******************************************************************************* |
| * Copyright (c) 2005, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jee.archive.internal; |
| |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.jst.jee.archive.AbstractArchiveLoadAdapter; |
| import org.eclipse.jst.jee.archive.ArchiveModelLoadException; |
| import org.eclipse.jst.jee.archive.ArchiveOpenFailureException; |
| import org.eclipse.jst.jee.archive.ArchiveOptions; |
| import org.eclipse.jst.jee.archive.IArchive; |
| import org.eclipse.jst.jee.archive.IArchiveFactory; |
| import org.eclipse.jst.jee.archive.IArchiveLoadAdapter; |
| import org.eclipse.jst.jee.archive.IArchiveResource; |
| import org.eclipse.jst.j2ee.commonarchivecore.internal.CommonArchiveResourceHandler; |
| import org.eclipse.osgi.util.NLS; |
| |
| public class ArchiveImpl extends ArchiveResourceImpl implements IArchive { |
| |
| private ArchiveOptions archiveOptions; |
| |
| private IArchiveLoadAdapter loadAdapter; |
| |
| private class ArchiveFileIndex { |
| private Map<IPath, IArchiveResource> index = new HashMap<IPath, IArchiveResource>(); |
| |
| private List<IArchive> nestedArchives = null; |
| |
| private List<IArchiveResource> fullIndex = null; |
| |
| private boolean fullyIndexed = false; |
| |
| public ArchiveFileIndex() { |
| } |
| |
| public synchronized List<IArchive> getNestedArchives() { |
| if (nestedArchives == null) { |
| nestedArchives = new ArrayList<IArchive>(); |
| } |
| return nestedArchives; |
| } |
| |
| public synchronized boolean containsFile(IPath archiveRelativePath) { |
| AbstractArchiveLoadAdapter.verifyRelative(archiveRelativePath); |
| return index.containsKey(archiveRelativePath); |
| } |
| |
| public synchronized IArchiveResource getFile(IPath archiveRelativePath) { |
| AbstractArchiveLoadAdapter.verifyRelative(archiveRelativePath); |
| IArchiveResource aFile = index.get(archiveRelativePath); |
| return aFile; |
| } |
| |
| public synchronized void noteEmptyFile(IPath archiveRelativePath) { |
| verifyNotFullyIndexed(); |
| AbstractArchiveLoadAdapter.verifyRelative(archiveRelativePath); |
| index.put(archiveRelativePath, null); |
| } |
| |
| public synchronized void addFile(IArchiveResource aFile) { |
| verifyNotFullyIndexed(); |
| AbstractArchiveLoadAdapter.verifyRelative(aFile.getPath()); |
| index.put(aFile.getPath(), aFile); |
| } |
| |
| public synchronized boolean isFullyIndexed() { |
| return fullyIndexed; |
| } |
| |
| public void fullyIndex(List<IArchiveResource> files) { |
| synchronized (this) { |
| if (fullyIndexed) { |
| verifyNotFullyIndexed(); |
| } |
| fullyIndexed = true; |
| } |
| |
| for (IArchiveResource aFile : files) { |
| AbstractArchiveLoadAdapter.verifyRelative(aFile.getPath()); |
| synchronized (this) { |
| if (!index.containsKey(aFile.getPath())) { |
| index.put(aFile.getPath(), aFile); |
| } |
| } |
| } |
| } |
| |
| public synchronized List<IArchiveResource> getFullIndex() { |
| if (!isFullyIndexed()) { |
| throw new RuntimeException("File list has not been fully indexed"); //$NON-NLS-1$ |
| } |
| if (fullIndex == null) { |
| List<IArchiveResource> list = new ArrayList<IArchiveResource>(); |
| list.addAll(index.values()); |
| fullIndex = Collections.unmodifiableList(list); |
| } |
| return fullIndex; |
| } |
| |
| private void verifyNotFullyIndexed() { |
| if (isFullyIndexed()) { |
| throw new RuntimeException("Attempting to modify a fully indexed file list"); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| private ArchiveFileIndex archiveFileIndex = new ArchiveFileIndex(); |
| |
| private FailedToCloseException openendBy = null; |
| |
| public ArchiveImpl(ArchiveOptions archiveOptions) { |
| setType(IArchiveResource.ARCHIVE_TYPE); |
| setArchiveOptions(archiveOptions); |
| loadAdapter = (IArchiveLoadAdapter) getArchiveOptions().getOption(ArchiveOptions.LOAD_ADAPTER); |
| loadAdapter.setArchive(this); |
| openendBy = new FailedToCloseException(); |
| } |
| |
| public boolean isOpen() { |
| return openendBy != null; |
| } |
| |
| public void close() { |
| if(isOpen()){ |
| openendBy = null; |
| for (IArchive nestedArchive : getNestedArchives()) { |
| IArchiveFactory.INSTANCE.closeArchive(nestedArchive); |
| } |
| loadAdapter.close(); |
| dispose(); |
| } |
| } |
| |
| @Override |
| protected void dispose() { |
| super.dispose(); |
| archiveFileIndex = null; |
| loadAdapter = null; |
| archiveFactory = null; |
| archiveOptions = null; |
| } |
| |
| public IArchiveResource getArchiveResource(IPath archiveRelativePath) throws FileNotFoundException { |
| AbstractArchiveLoadAdapter.verifyRelative(archiveRelativePath); |
| IArchiveResource aFile = null; |
| if (archiveFileIndex.containsFile(archiveRelativePath)) { |
| aFile = archiveFileIndex.getFile(archiveRelativePath); |
| } else if (!archiveFileIndex.isFullyIndexed()) { |
| aFile = loadAdapter.getArchiveResource(archiveRelativePath); |
| if (aFile == null) { |
| archiveFileIndex.noteEmptyFile(archiveRelativePath); |
| } else { |
| archiveFileIndex.addFile(aFile); |
| } |
| } |
| if(aFile == null){ |
| throw new FileNotFoundException(NLS.bind(CommonArchiveResourceHandler.ArchiveImpl_0_in_1_, new Object[] { archiveRelativePath.toString(), toString() })); |
| } |
| return aFile; |
| } |
| |
| public List<IArchiveResource> getArchiveResources() { |
| synchronized (this) { |
| if (!archiveFileIndex.isFullyIndexed()) { |
| archiveFileIndex.fullyIndex(loadAdapter.getArchiveResources()); |
| } |
| } |
| return archiveFileIndex.getFullIndex(); |
| } |
| |
| public void setLoadAdapter(IArchiveLoadAdapter loadAdapter) { |
| this.loadAdapter = loadAdapter; |
| } |
| |
| public IArchiveLoadAdapter getLoadAdapter() { |
| return loadAdapter; |
| } |
| |
| protected void setArchiveOptions(ArchiveOptions archiveOptions) { |
| this.archiveOptions = archiveOptions; |
| } |
| |
| public ArchiveOptions getArchiveOptions() { |
| return archiveOptions; |
| } |
| |
| @Override |
| public String toString() { |
| return loadAdapter.toString(); |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| super.finalize(); |
| if (isOpen()) { |
| System.err.println("Archive opener did not close archive: " + this); //$NON-NLS-1$ |
| System.err.println("Archive was opened here:"); //$NON-NLS-1$ |
| openendBy.printStackTrace(System.err); |
| close(); |
| } |
| } |
| |
| public boolean containsModelObject() { |
| return containsModelObject(IArchive.EMPTY_MODEL_PATH); |
| } |
| |
| public boolean containsModelObject(IPath modelObjectPath) { |
| AbstractArchiveLoadAdapter.verifyRelative(modelObjectPath); |
| return getLoadAdapter().containsModelObject(modelObjectPath); |
| } |
| |
| public Object getModelObject() throws ArchiveModelLoadException { |
| return getModelObject(IArchive.EMPTY_MODEL_PATH); |
| } |
| |
| public Object getModelObject(IPath modelObjectPath) throws ArchiveModelLoadException { |
| AbstractArchiveLoadAdapter.verifyRelative(modelObjectPath); |
| return getLoadAdapter().getModelObject(modelObjectPath); |
| } |
| |
| public boolean containsArchiveResource(IPath archiveRelativePath) { |
| AbstractArchiveLoadAdapter.verifyRelative(archiveRelativePath); |
| if (archiveFileIndex.containsFile(archiveRelativePath)) { |
| return true; |
| } else if (!archiveFileIndex.isFullyIndexed()) { |
| return loadAdapter.containsArchiveResource(archiveRelativePath); |
| } |
| return false; |
| } |
| |
| public IArchive getNestedArchive(IArchiveResource archiveResource) throws ArchiveOpenFailureException { |
| try { |
| if (archiveResource.getArchive() != this) { |
| throw new ArchiveOpenFailureException("Attempted to open nested IArchive " + archiveResource.getPath() + " using an IArchiveResource not contained in this IArchive."); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| getArchiveResources(); // need to force the full index to be built now. |
| IArchiveResource cachedArchiveResource = getArchiveResource(archiveResource.getPath()); |
| |
| if (cachedArchiveResource.getType() == IArchiveResource.ARCHIVE_TYPE) { |
| IArchive nestedArchive = (IArchive) cachedArchiveResource; |
| if (!archiveFileIndex.getNestedArchives().contains(nestedArchive)) { |
| archiveFileIndex.getNestedArchives().add(nestedArchive); |
| } |
| return nestedArchive; |
| } else if (cachedArchiveResource.getType() == IArchiveResource.DIRECTORY_TYPE) { |
| throw new ArchiveOpenFailureException("Attempted to open nested IArchive " + cachedArchiveResource.getPath() + " using a directory."); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| IArchiveLoadAdapter nestedLoadAdapter = null; |
| |
| try { |
| java.io.File tempFile = null; |
| try { |
| tempFile = ArchiveUtil.createTempFile(cachedArchiveResource.getPath().toString()); |
| } catch (IOException e) { |
| ArchiveUtil.warn("Warning: Unable to create temp file for " + cachedArchiveResource.getPath() + ". This will impact performance."); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| if (tempFile != null) { |
| InputStream in = cachedArchiveResource.getInputStream(); |
| OutputStream out = new FileOutputStream(tempFile); |
| ArchiveUtil.copy(in, out); |
| nestedLoadAdapter = new TempZipFileArchiveLoadAdapterImpl(tempFile); |
| } |
| } catch (IOException e) { |
| throw new ArchiveOpenFailureException(e); |
| } |
| |
| if (nestedLoadAdapter == null) { |
| // TODO implement a ZipStream reader if necessary |
| } |
| |
| ArchiveOptions nestedArchiveOptions = cloneUnknownOptions(archiveOptions); |
| nestedArchiveOptions.setOption(ArchiveOptions.PARENT_ARCHIVE, this); |
| nestedArchiveOptions.setOption(ArchiveOptions.LOAD_ADAPTER, nestedLoadAdapter); |
| nestedArchiveOptions.setOption(ArchiveOptions.ARCHIVE_PATH, cachedArchiveResource.getPath()); |
| IArchive nestedArchive = archiveFactory.openArchive(nestedArchiveOptions); |
| nestedArchive.setPath(cachedArchiveResource.getPath()); |
| nestedArchive.setArchive(this); |
| return nestedArchive; |
| |
| } catch (FileNotFoundException e) { |
| throw new ArchiveOpenFailureException(e); |
| } |
| } |
| |
| protected ArchiveOptions cloneUnknownOptions(ArchiveOptions archiveOptions){ |
| ArchiveOptions newOptions = new ArchiveOptions(); |
| Iterator iterator = archiveOptions.keySet().iterator(); |
| while(iterator.hasNext()){ |
| Object key = iterator.next(); |
| if(key == ArchiveOptions.ARCHIVE_PATH || key == ArchiveOptions.LOAD_ADAPTER || key == ArchiveOptions.SAVE_ADAPTER){ |
| continue; |
| } else { |
| newOptions.setOption(key, archiveOptions.getOption(key)); |
| } |
| } |
| return newOptions; |
| } |
| |
| |
| public List<IArchive> getNestedArchives() { |
| return Collections.unmodifiableList(archiveFileIndex.getNestedArchives()); |
| } |
| |
| /** |
| * Internal |
| * |
| * @param archiveResource |
| */ |
| void addArchiveResourceInternal(IArchiveResource archiveResource) { |
| archiveFileIndex.index.put(archiveResource.getPath(), archiveResource); |
| if(archiveResource.getType() == ARCHIVE_TYPE){ |
| archiveFileIndex.getNestedArchives().add((IArchive)archiveResource); |
| } |
| archiveFileIndex.fullIndex = null; |
| } |
| |
| protected IArchiveFactory archiveFactory; |
| /** |
| * Internal; clients should not call. |
| * @param archiveFactory |
| */ |
| public void setArchiveFactory(IArchiveFactory archiveFactory){ |
| this.archiveFactory = archiveFactory; |
| } |
| |
| } |