blob: ed601cd9cbd22f0b45365f4ac084388ffcc2b738 [file] [log] [blame]
/*******************************************************************************
* 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;
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(archiveRelativePath.toString() +" in "+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;
}
public String toString() {
return loadAdapter.toString();
}
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$
}
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;
}
}