/* * 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.common.vdb; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import org.teiid.core.designer.TeiidDesignerException; import org.teiid.core.designer.TeiidDesignerRuntimeException; import org.teiid.core.designer.util.CoreArgCheck; /** * @since 8.0 */ public class VdbHeaderReader { private static final String XML_DECLARATION_PREFIX_STRING = "<?xml version="; //$NON-NLS-1$ private static final String VDB_FILE_EXTENSION = ".vdb"; //$NON-NLS-1$ private static final String MANIFEST_MODEL_NAME = "MetaMatrix-VdbManifestModel.xmi"; //$NON-NLS-1$ private static final String LOWER_CASE_MANIFEST_MODEL_NAME = MANIFEST_MODEL_NAME.toLowerCase(); // ================================================================================== // P U B L I C M E T H O D S // ================================================================================== public static VdbHeader readHeader( final File file ) throws TeiidDesignerException { if (file != null && file.isFile() && file.exists() && file.length() > 0) { final String lowerCaseFileName = file.getName().toLowerCase(); // If the java.io.File represents a VDB archive file if (lowerCaseFileName.endsWith(VDB_FILE_EXTENSION)) { ZipFile zipFile = null; InputStream iStream = null; VdbHeader header = null; try { zipFile = new ZipFile(file); iStream = getManifestStreamFromVdbArchive(zipFile); // If the zip is empty or does not contain a manifest model return null; if (iStream == null) { return null; } VdbHeaderReader reader = new VdbHeaderReader(); header = reader.read(iStream); } catch (IOException e) { throw new TeiidDesignerRuntimeException(e); } finally { if (iStream != null) { try { iStream.close(); } catch (IOException err) { // do nothing } } if (zipFile != null) { try { zipFile.close(); } catch (IOException e) { // do nothing } } } return header; } // Else if the java.io.File is the "MetaMatrix-VdbManifestModel.xmi" itself, then read it else if (LOWER_CASE_MANIFEST_MODEL_NAME.equals(lowerCaseFileName)) { VdbHeaderReader reader = new VdbHeaderReader(); return reader.read(file); } } // Otherwise return null since we don't know how to process this file return null; } /** * Read only the <XMI.header> section of the file and return the <code>VdbHeader</code> object representing its contents * * @param istream the InputStream from which we read the header * @return the VdbHeader object representing the contents of this section * @throws TeiidDesignerException if there is an error reading from the stream */ private VdbHeader read( InputStream istream ) throws TeiidDesignerException { if (istream == null) { // TODO: ADD I18n ?? final String msg = "VdbHeaderReader.The_InputStream_reference_may_not_be_null._1"; //$NON-NLS-1$ throw new IllegalArgumentException(msg); } DefaultHandler handler = new TerminatingVdbHeaderContentHandler(); try { Thread.currentThread().setContextClassLoader(VdbHeaderReader.class.getClassLoader()); SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setNamespaceAware(true); SAXParser parser = spf.newSAXParser(); parser.parse(new InputSource(istream), handler); } catch (SAXException e) { if (TerminatingVdbHeaderContentHandler.HEADER_FOUND_EXCEPTION_MESSAGE.equals(e.getMessage())) { // The header was successfully found } else if (TerminatingVdbHeaderContentHandler.XMI_NOT_FOUND_EXCEPTION_MESSAGE.equals(e.getMessage())) { // The file is probably an XML file but not an XMI file } else if (e instanceof SAXParseException) { // The file is probably a text file but not an XML file } } catch (IOException e) { // The file is not a file that can be interpretted by the SAX parser } catch (Throwable e) { // TODO: ADD I18n ?? final String msg = "VdbHeaderReader.Error_in_parsing_file_1"; //$NON-NLS-1$ throw new TeiidDesignerException(e, msg); } return ((TerminatingVdbHeaderContentHandler)handler).getVdbHeader(); } /** * Read only the <XMI.header> section of the file and return the <code>VdbHeader</code> object representing its contents * * @param file the File from which we read the header * @return the VdbHeader object representing the contents of this section * @throws TeiidDesignerException if there is an error reading the file */ public VdbHeader read( File file ) throws TeiidDesignerException { if (file == null) { //// TODO: ADD I18n ?? final String msg = "VdbHeaderReader.The_file_reference_may_not_be_null_2"; //$NON-NLS-1$ throw new IllegalArgumentException(msg); } if (!file.exists()) { //final Object[] params = new Object[] {file}; // TODO: ADD I18n ?? final String msg = "VdbHeaderReader.The_file_0_does_not_exist_and_therefore_cannot_be_read._3"; //$NON-NLS-1$ throw new IllegalArgumentException(msg); } if (!file.canRead()) { //final Object[] params = new Object[] {file}; // TODO: ADD I18n ?? final String msg = "VdbHeaderReader.The_file_0_does_not_have_read_privileges._4"; //$NON-NLS-1$ throw new IllegalArgumentException(msg); } // If the file does not start with an XML declaration tag ... if (!isXmlFile(file)) { return null; } // Attempt to read the XML file and interpret it as an XMI file FileInputStream fis = null; BufferedInputStream bis = null; try { fis = new FileInputStream(file); bis = new BufferedInputStream(fis); return read(bis); } catch (FileNotFoundException e) { // TODO: ADD I18n ?? final String msg = "VdbHeaderReader.Error_in_parsing_file_1"; //$NON-NLS-1$ throw new TeiidDesignerException(e, msg); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { // do nothing } } if (fis != null) { try { fis.close(); } catch (IOException e) { // do nothing } } } } // ================================================================================== // P R I V A T E M E T H O D S // ================================================================================== private static boolean isXmlFile( File file ) { FileInputStream fis = null; try { fis = new FileInputStream(file); byte[] buf = new byte[32]; fis.read(buf); if (new String(buf).startsWith(XML_DECLARATION_PREFIX_STRING)) { return true; } } catch (IOException e) { // do nothing } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // do nothing } } } return false; } /** * Return a java.io.InputStream reference for the MetaMatrix-VdbManifestModel.xmi model file contained within the Vdb archive. * If the specified file is not a Vdb archive file or the archive does not contain a manifest model then null is returned. * * @param zipFile the ZipFile for the VDB archive * @return the inputstream for the manifest file entry */ private static InputStream getManifestStreamFromVdbArchive( final ZipFile zipFile ) { return getEntryStreamFromArchive(zipFile, MANIFEST_MODEL_NAME); } /** * Return a java.io.InputStream reference for the specified zip entry name * * @param zipFile the ZipFile for the VDB archive * @param zipEntryName the fully qualified name of the zip entry * @return the inputstream for the zipfile entry */ private static InputStream getEntryStreamFromArchive( final ZipFile zipFile, final String zipEntryName ) { CoreArgCheck.isNotNull(zipFile); CoreArgCheck.isNotEmpty(zipEntryName); // the zip file that would be initialized if the file being read is an archive try { // Iterate over all entries in the zip file ... for (final Enumeration entries = zipFile.entries(); entries.hasMoreElements();) { ZipEntry entry = (ZipEntry)entries.nextElement(); if (entry == null) { continue; } // If the specified zip entry is found ... if (entry.getName().equalsIgnoreCase(zipEntryName)) { // return the contents of the entry return zipFile.getInputStream(entry); } } } catch (IOException e) { throw new TeiidDesignerRuntimeException(e); } return null; } }