/*******************************************************************************
* Copyright (c) 2006, 2010 Spring IDE Developers
* 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:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.core.io;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.springframework.ide.eclipse.core.SpringCore;
import org.springframework.ide.eclipse.core.model.IResourceModelElement;
import org.springframework.util.ObjectUtils;
/**
* Wrapper for an entry in a ZIP file.
* @author Torsten Juergeleit
* @author Christian Dupuis
*/
public class ZipEntryStorage implements IStorage, IAdaptable {
/**
* This string (with the value of "!") is used to delimit the ZIP file name from the corresponding ZIP entry
*/
public static final String DELIMITER = "!";
private String fullName;
private IFile file;
private String entryName;
private IPath entryPath;
private IResourceModelElement parentModelElement;
/**
* Creates a <code>ZipEntryStorage</code> from a full-qualified name of a ZIP file entry (project-relative path to
* the ZIP file plus full path of the ZIP file entry delimited by <code>DELIMITER</code>) and the project which
* contains the ZIP file.
* @param project the project which contains the ZIP file
* @param fullName the full-qualified name of the ZIP file entry (project-relative path to the ZIP file plus full
* path of the ZIP file entry delimited by <code>DELIMITER</code>)
*/
public ZipEntryStorage(IProject project, String fullName) {
int pos = fullName.indexOf(ZipEntryStorage.DELIMITER);
if (pos == -1 || pos == (fullName.length() - DELIMITER.length())) {
throw new IllegalArgumentException("Illegal JAR entry name '" + fullName + "'");
}
else {
IResource member = project.findMember(fullName.substring(0, pos));
if (member == null || !(member instanceof IFile)) {
throw new IllegalArgumentException("Missing or wrong zip file: " + file);
}
this.fullName = fullName;
this.file = (IFile) member;
this.entryName = fullName.substring(pos + DELIMITER.length());
this.entryPath = new Path(this.entryName);
}
}
/**
* Creates a <code>ZipEntryStorage</code> from a full path of a ZIP file entry and the corresponding ZIP file.
* @param file the ZIP file
* @param entryName the full path of the ZIP file entry
*/
public ZipEntryStorage(IFile file, String entryName) {
if (file == null || !file.exists()) {
throw new IllegalArgumentException("Missing or wrong zip file: " + file);
}
this.fullName = file.getProjectRelativePath() + DELIMITER + entryName;
this.file = file;
this.entryName = entryName;
this.entryPath = new Path(entryName);
}
/**
* Creates a <code>ZipEntryStorage</code> from a given archived model element.
* @param element the archived model element
*/
public ZipEntryStorage(IResourceModelElement element) {
if (element == null || !element.isElementArchived() || !(element.getElementResource() instanceof IFile)) {
throw new IllegalArgumentException("Missing or wrong model element: " + element);
}
this.fullName = element.getElementName();
this.file = (IFile) element.getElementResource();
this.entryName = fullName.substring(fullName.indexOf(DELIMITER) + DELIMITER.length());
this.entryPath = new Path(entryName);
this.parentModelElement = element;
}
/**
* Returns the ZIP file resource of this ZIP file entry.
*/
public IFile getFile() {
return file;
}
public InputStream getContents() throws CoreException {
try {
ZipFile file = new ZipFile(this.file.getLocation().toFile());
String cleanedEntryName = entryName;
if (cleanedEntryName.length() > 1 && cleanedEntryName.charAt(0) == '/') {
cleanedEntryName = cleanedEntryName.substring(1);
}
ZipEntry entry = file.getEntry(cleanedEntryName);
if (entry == null) {
throw new CoreException(SpringCore.createErrorStatus("Invalid path '" + cleanedEntryName + "'", null));
}
return InputStreamUtils.getWrappedInputStream(file, entry);
}
catch (IOException e) {
throw new CoreException(SpringCore.createErrorStatus(e.getMessage(), e));
}
}
/**
* Returns the full path of the ZIP file entry.
*/
public IPath getFullPath() {
return entryPath;
}
public String getName() {
return entryPath.lastSegment();
}
/**
* Returns the full-qualified name of the ZIP file entry (project-relative path to the ZIP file plus full path of
* the ZIP file entry delimited by <code>DELIMITER</code>).
*/
public String getFullName() {
return fullName;
}
/**
* Returns the name of the entry within the Zip file
* @since 2.0.3
*/
public String getEntryName() {
return entryName;
}
/**
* Returns the full-qualified name of the ZIP file entry (workspace-relative path to the ZIP file plus full path of
* the ZIP file entry delimited by <code>DELIMITER</code>).
*/
public String getAbsoluteName() {
return file.getProject().getFullPath().append(fullName).toString();
}
/**
* Returns <code>true</code> because the ZIP file entry is not modifiable.
*/
public boolean isReadOnly() {
return true;
}
/**
* Adapts to {@link IFile}, {@link File} or {@link ZipFile}.
*/
public Object getAdapter(Class adapter) {
if (file != null) {
if (adapter.equals(IFile.class)) {
return file;
}
else if (adapter.equals(File.class)) {
return file.getFullPath().toFile();
}
else if (adapter.equals(ZipFile.class)) {
try {
return new ZipFile(file.getFullPath().toFile());
}
catch (IOException e) {
SpringCore.log(e);
}
}
}
if (IResourceModelElement.class.equals(adapter)) {
return this.parentModelElement;
}
return null;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ZipEntryStorage)) {
return false;
}
ZipEntryStorage that = (ZipEntryStorage) other;
if (!ObjectUtils.nullSafeEquals(this.fullName, that.fullName))
return false;
return ObjectUtils.nullSafeEquals(this.file, that.file);
}
@Override
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(fullName);
return 29 * hashCode + ObjectUtils.nullSafeHashCode(file);
}
@Override
public String toString() {
return "ZipEntryStorage[" + file.toString() + " - " + entryPath + "]";
}
}