/* * 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.core.index; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.FileUtils; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.index.AbstractIndexSelector; import org.teiid.designer.core.index.Index; import org.teiid.designer.core.index.IndexConstants; import org.teiid.designer.core.resource.EmfResource; import org.teiid.designer.core.util.DateUtil; import org.teiid.designer.core.workspace.ModelFileUtil; /** * ResourceFileIndexSelector returns indexes associated with a specified file. The specified file can represent a single EMF * resource, a folder containing zero or more resources, or an archive containing resource files. Indexes will be generated for * all resources associated with the specified file. * * @since 8.0 */ // mtkTODO: Remove this class (and the subclass, associated tests, and factory functionality) public class ResourceFileIndexSelector extends AbstractIndexSelector { private static final File[] EMPTY_FILE_ARRAY = new File[0]; private static final Index[] EMPTY_INDEX_ARRAY = new Index[0]; private static final Resource[] EMPTY_RESOURCE_ARRAY = new Resource[0]; protected static final String TEMP_DIR = FileUtils.TEMP_DIRECTORY + "\\indexes"; //$NON-NLS-1$ protected final File selectedFile; protected Index[] indexes; protected String indexDirectoryPath; // ================================================================================== // C O N S T R U C T O R S // ================================================================================== /** * Construct an instance of ResourceFileIndexSelector. * * @param filePath the absolute path to the file; may not be null * @throws CoreException */ public ResourceFileIndexSelector( String filepath ) throws ModelerCoreException { if (filepath == null) { CoreArgCheck.isNotNull(filepath, ModelerCore.Util.getString("ResourceFileIndexSelector.The_filepath_string_may_not_be_null_1")); //$NON-NLS-1$ } this.selectedFile = new File(filepath); // Check if the selected file exists ... if (!this.selectedFile.exists()) { throw new IllegalArgumentException( ModelerCore.Util.getString("ResourceFileIndexSelector.The_specified_file_does_not_exist._2", filepath)); //$NON-NLS-1$ } // The specified file is an archive ... if (FileUtils.isArchiveFileName(filepath)) { ModelerCore.Util.log(IStatus.INFO, ModelerCore.Util.getString("ResourceFileIndexSelector.Building_indexes_from_resource_found_in_archive_._3", filepath)); //$NON-NLS-1$ } // The specified file is a folder ... else if (this.selectedFile.isDirectory()) { ModelerCore.Util.log(IStatus.INFO, ModelerCore.Util.getString("ResourceFileIndexSelector.Building_indexes_from_resource_found_under_folder_._4", filepath)); //$NON-NLS-1$ } // The specified file is the resource itself ... else if (this.selectedFile.isFile()) { ModelerCore.Util.log(IStatus.INFO, ModelerCore.Util.getString("ResourceFileIndexSelector.Building_indexes_from_resource_at_._5", filepath)); //$NON-NLS-1$ } // The specified resource cannot be interpretted else { throw new ModelerCoreException( ModelerCore.Util.getString("ResourceFileIndexSelector.The_specified_file_cannot_be_processed_by_the_ResourceFileIndexSelector_6", filepath)); //$NON-NLS-1$ } } // ================================================================================== // I N T E R F A C E M E T H O D S // ================================================================================== /* * @See org.teiid.designer.core.index.IndexSelector#getIndexes() */ @Override public Index[] getIndexes() throws IOException { // If no index files exist yet then look for EMF resource // files to use for creating the index files if (this.indexes == null || this.indexes.length == 0) { this.indexes = buildIndexes(this.selectedFile); } return this.indexes; } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== /** * Builds new index files for any models that are part of a Archive/directory. */ protected Index[] buildIndexes( final File f ) throws IOException { // Retrieve any model files from the specified File File[] modelFiles = loadModelFiles(f); // Load the EMF resources for any model files that were found Resource[] models = EMPTY_RESOURCE_ARRAY; try { models = loadResources(modelFiles); } catch (Throwable e) { ModelerCore.Util.log(IStatus.ERROR, e, ModelerCore.Util.getString("ResourceFileIndexSelector.Error_loading_resources_for_7", f)); //$NON-NLS-1$ } // Create new index files for any loaded resources Index[] newIndexes = EMPTY_INDEX_ARRAY; try { newIndexes = indexResources(models); } catch (Throwable e) { ModelerCore.Util.log(IStatus.ERROR, e, ModelerCore.Util.getString("ResourceFileIndexSelector.Error_building_indexes_for_resources_in_8", f)); //$NON-NLS-1$ } return newIndexes; } /** * Return the MtkIndex[] corresponding to the specified array of EMF resources. * * @param modelFiles * @return * @throws CoreException */ protected Index[] indexResources( final Resource[] models ) throws CoreException { ArrayList tmp = new ArrayList(); File indexDirectory = new File(this.getIndexDirectoryPath()); // Create index files for all model resources for (int i = 0; i < models.length; i++) { EmfResource resource = (EmfResource)models[i]; if (resource != null) { String indexFileName = resource.getURI().lastSegment(); String extension = resource.getURI().fileExtension(); if (extension != null) { int endIndex = indexFileName.indexOf(extension) - 1; indexFileName = indexFileName.substring(0, endIndex); } indexFileName = indexFileName + IndexConstants.EXTENSION_CHAR + IndexConstants.INDEX_EXT; // Remove any existing index file prior to creating the new one File indexFilePath = new File(indexDirectory.getAbsolutePath() + File.separator + indexFileName); if (indexFilePath.exists()) { indexFilePath.delete(); } // Index the EMF resource String resourcePath = resource.getURI().toFileString(); IndexUtil.indexResource(resource, resourcePath, this.getIndexDirectoryPath(), indexFileName); // Retrive the index file from the file system File indexFile = new File(indexDirectory, indexFileName); if (isIndexFile(indexFile)) { Index theIndex = IndexUtil.getIndexFile(indexFile.getName(), indexFile.getAbsolutePath(), resource.getURI().lastSegment()); if (theIndex != null) { tmp.add(theIndex); } } } } Index[] result = new Index[tmp.size()]; tmp.toArray(result); return result; } /** * Return the Resource[] for the EMF resources corresponding to the specified array of model files. * * @param modelFiles * @return * @throws CoreException */ protected Resource[] loadResources( final File[] modelFiles ) throws CoreException { ArrayList tmp = new ArrayList(); // Create a temporary container final String tempContainerName = DateUtil.getCurrentDateAsString() + "_Container"; //$NON-NLS-1$ final Container container = this.createContainer(tempContainerName); // Load the resources into the temporary container for (int i = 0; i < modelFiles.length; i++) { File modelFile = modelFiles[i]; Resource resource = loadResource(container, modelFile); if (resource != null && resource instanceof EmfResource) { tmp.add(resource); } } Resource[] result = new Resource[tmp.size()]; tmp.toArray(result); return result; } /** * Load the Resource for the specified model file * * @param modelFile * @return * @throws CoreException */ protected Resource loadResource( final Container container, final File modelFile ) { URI uri = URI.createFileURI(modelFile.getAbsolutePath()); Resource resource = container.getResource(uri, true); return resource; } /** * Create a {@link org.teiid.designer.core.container.Container} instance to be used when loading the resources. * * @param name * @return */ protected Container createContainer( final String name ) throws CoreException { return ModelerCore.createContainer(name); } /** * Return the File[] for the specified file if it is a model file, folder, or archive. * * @param f * @return * @throws IOException */ protected File[] loadModelFiles( final File f ) throws IOException { File[] modelFiles = EMPTY_FILE_ARRAY; // Retrieve any model files from the archive if (FileUtils.isArchiveFileName(f.getName())) { modelFiles = loadModelsFromZip(f); } // Retrieve model files in the given directory else if (f.isDirectory()) { modelFiles = loadModelsFromFolder(f); } // Retrieve the model file from the specified file else { modelFiles = loadModelsFromFile(f); } return modelFiles; } /** * Return the File[] for the specified file if it is a model file. * * @param file * @return * @throws IOException */ protected File[] loadModelsFromFile( final File file ) { File[] result = EMPTY_FILE_ARRAY; if (ModelFileUtil.isModelFile(file)) { result = new File[1]; result[0] = file; } return result; } /** * Return the File[] constructed from model files found in the specified folder * * @param folder * @return * @throws IOException */ protected File[] loadModelsFromFolder( final File folder ) { ArrayList tmp = new ArrayList(); File[] files = folder.listFiles(); for (int i = 0; i < files.length; i++) { if (ModelFileUtil.isModelFile(files[i])) { tmp.add(files[i]); } } File[] result = new File[tmp.size()]; tmp.toArray(result); return result; } /** * Return the File[] constructed from model files found in the specified archive * * @param folder * @return * @throws IOException */ protected File[] loadModelsFromZip( final File zip ) throws IOException { // the zip file that would be initialized // if the file being read is an archive ZipFile zipFile = null; try { zipFile = new ZipFile(zip); // ArrayListy of MtkIndexes, one for each entry in the zip file ArrayList tmp = new ArrayList(); // Iterate over all entries in the zip file ... Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { // need to read the entry and write a file to a temporary location ZipEntry entry = (ZipEntry)entries.nextElement(); if (entry == null) { break; } IPath zipEntryPath = new Path(entry.getName()); String entryName = zipEntryPath.lastSegment(); // read the contents of the entry InputStream inputStream = zipFile.getInputStream(entry); // buffer that would contain the contents of the entry byte[] buffer; int length = (int)entry.getSize(); if (length >= 0) { buffer = new byte[length]; int offset = 0; do { int n = inputStream.read(buffer, offset, length); offset += n; length -= n; } while (length > 0); } else { buffer = new byte[1024]; int n; do { n = inputStream.read(buffer, 0, 1024); } while (n >= 0); } // create the directory into which the models will be extracted - use // the same directory path into which the index files will be written File indexDirectory = new File(this.getIndexDirectoryPath()); if (!indexDirectory.exists()) { indexDirectory.mkdir(); } // create an index file at the temporary location // write contents of the zip entry to this file File entryFile = new File(indexDirectory.getAbsolutePath() + File.separator + entryName); entryFile.createNewFile(); entryFile.deleteOnExit(); FileOutputStream outputStream = new FileOutputStream(entryFile); outputStream.write(buffer); outputStream.flush(); outputStream.close(); // Add an File reference if zip entry is a model file if (ModelFileUtil.isModelFile(entryFile)) { tmp.add(entryFile); } } File[] result = new File[tmp.size()]; tmp.toArray(result); return result; } catch (IOException e) { throw e; } finally { try { if (zipFile != null) { zipFile.close(); } } catch (IOException e) { }// Ignore } } /** * Check if the given file name is an index name, by checking the extension. * * @param fileName The index file name. * @return true if it is an index file. */ protected boolean isIndexFile( final String fileName ) { if (fileName == null || fileName.length() == 0) { return false; } if (fileName.endsWith(IndexConstants.INDEX_EXT)) { return true; } return false; } /** * Check if the given file is an index, by checking the type and extension. * * @param file The File instance to check. * @return true if it is an index file. */ protected boolean isIndexFile( final File file ) { if (file != null && file.isFile() && file.exists()) { return isIndexFile(file.getName()); } return false; } /** * Returns the location of the directory into which index files will be written * * @return */ protected String getIndexDirectoryPath() { if (this.indexDirectoryPath == null) { this.indexDirectoryPath = TEMP_DIR; } return this.indexDirectoryPath; } protected void setIndexDirectoryPath( final String path ) { this.indexDirectoryPath = path; } }