/* * 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; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collections; import java.util.Enumeration; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.runtime.Path; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.teiid.core.designer.ModelerCoreException; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.core.designer.util.FileUtils; import org.teiid.designer.core.container.Container; import org.teiid.designer.core.container.ContainerImpl; import org.teiid.designer.core.workspace.ModelFileUtil; /** * @since 8.0 */ public class ExternalResourceLoader { private static final String BUNDLE_RESOURCE_URL = "bundleresource://"; //$NON-NLS-1$ protected static final String EXTENSION_CHAR = "."; //$NON-NLS-1$ protected static final String SUFFIX_JAR = ".JAR"; //$NON-NLS-1$ protected static final String SUFFIX_ZIP = ".ZIP"; //$NON-NLS-1$ protected static final String SUFFIX_VDB = ".VDB"; //$NON-NLS-1$ public ExternalResourceLoader() { } public Resource load( final ExternalResourceDescriptor descriptor, final Container container ) throws ModelerCoreException { if (descriptor == null) { CoreArgCheck.isNotNull(descriptor, ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_reference_may_not_be_null_1")); //$NON-NLS-1$ } if (container == null) { CoreArgCheck.isNotNull(container, ModelerCore.Util.getString("ExternalResourceLoader.The_Container_reference_may_not_be_null_2")); //$NON-NLS-1$ } // Validate the information in the descriptor this.validateDescriptor(descriptor); // Obtain the external resource information for loading String resourceUrl = descriptor.getResourceUrl(); String resourceName = descriptor.getResourceName(); String internalUri = descriptor.getInternalUri(); String tempDirPath = this.getTempDirectoryPath(descriptor); File resourceFile = retrieveResourceFile(resourceUrl, resourceName, tempDirPath); // Check that the retrieved resource is a EMF resource if (resourceFile == null) { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.An_existing_resource_with_the_name_cannot_retrieved_from_{1}._7", resourceName, resourceUrl)); //$NON-NLS-1$ } if (!ModelFileUtil.isModelFile(resourceFile)) { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.The_external_resource_with_the_name_is_not_a_model_resource._8", resourceName)); //$NON-NLS-1$ } // Load the EMF resource into the container return loadResource(container, resourceFile, internalUri); } public void validateDescriptor( final ExternalResourceDescriptor descriptor ) throws ModelerCoreException { if (descriptor == null) { CoreArgCheck.isNotNull(descriptor, ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_reference_may_not_be_null_1")); //$NON-NLS-1$ } if (descriptor.getResourceUrl() == null || descriptor.getResourceUrl().length() == 0) { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_may_not_have_a_null_or_empty_resource_URL_string_3")); //$NON-NLS-1$ } if (descriptor.getResourceName() == null || descriptor.getResourceName().length() == 0) { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_may_not_have_a_null_or_empty_resource_name_string_4")); //$NON-NLS-1$ } final String resourceUrl = descriptor.getResourceUrl(); final String resourceName = descriptor.getResourceName(); // validate only if this is file based URL if (!resourceUrl.startsWith(BUNDLE_RESOURCE_URL)) { // Check if the external resource exists ... File f = new File(resourceUrl); if (!f.exists()) { // Look for resource in classpath (for running outside of Eclipse) final URL url = ClassLoader.getSystemResource(resourceUrl); if (url == null) { throw new IllegalArgumentException( ModelerCore.Util.getString("ExternalResourceLoader.The_resource_with_name_and_location_cannot_be_found_on_the_file_system._2", resourceName, resourceUrl)); //$NON-NLS-1$ } final String loc = url.getPath(); ((ExternalResourceDescriptorImpl)descriptor).setResourceUrl(loc); f = new File(loc); } // The resource location is an archive ... if (this.isArchiveFileName(resourceUrl)) { } // The resource location is a folder ... else if (f.isDirectory()) { } // The resource location is the resource itself ... else if (f.isFile() && f.getName().equalsIgnoreCase(resourceName)) { } // The specified resource cannot be interpretted else { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.The_resource_with_name_and_location_cannot_be_processed_by_the_loader._6", resourceName, resourceUrl)); //$NON-NLS-1$ } } } private File retrieveResourceFile( final String resourceUrl, final String resourceName, final String tempDirectoryPath ) throws ModelerCoreException { //System.out.println("retrieveResourceFile(" + resourceUrl + ", " + resourceName + ", " + tempDirectoryPath + ")"); File resourceFile = null; // since this could be jar/zip/vdb file, and ZipUtil only works with the // physical files, we need to materialize this. if (resourceUrl.startsWith(BUNDLE_RESOURCE_URL)) { String fileName = CoreStringUtil.getLastToken(resourceUrl, "/"); //$NON-NLS-1$ resourceFile = new File(tempDirectoryPath, fileName); if (!resourceFile.exists()) { try { FileUtils.write(new URL(resourceUrl).openStream(), resourceFile); } catch (IOException e) { throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.An_existing_resource_with_the_name_cannot_retrieved_from_{1}._7", resourceName, resourceUrl)); //$NON-NLS-1$ } } else { //System.out.println("First Check: " + resourceFile.getAbsolutePath()); FileInputStream fis = null; try { fis = new FileInputStream(resourceFile); if (!(contentEquals(fis, new URL(resourceUrl).openStream()))){ //System.out.println("contents mismatch: trying to write new resource"); FileUtils.write(new URL(resourceUrl).openStream(), resourceFile); } } catch (IOException e) { e.printStackTrace(); throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.An_existing_resource_with_the_name_cannot_retrieved_from_{1}._7", resourceName, resourceUrl)); //$NON-NLS-1$ } finally { if( fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } } else { resourceFile = new File(resourceUrl); // Retrieve the resource from the folder if (resourceFile.isDirectory()) { return retrieveResourceFromFolder(resourceFile, resourceName); } } // Retrieve the resource from the archive if (this.isArchiveFileName(resourceFile.getAbsolutePath())) { return retrieveResourceFromZip(resourceFile, resourceName, tempDirectoryPath); } return resourceFile; } /* * A resource currently exists if the resource does not match the resource from the Bundle it will be overwritten * TODO: Determine if moving these resources to the workspace is actually needed. Some of this might be avoided by * referencing the files directly from the plugin directory */ public static boolean contentEquals(InputStream input1, InputStream input2) throws IOException { if (!(input1 instanceof BufferedInputStream)) { input1 = new BufferedInputStream(input1); } if (!(input2 instanceof BufferedInputStream)) { input2 = new BufferedInputStream(input2); } int ch = input1.read(); while (-1 != ch) { int ch2 = input2.read(); if (ch != ch2) { return false; } ch = input1.read(); } // ch2 should not have anymore to read int ch2 = input2.read(); return (ch2 == -1); } /** * Load the model resource into the specified container * * @param container to load the resource into * @param resourceFile the File instance representing the model resource * @param internalUri the string to use as a logical URI reference to this resource * @return * @throws CoreException */ protected Resource loadResource( final Container container, final File resourceFile, final String internalUri ) throws ModelerCoreException { if (resourceFile == null) { CoreArgCheck.isNotNull(resourceFile, ModelerCore.Util.getString("ExternalResourceLoader.The_java.io.File_reference_may_not_be_null_11")); //$NON-NLS-1$ } if (!resourceFile.exists()) { CoreArgCheck.isTrue(resourceFile.exists(), ModelerCore.Util.getString("ExternalResourceLoader.The_java.io.File_reference_must_exist_12")); //$NON-NLS-1$ } try { // Create the physical URI URI physicalURI = URI.createFileURI(resourceFile.getAbsolutePath()); // Create the logical URI URI logicalURI = null; if (internalUri != null && internalUri.length() > 0) { logicalURI = URI.createURI(internalUri); } Resource externalResource = null; // Create an external resource and load it into the container using the logical URI if (logicalURI != null && container instanceof ContainerImpl) { // Get the appropriate resource factory to use for creating the new // resource instance. We use the physical URI assuming it has a file // extension or protocol found in the factory registry maps. ResourceSet resourceSet = ((ContainerImpl)container).getResourceSet(); Resource.Factory resourceFactory = resourceSet.getResourceFactoryRegistry().getFactory(physicalURI); if (resourceFactory != null) { // Create resource using the logical URI externalResource = resourceFactory.createResource(logicalURI); resourceSet.getResources().add(externalResource); // Load the external resource from the file FileInputStream fis = null; InputStream bis = null; try { fis = new FileInputStream(resourceFile); bis = new BufferedInputStream(fis); Map options = (externalResource.getResourceSet() != null ? externalResource.getResourceSet().getLoadOptions() : Collections.EMPTY_MAP); externalResource.load(bis, options); } finally { if (bis != null) { bis.close(); } if (fis != null) { fis.close(); } } } } // Create an external resource and load it into the container using the physical URI if (externalResource == null) { externalResource = container.getResource(physicalURI, true); // Add a logical URI mapping to the resource set if (logicalURI != null) { container.getURIConverter().getURIMap().put(logicalURI, physicalURI); } } return externalResource; } catch (Throwable e) { throw new ModelerCoreException( e, ModelerCore.Util.getString("ExternalResourceLoader.Error_loading_the_external_resource_into_the_container._13", resourceFile)); //$NON-NLS-1$ } } /** * Return the File constructed from model files found in the specified folder * * @param folder * @return * @throws IOException */ protected File retrieveResourceFromFolder( final File folder, final String fileName ) throws ModelerCoreException { File[] files = folder.listFiles(); for (int i = 0; i < files.length; i++) { File f = files[i]; if (f.isFile() && f.exists() && f.getName().equalsIgnoreCase(fileName)) { return f; } } throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.An_existing_file_with_the_name_cannot_be_found_under_the_directory._14", fileName, folder)); //$NON-NLS-1$ } /** * Return the File[] constructed from model files found in the specified archive * * @param folder * @return * @throws IOException */ protected File retrieveResourceFromZip( final File zip, final String zipEntryName, final String tempDirectoryLocation ) throws ModelerCoreException { ZipFile zipFile = null; try { zipFile = new ZipFile(zip); // Iterate over all entries in the zip file ... Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry)entries.nextElement(); if (entry == null) { break; } // Find the specified entry by name if (entry.getName().equalsIgnoreCase(zipEntryName)) { // 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); } // Set the location for the extracted file File extractDirectory = new File(tempDirectoryLocation); if (!extractDirectory.exists()) { extractDirectory.mkdir(); } // Extract the entry that is the external resource // Create a temporary file for the external resource and write // the contents of the zip entry to this file String entryName = (new Path(entry.getName())).lastSegment(); File entryFile = new File(extractDirectory + File.separator + entryName); entryFile.createNewFile(); entryFile.deleteOnExit(); FileOutputStream outputStream = new FileOutputStream(entryFile); outputStream.write(buffer); outputStream.flush(); outputStream.close(); inputStream.close(); return entryFile; } } throw new ModelerCoreException( ModelerCore.Util.getString("ExternalResourceLoader.An_existing_entry_with_the_name_cannot_be_found_in_the_archive._15", zipEntryName, zip)); //$NON-NLS-1$ } catch (Throwable e) { throw new ModelerCoreException( e, ModelerCore.Util.getString("ExternalResourceLoader.An_existing_entry_with_the_name_cannot_be_found_in_the_archive._16", zipEntryName, zip)); //$NON-NLS-1$ } finally { try { if (zipFile != null) { zipFile.close(); } } catch (IOException e) { }// Ignore } } protected String getTempDirectoryPath( final ExternalResourceDescriptor descriptor ) { if (descriptor == null) { CoreArgCheck.isNotNull(descriptor, ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_reference_may_not_be_null_1")); //$NON-NLS-1$ } CoreArgCheck.isInstanceOf(ExternalResourceDescriptorImpl.class, descriptor, ModelerCore.Util.getString("ExternalResourceLoader.The_ExternalResourceDescriptor_must_be_an_instanceof_ExternalResourceDescriptorImpl_1")); //$NON-NLS-1$ final ExternalResourceDescriptorImpl descriptorImpl = (ExternalResourceDescriptorImpl)descriptor; String tempDirPath = descriptorImpl.getTempDirectoryPath(); if (tempDirPath == null || tempDirPath.length() == 0) { try { tempDirPath = File.createTempFile("temp", null).getParent(); //$NON-NLS-1$ } catch (final IOException err) { tempDirPath = System.getProperty("user.dir"); //$NON-NLS-1$ } } return tempDirPath; } /** * Returns true iff str.toUpperCase().endsWith(".JAR") || str.toUpperCase().endsWith(".ZIP") || * str.toUpperCase().endsWith(".VDB") */ protected boolean isArchiveFileName( String name ) { if (CoreStringUtil.isEmpty(name)) { return false; } final String upperCaseName = name.toUpperCase(); if (upperCaseName.endsWith(SUFFIX_JAR) || upperCaseName.endsWith(SUFFIX_ZIP) || upperCaseName.endsWith(SUFFIX_VDB)) { return true; } return false; } }