blob: 24dc5ca17041282460f7c7a1e4207c729daf50e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.update.internal.core;
import org.eclipse.update.core.FeatureContentProvider;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.eclipse.update.core.BaseSiteFactory;
import org.eclipse.update.core.ContentReference;
import org.eclipse.update.core.Feature;
import org.eclipse.update.core.ISite;
import org.eclipse.update.core.JarContentReference;
import org.eclipse.update.core.PluginEntry;
import org.eclipse.update.core.Site;
import org.eclipse.update.core.SiteContentProvider;
import org.eclipse.update.core.SiteFeatureReferenceModel;
import org.eclipse.update.core.Utilities;
import org.eclipse.update.core.model.ArchiveReferenceModel;
import org.eclipse.update.core.model.InvalidSiteTypeException;
import org.eclipse.update.core.model.SiteModel;
import org.eclipse.update.core.model.SiteModelFactory;
import org.eclipse.update.internal.model.BundleManifest;
import org.eclipse.update.internal.model.DefaultPluginParser;
import org.xml.sax.SAXException;
public class SiteFileFactory extends BaseSiteFactory {
// private when parsing file system
private SiteFile site;
/*
* @see ISiteFactory#createSite(URL,boolean)
*/
public ISite createSite(URL url) throws CoreException, InvalidSiteTypeException {
Site site = null;
InputStream siteStream = null;
SiteModelFactory factory = this;
try {
// if url points to a directory
// attempt to parse site.xml
String path = url.getFile();
File siteLocation = new File(path);
if (siteLocation.isDirectory()) {
url = siteLocation.toURL();
File siteXMLFile = new File(siteLocation, Site.SITE_XML);
if (siteXMLFile.exists()) {
siteStream = new FileInputStream(siteXMLFile);
site = (Site) factory.parseSite(siteStream);
} else {
// parse siteLocation
site = parseSite(siteLocation);
}
} else {
// we are not pointing to a directory
// attempt to parse the file
try {
URL resolvedURL = URLEncoder.encode(url);
siteStream = openStream(resolvedURL);
site = (Site) factory.parseSite(siteStream);
} catch (IOException e) {
// attempt to parse parent directory
File file = new File(url.getFile());
File parentDirectory = file.getParentFile();
// do not create directory if it doesn't exist [18318]
// instead hrow error
if (parentDirectory != null && !parentDirectory.exists())
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_DirectoryDoesNotExist, (new String[] {file.getAbsolutePath()})), null);
if (parentDirectory == null || !parentDirectory.isDirectory())
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToObtainParentDirectory, (new String[] {file.getAbsolutePath()})), null);
site = parseSite(parentDirectory);
}
}
SiteContentProvider contentProvider = new SiteFileContentProvider(url);
site.setSiteContentProvider(contentProvider);
contentProvider.setSite(site);
site.resolve(url, url);
// Do not set read only as may install in it
//site.markReadOnly();
} catch (MalformedURLException e) {
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURL, (new String[] {url == null ? "" : url.toExternalForm()})), e); //$NON-NLS-1$
} catch (IOException e) {
throw Utilities.newCoreException(Messages.SiteFileFactory_UnableToAccessSite, ISite.SITE_ACCESS_EXCEPTION, e);
} finally {
try {
if (siteStream != null)
siteStream.close();
} catch (IOException e) {
}
}
return site;
}
/**
* Method parseSite.
*/
private Site parseSite(File directory) throws CoreException {
this.site = (SiteFile) createSiteMapModel();
if (!directory.exists())
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_FileDoesNotExist, (new String[] {directory.getAbsolutePath()})), null);
File pluginPath = new File(directory, Site.DEFAULT_PLUGIN_PATH);
//PACKAGED
try {
parsePackagedFeature(directory); // in case it contains JAR files
} catch (EmptyDirectoryException ede) {
UpdateCore.log(ede.getStatus());
}
try {
parsePackagedPlugins(pluginPath);
} catch (EmptyDirectoryException ede) {
UpdateCore.log(ede.getStatus());
}
// INSTALLED
try {
parseInstalledFeature(directory);
} catch (EmptyDirectoryException ede) {
UpdateCore.log(ede.getStatus());
}
try {
parseInstalledPlugins(pluginPath);
} catch (EmptyDirectoryException ede) {
UpdateCore.log(ede.getStatus());
}
return site;
}
/**
* Method parseFeature.
* @throws CoreException
*/
private void parseInstalledFeature(File directory) throws CoreException {
File featureDir = new File(directory, Site.DEFAULT_INSTALLED_FEATURE_PATH);
if (featureDir.exists()) {
String[] dir;
SiteFeatureReferenceModel featureRef;
URL featureURL;
File currentFeatureDir;
String newFilePath = null;
try {
// handle the installed featuresConfigured under featuresConfigured subdirectory
dir = featureDir.list();
if (dir == null) {
throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, directory.getName() + File.separator + directory.getName() + "directory is empty", null)); //$NON-NLS-1$
}
for (int index = 0; index < dir.length; index++) {
// the URL must ends with '/' for the bundle to be resolved
newFilePath = dir[index] + (dir[index].endsWith("/") ? "/" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
currentFeatureDir = new File(featureDir, newFilePath);
// check if feature.xml exists
File featureXMLFile = new File(currentFeatureDir, Feature.FEATURE_XML);
if (!featureXMLFile.exists()) {
UpdateCore.warn("Unable to find feature.xml in directory:" + currentFeatureDir); //$NON-NLS-1$
} else {
// PERF: remove code
//SiteFileFactory archiveFactory = new SiteFileFactory();
featureURL = currentFeatureDir.toURL();
featureRef = createFeatureReferenceModel();
featureRef.setSiteModel(site);
featureRef.setURLString(featureURL.toExternalForm());
featureRef.setType(ISite.DEFAULT_INSTALLED_FEATURE_TYPE);
((Site) site).addFeatureReferenceModel(featureRef);
}
}
} catch (MalformedURLException e) {
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {newFilePath})), e);
}
}
}
/**
* Method parseFeature.
* @throws CoreException
*/
private void parsePackagedFeature(File directory) throws CoreException {
// FEATURES
File featureDir = new File(directory, Site.DEFAULT_FEATURE_PATH);
if (featureDir.exists()) {
String[] dir;
SiteFeatureReferenceModel featureRef;
URL featureURL;
File currentFeatureFile;
String newFilePath = null;
try {
// only list JAR files
dir = featureDir.list(FeaturePackagedContentProvider.filter);
if (dir == null) {
throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, directory.getName() + File.separator + directory.getName() + "directory is empty", null)); //$NON-NLS-1$
}
for (int index = 0; index < dir.length; index++) {
// check if the JAR file contains a feature.xml
currentFeatureFile = new File(featureDir, dir[index]);
JarContentReference ref = new JarContentReference("", currentFeatureFile); //$NON-NLS-1$
ContentReference result = null;
try {
result = ref.peek(Feature.FEATURE_XML, null, null);
} catch (IOException e) {
UpdateCore.warn("Exception retrieving feature.xml in file:" + currentFeatureFile, e); //$NON-NLS-1$
}
if (result == null) {
UpdateCore.warn("Unable to find feature.xml in file:" + currentFeatureFile); //$NON-NLS-1$
} else {
featureURL = currentFeatureFile.toURL();
// PERF: remove code
//SiteFileFactory archiveFactory = new SiteFileFactory();
featureRef = createFeatureReferenceModel();
featureRef.setSiteModel(site);
featureRef.setURLString(featureURL.toExternalForm());
featureRef.setType(ISite.DEFAULT_PACKAGED_FEATURE_TYPE);
site.addFeatureReferenceModel(featureRef);
}
}
} catch (MalformedURLException e) {
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {newFilePath})), e);
}
}
}
/**
* Method parsePlugins.
*
* look into each plugin/fragment directory, crack the plugin.xml open (or
* fragment.xml ???) get id and version, calculate URL...
*
* @throws CoreException
*/
private void parseInstalledPlugins(File pluginsDir) throws CoreException {
if (!pluginsDir.exists() || !pluginsDir.isDirectory()) {
return;
}
File[] dirs = pluginsDir.listFiles(new FileFilter() {
public boolean accept(File f) {
return f.isDirectory();
}
});
DefaultPluginParser parser = new DefaultPluginParser();
if (dirs == null) {
throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, pluginsDir.getName() + File.separator + pluginsDir.getName() + "directory is empty", null)); //$NON-NLS-1$
}
for (int i = 0; i < dirs.length; i++) {
File pluginFile = new File(dirs[i], "META-INF/MANIFEST.MF"); //$NON-NLS-1$
InputStream in = null;
try {
BundleManifest bundleManifest = new BundleManifest(pluginFile);
if (bundleManifest.exists()) {
PluginEntry entry = bundleManifest.getPluginEntry();
addParsedPlugin(entry, dirs[i]);
} else {
if (!(pluginFile = new File(dirs[i], "plugin.xml")) //$NON-NLS-1$
.exists()) {
pluginFile = new File(dirs[i], "fragment.xml"); //$NON-NLS-1$
}
if (pluginFile != null && pluginFile.exists() && !pluginFile.isDirectory()) {
in = new FileInputStream(pluginFile);
PluginEntry entry = parser.parse(in);
addParsedPlugin(entry, dirs[i]);
}
}
} catch (IOException e) {
String pluginFileString = (pluginFile == null) ? null : pluginFile.getAbsolutePath();
UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {pluginFileString})), e));
} catch (SAXException e) {
String pluginFileString = (pluginFile == null) ? null : pluginFile.getAbsolutePath();
UpdateCore.log(Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_ErrorParsingFile, (new String[] {pluginFileString})), e));
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
}
}
/**
* transform each Plugin and Fragment into an ArchiveReferenceModel
* and a PluginEntry for the Site
*/
// PERF: removed intermediate Plugin object
private void addParsedPlugin(PluginEntry entry, File file) throws CoreException {
String location = null;
try {
if (entry != null) {
// create the plugin Entry
((Site) site).addPluginEntry(entry);
// Create the Site mapping ArchiveRef->PluginEntry
// the id of the archiveRef is plugins\<pluginid>_<ver>.jar as per the specs
// PERF: remove code
//SiteFileFactory archiveFactory = new SiteFileFactory();
ArchiveReferenceModel archive = createArchiveReferenceModel();
String id = (entry.getVersionedIdentifier().toString());
String pluginID = Site.DEFAULT_PLUGIN_PATH + id + FeatureContentProvider.JAR_EXTENSION;
archive.setPath(pluginID);
location = file.toURL().toExternalForm();
archive.setURLString(location);
((Site) site).addArchiveReferenceModel(archive);
// TRACE
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_PARSING) {
UpdateCore.debug("Added archive to site:" + pluginID + " pointing to: " + location); //$NON-NLS-1$ //$NON-NLS-2$
}
}
} catch (MalformedURLException e) {
throw Utilities.newCoreException(NLS.bind(Messages.SiteFileFactory_UnableToCreateURLForFile, (new String[] {location})), e);
}
}
/**
*
*/
private void parsePackagedPlugins(File pluginDir) throws CoreException {
if (!pluginDir.exists()) {
return;
}
String[] dir = pluginDir.list(FeaturePackagedContentProvider.filter);
if (dir == null) {
throw new EmptyDirectoryException(new Status(IStatus.WARNING, UpdateCore.getPlugin().getBundle().getSymbolicName(), IStatus.OK, pluginDir.getName() + File.separator + pluginDir.getName() + "directory is empty", null)); //$NON-NLS-1$
}
for (int i = 0; i < dir.length; i++) {
ContentReference ref = null;
String refString = null;
InputStream in = null;
JarContentReference jarReference = null;
try {
File file = new File(pluginDir, dir[i]);
jarReference = new JarContentReference(null, file);
ref = jarReference.peek("META-INF/MANIFEST.MF", null, null); //$NON-NLS-1$
if (ref != null) {
in = ref.getInputStream();
BundleManifest manifest = new BundleManifest(in);
if (manifest.exists()) {
addParsedPlugin(manifest.getPluginEntry(), file);
continue;
}
}
ref = jarReference.peek("plugin.xml", null, null);//$NON-NLS-1$
if (ref == null) {
ref = jarReference.peek("fragment.xml", null, null); //$NON-NLS-1$
}
if (ref != null) {
in = ref.getInputStream();
PluginEntry entry = new DefaultPluginParser().parse(in);
addParsedPlugin(entry, file);
}
} catch (Exception e) {
try {
refString = (ref == null) ? null : ref.asURL().toExternalForm();
} catch (IOException ioe) {
}
String message;
if (e instanceof IOException) {
message = NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {refString}));
} else if (e instanceof SAXException) {
message = NLS.bind(Messages.SiteFileFactory_ErrorParsingFile, (new String[] {refString}));
} else {
message = NLS.bind(Messages.SiteFileFactory_ErrorAccessing, (new String[] {refString}));
}// end if
// Log exception, but do not throw to caller.
// Continue with processing remaining plug-ins
UpdateCore.log(message, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ce) {
}
}
if (jarReference != null) {
try {
jarReference.closeArchive();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
/*
* @see SiteModelFactory#createSiteMapModel()
*/
public SiteModel createSiteMapModel() {
return new SiteFile();
}
/*
* @see SiteModelFactory#canParseSiteType(String)
*/
public boolean canParseSiteType(String type) {
return (super.canParseSiteType(type) || SiteFileContentProvider.SITE_TYPE.equalsIgnoreCase(type));
}
}