/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.vdb;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collection;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import net.jcip.annotations.ThreadSafe;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.teiid.core.designer.util.StringConstants;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.util.VdbHelper.VdbFolders;
import org.teiid.designer.core.workspace.WorkspaceResourceFinderUtil;
import org.teiid.designer.vdb.manifest.EntryElement;
/**
* VdbFileEntry - represents VDB file entries, either UDF jars or otherFiles
*
* @since 8.0
*/
@ThreadSafe
public final class VdbFileEntry extends VdbEntry {
private IPath sourceFilePath;
private FileEntryType fileType;
/**
* Enumerates different fileTypes in the VDB (Udf jars, user files)
*/
public enum FileEntryType {
/**
* User File Entry
*/
UserFile,
/**
* UDF jar Entry
*/
UDFJar;
}
/**
* Constructs a file entry and adds it to the specified VDB.
*
* @param vdb the VDB where the resource is be added to (may not be <code>null</code>)
* @param sourcePath the resource path (may not be <code>null</code>)
* @param entryType the type of FileEntry
* @throws Exception
*/
public VdbFileEntry( final Vdb vdb,
final IPath sourcePath,
final FileEntryType entryType) throws Exception {
super(vdb, sourcePath);
this.sourceFilePath = sourcePath;
this.fileType = entryType;
// // Reset the path since this is not a workspace file
resetPath();
}
/**
* Constructs a file entry and adds it to the specified VDB.
*
* @param vdb the VDB where the resource is be added to (may not be <code>null</code>)
* @param element the EntryElement
* @throws Exception
*/
public VdbFileEntry( final Vdb vdb,
final EntryElement element) throws Exception {
super(vdb, Path.fromPortableString(element.getPath()));
this.sourceFilePath = Path.fromPortableString(element.getPath());
if(element.getPath().startsWith(StringConstants.FORWARD_SLASH + VdbFolders.UDF.getReadFolder())) {
this.fileType = FileEntryType.UDFJar;
} else {
this.fileType = FileEntryType.UserFile;
}
// Reset the path since this is not a workspace file
resetPath();
}
private void resetPath() throws Exception {
if (sourceFilePath == null)
return;
String fileName = this.sourceFilePath.lastSegment();
IPath newPath;
if(this.fileType == FileEntryType.UDFJar)
newPath = new Path(StringConstants.FORWARD_SLASH + VdbFolders.UDF.getWriteFolder() + StringConstants.FORWARD_SLASH + fileName);
else
newPath = new Path(StringConstants.FORWARD_SLASH + VdbFolders.OTHER_FILES.getWriteFolder() + StringConstants.FORWARD_SLASH + fileName);
setPath(newPath);
// Need to re-synchronize due to changing the path
setSynchronization(Synchronization.NotSynchronized);
synchronize();
}
/**
* @return source file path
*/
public IPath getSourceFilePath() {
return sourceFilePath;
}
/**
* Called via {@link VdbEntry} constructor when {@link #sourceFilePath}
* has not been initialised. So override to avoid the synchronisation until
* {@link #resetPath()} has been called in our constructor.
*/
@Override
protected Synchronization synchronizeEntry() throws Exception {
if (sourceFilePath == null)
return Synchronization.NotApplicable;
return super.synchronizeEntry();
}
/**
* @return the associated workspace file, or <code>null</code> if it doesn't exist
*/
@Override
public IFile findFileInWorkspace() {
IResource resource = ModelerCore.getWorkspace().getRoot().findMember(getSourceFilePath());
if (resource == null) {
// Lets try a little harder since the file may be in the project but not a model resource
if (getVdb() != null && getVdb().getSourceFile() != null && getVdb().getSourceFile().getProject() != null) {
IProject vdbProject = getVdb().getSourceFile().getProject();
resource = vdbProject.findMember(getPath());
if (resource == null)
resource = vdbProject.findMember(getSourceFilePath());
if (resource == null) {
Collection<IFile> files = WorkspaceResourceFinderUtil.findIResourceInProjectByName(getPathName(), vdbProject);
//
// Pick the first one, which is the best we can do.
// If user has 2 files of the same name in the same project then its impossible
// to tell what to do.
//
if (! files.isEmpty())
resource = files.iterator().next();
}
}
}
if (!(resource instanceof IFile)) {
setSynchronization(Synchronization.NotApplicable);
return null;
}
//
// Update the source file path to the resource path
//
sourceFilePath = resource.getFullPath();
return (IFile)resource;
}
@Override
public void save( final ZipOutputStream out) throws Exception {
// Name of VDB entry
String zipName = getPath().toOSString();
//
// Path on Windows will be using backslashes but zip entries only
// deal with forward slashes so need to replace with them.
//
zipName = zipName.replace(DOUBLE_BACK_SLASH, FORWARD_SLASH);
// Need to strip off the leading delimeter if it exists, else a "jar" extract command will result in models
// being located at the file system "root" folder.
if(zipName.startsWith(StringConstants.FORWARD_SLASH)) {
zipName = zipName.substring(1, zipName.length());
}
final ZipEntry zipEntry = new ZipEntry(zipName);
zipEntry.setComment(getDescription());
File theFile = findSourceFile();
save(out, zipEntry, theFile);
}
/**
* @return the type of file
*/
public FileEntryType getFileType() {
return this.fileType;
}
/**
* Find the artifact file at the specified path, for the specified project. The
* path may be absolute or it may be relative to the supplied project. The
* source file could be in a couple of places depending on how the vdb
* has been created.
* <li>if the source file is in the workspace then the source file path will be
* relative to the project
* <li>if the vdb has been freshly open then it could be beneath the staging folder
* of the parent vdb
* <li>if the vdb has been created from scratch and the source file added
* then the source file path should be absolute
*
* @return the File object if found or throws a {@link FileNotFoundException}
* @throws Exception
*/
private File findSourceFile() throws Exception {
//
// Try and find the source file adjacent to the project since
// this should be the most up to date version
//
IProject vdbProject = getVdb().getSourceFile().getProject();
if (vdbProject != null) {
IFile projectFile = vdbProject.getFile(getPath());
if (projectFile.exists())
return projectFile.getLocation().toFile();
IPath sourceFilePath = getSourceFilePath();
if (getSourceFilePath().isAbsolute()) {
sourceFilePath = getSourceFilePath().makeRelativeTo(vdbProject.getFullPath());
}
projectFile = vdbProject.getFile(sourceFilePath);
if (projectFile.exists())
return projectFile.getLocation().toFile();
}
//
// File cannot be found in project so see if the source file path
// leads us to the file
//
File sourceFile = sourceFilePath.toFile();
if (sourceFile.exists())
return sourceFile;
//
// Source file refers to the path used in the jar, eg. lib/blah.jar.
// This can happen when a vdb was opened that is not in the workspace.
// To ensure that the file is saved, fetch the file from the staging area
//
sourceFile = new File(getVdb().getStagingFolder(), getPath().toOSString());
if (sourceFile.exists())
return sourceFile;
throw new FileNotFoundException("Cannot save vdb file entry '" + sourceFilePath + "' to vdb file"); //$NON-NLS-1$//$NON-NLS-2$
}
@Override
public VdbFileEntry clone() {
try {
VdbFileEntry clone = new VdbFileEntry(getVdb(), sourceFilePath, fileType);
cloneVdbObject(clone);
return clone;
} catch (Exception ex) {
VdbPlugin.UTIL.log(ex);
return null;
}
}
}