blob: a319a8dd55acdc0751173263b8a1c1a726314d95 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 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.jdt.internal.ui.jarpackager;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.util.Assert;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService;
import org.eclipse.ltk.core.refactoring.history.RefactoringHistory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.jarpackager.IJarDescriptionReader;
import org.eclipse.jdt.ui.jarpackager.JarPackageData;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
/**
* Reads data from an InputStream and returns a JarPackage
*/
public class JarPackageReader extends Object implements IJarDescriptionReader {
protected InputStream fInputStream;
private MultiStatus fWarnings;
/**
* Reads a Jar Package from the underlying stream.
* It is the client's responsibility to close the stream.
*/
public JarPackageReader(InputStream inputStream) {
Assert.isNotNull(inputStream);
fInputStream= new BufferedInputStream(inputStream);
fWarnings= new MultiStatus(JavaPlugin.getPluginId(), 0, JarPackagerMessages.JarPackageReader_jarPackageReaderWarnings, null);
}
public void read(JarPackageData jarPackage) throws CoreException {
try {
readXML(jarPackage);
} catch (IOException ex) {
String message= (ex.getLocalizedMessage() != null ? ex.getLocalizedMessage() : ""); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, ex));
} catch (SAXException ex) {
String message= (ex.getLocalizedMessage() != null ? ex.getLocalizedMessage() : ""); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, ex));
}
}
/**
* Closes this stream.
* It is the clients responsibility to close the stream.
*
* @exception CoreException
*/
public void close() throws CoreException {
if (fInputStream != null)
try {
fInputStream.close();
} catch (IOException ex) {
String message= (ex.getLocalizedMessage() != null ? ex.getLocalizedMessage() : ""); //$NON-NLS-1$
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, message, ex));
}
}
public JarPackageData readXML(JarPackageData jarPackage) throws IOException, SAXException {
DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
factory.setValidating(false);
DocumentBuilder parser= null;
try {
parser= factory.newDocumentBuilder();
} catch (ParserConfigurationException ex) {
throw new IOException(ex.getLocalizedMessage());
} finally {
// Note: Above code is OK since clients are responsible to close the stream
}
Element xmlJarDesc= parser.parse(new InputSource(fInputStream)).getDocumentElement();
if (!xmlJarDesc.getNodeName().equals(JarPackagerUtil.DESCRIPTION_EXTENSION)) {
throw new IOException(JarPackagerMessages.JarPackageReader_error_badFormat);
}
NodeList topLevelElements= xmlJarDesc.getChildNodes();
for (int i= 0; i < topLevelElements.getLength(); i++) {
Node node= topLevelElements.item(i);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
Element element= (Element)node;
xmlReadJarLocation(jarPackage, element);
xmlReadOptions(jarPackage, element);
xmlReadRefactoring(jarPackage, element);
xmlReadSelectedProjects(jarPackage, element);
if (jarPackage.areGeneratedFilesExported())
xmlReadManifest(jarPackage, element);
xmlReadSelectedElements(jarPackage, element);
}
return jarPackage;
}
private void xmlReadJarLocation(JarPackageData jarPackage, Element element) {
if (element.getNodeName().equals(JarPackagerUtil.JAR_EXTENSION))
jarPackage.setJarLocation(Path.fromPortableString(element.getAttribute("path"))); //$NON-NLS-1$
}
private void xmlReadOptions(JarPackageData jarPackage, Element element) throws java.io.IOException {
if (element.getNodeName().equals("options")) { //$NON-NLS-1$
jarPackage.setOverwrite(getBooleanAttribute(element, "overwrite")); //$NON-NLS-1$
jarPackage.setCompress(getBooleanAttribute(element, "compress")); //$NON-NLS-1$
jarPackage.setExportErrors(getBooleanAttribute(element, "exportErrors")); //$NON-NLS-1$
jarPackage.setExportWarnings(getBooleanAttribute(element, "exportWarnings")); //$NON-NLS-1$
jarPackage.setSaveDescription(getBooleanAttribute(element, "saveDescription")); //$NON-NLS-1$
jarPackage.setUseSourceFolderHierarchy(getBooleanAttribute(element, "useSourceFolders", false)); //$NON-NLS-1$
jarPackage.setDescriptionLocation(Path.fromPortableString(element.getAttribute("descriptionLocation"))); //$NON-NLS-1$
jarPackage.setBuildIfNeeded(getBooleanAttribute(element, "buildIfNeeded", jarPackage.isBuildingIfNeeded())); //$NON-NLS-1$
jarPackage.setIncludeDirectoryEntries(getBooleanAttribute(element, "includeDirectoryEntries", false)); //$NON-NLS-1$
jarPackage.setRefactoringAware(getBooleanAttribute(element, "storeRefactorings", false)); //$NON-NLS-1$
}
}
private void xmlReadRefactoring(JarPackageData jarPackage, Element element) throws java.io.IOException {
if (element.getNodeName().equals("storedRefactorings")) { //$NON-NLS-1$
jarPackage.setExportStructuralOnly(getBooleanAttribute(element, "structuralOnly", jarPackage.isExportStructuralOnly())); //$NON-NLS-1$
jarPackage.setDeprecationAware(getBooleanAttribute(element, "deprecationInfo", jarPackage.isDeprecationAware())); //$NON-NLS-1$
List elements= new ArrayList();
int count= 1;
String value= element.getAttribute("project" + count); //$NON-NLS-1$
while (value != null && !"".equals(value)) { //$NON-NLS-1$
final IProject project= ResourcesPlugin.getWorkspace().getRoot().getProject(value);
if (project.exists())
elements.add(project);
count++;
value= element.getAttribute("project" + count); //$NON-NLS-1$
}
jarPackage.setRefactoringProjects((IProject[]) elements.toArray(new IProject[elements.size()]));
elements.clear();
count= 1;
IRefactoringHistoryService service= RefactoringCore.getHistoryService();
try {
service.connect();
value= element.getAttribute("refactoring" + count); //$NON-NLS-1$
while (value != null && !"".equals(value)) { //$NON-NLS-1$
final ByteArrayInputStream stream= new ByteArrayInputStream(value.getBytes("UTF-8")); //$NON-NLS-1$
try {
final RefactoringHistory history= service.readRefactoringHistory(stream, RefactoringDescriptor.NONE);
if (history != null) {
final RefactoringDescriptorProxy[] descriptors= history.getDescriptors();
if (descriptors.length > 0) {
for (int index= 0; index < descriptors.length; index++) {
elements.add(descriptors[index]);
}
}
}
} catch (CoreException exception) {
JavaPlugin.log(exception);
}
count++;
value= element.getAttribute("refactoring" + count); //$NON-NLS-1$
}
} finally {
service.disconnect();
}
jarPackage.setRefactoringDescriptors((RefactoringDescriptorProxy[]) elements.toArray(new RefactoringDescriptorProxy[elements.size()]));
}
}
private void xmlReadManifest(JarPackageData jarPackage, Element element) throws java.io.IOException {
if (element.getNodeName().equals("manifest")) { //$NON-NLS-1$
jarPackage.setManifestVersion(element.getAttribute("manifestVersion")); //$NON-NLS-1$
jarPackage.setUsesManifest(getBooleanAttribute(element, "usesManifest")); //$NON-NLS-1$
jarPackage.setReuseManifest(getBooleanAttribute(element, "reuseManifest")); //$NON-NLS-1$
jarPackage.setSaveManifest(getBooleanAttribute(element,"saveManifest")); //$NON-NLS-1$
jarPackage.setGenerateManifest(getBooleanAttribute(element, "generateManifest")); //$NON-NLS-1$
jarPackage.setManifestLocation(Path.fromPortableString(element.getAttribute("manifestLocation"))); //$NON-NLS-1$
jarPackage.setManifestMainClass(getMainClass(element));
xmlReadSealingInfo(jarPackage, element);
}
}
private void xmlReadSealingInfo(JarPackageData jarPackage, Element element) throws java.io.IOException {
/*
* Try to find sealing info. Could ask for single child node
* but this would stop others from adding more child nodes to
* the manifest node.
*/
NodeList sealingElementContainer= element.getChildNodes();
for (int j= 0; j < sealingElementContainer.getLength(); j++) {
Node sealingNode= sealingElementContainer.item(j);
if (sealingNode.getNodeType() == Node.ELEMENT_NODE
&& sealingNode.getNodeName().equals("sealing")) { //$NON-NLS-1$
// Sealing
Element sealingElement= (Element)sealingNode;
jarPackage.setSealJar(getBooleanAttribute(sealingElement, "sealJar")); //$NON-NLS-1$
jarPackage.setPackagesToSeal(getPackages(sealingElement.getElementsByTagName("packagesToSeal"))); //$NON-NLS-1$
jarPackage.setPackagesToUnseal(getPackages(sealingElement.getElementsByTagName("packagesToUnSeal"))); //$NON-NLS-1$
}
}
}
private void xmlReadSelectedElements(JarPackageData jarPackage, Element element) throws java.io.IOException {
if (element.getNodeName().equals("selectedElements")) { //$NON-NLS-1$
jarPackage.setExportClassFiles(getBooleanAttribute(element, "exportClassFiles")); //$NON-NLS-1$
jarPackage.setExportOutputFolders(getBooleanAttribute(element, "exportOutputFolder", false)); //$NON-NLS-1$
jarPackage.setExportJavaFiles(getBooleanAttribute(element, "exportJavaFiles")); //$NON-NLS-1$
NodeList selectedElements= element.getChildNodes();
Set elementsToExport= new HashSet(selectedElements.getLength());
for (int j= 0; j < selectedElements.getLength(); j++) {
Node selectedNode= selectedElements.item(j);
if (selectedNode.getNodeType() != Node.ELEMENT_NODE)
continue;
Element selectedElement= (Element)selectedNode;
if (selectedElement.getNodeName().equals("file")) //$NON-NLS-1$
addFile(elementsToExport, selectedElement);
else if (selectedElement.getNodeName().equals("folder")) //$NON-NLS-1$
addFolder(elementsToExport,selectedElement);
else if (selectedElement.getNodeName().equals("project")) //$NON-NLS-1$
addProject(elementsToExport ,selectedElement);
else if (selectedElement.getNodeName().equals("javaElement")) //$NON-NLS-1$
addJavaElement(elementsToExport, selectedElement);
// Note: Other file types are not handled by this writer
}
jarPackage.setElements(elementsToExport.toArray());
}
}
private void xmlReadSelectedProjects(JarPackageData jarPackage, Element element) throws java.io.IOException {
if (element.getNodeName().equals("selectedProjects")) { //$NON-NLS-1$
NodeList selectedElements= element.getChildNodes();
Set selectedProjects= new HashSet(selectedElements.getLength());
for (int index= 0; index < selectedElements.getLength(); index++) {
Node node= selectedElements.item(index);
if (node.getNodeType() != Node.ELEMENT_NODE)
continue;
Element selectedElement= (Element)node;
if (selectedElement.getNodeName().equals("project")) //$NON-NLS-1$
addProject(selectedProjects ,selectedElement);
}
jarPackage.setRefactoringProjects((IProject[]) selectedProjects.toArray(new IProject[selectedProjects.size()]));
}
}
protected boolean getBooleanAttribute(Element element, String name, boolean defaultValue) throws IOException {
if (element.hasAttribute(name))
return getBooleanAttribute(element, name);
else
return defaultValue;
}
protected boolean getBooleanAttribute(Element element, String name) throws IOException {
String value= element.getAttribute(name);
if (value != null && value.equalsIgnoreCase("true")) //$NON-NLS-1$
return true;
if (value != null && value.equalsIgnoreCase("false")) //$NON-NLS-1$
return false;
throw new IOException(JarPackagerMessages.JarPackageReader_error_illegalValueForBooleanAttribute);
}
private void addFile(Set selectedElements, Element element) throws IOException {
IPath path= getPath(element);
if (path != null) {
IFile file= JavaPlugin.getWorkspace().getRoot().getFile(path);
if (file != null)
selectedElements.add(file);
}
}
private void addFolder(Set selectedElements, Element element) throws IOException {
IPath path= getPath(element);
if (path != null) {
IFolder folder= JavaPlugin.getWorkspace().getRoot().getFolder(path);
if (folder != null)
selectedElements.add(folder);
}
}
private void addProject(Set selectedElements, Element element) throws IOException {
String name= element.getAttribute("name"); //$NON-NLS-1$
if (name.length() == 0)
throw new IOException(JarPackagerMessages.JarPackageReader_error_tagNameNotFound);
IProject project= JavaPlugin.getWorkspace().getRoot().getProject(name);
if (project != null)
selectedElements.add(project);
}
private IPath getPath(Element element) throws IOException {
String pathString= element.getAttribute("path"); //$NON-NLS-1$
if (pathString.length() == 0)
throw new IOException(JarPackagerMessages.JarPackageReader_error_tagPathNotFound);
return Path.fromPortableString(element.getAttribute("path")); //$NON-NLS-1$
}
private void addJavaElement(Set selectedElements, Element element) throws IOException {
String handleId= element.getAttribute("handleIdentifier"); //$NON-NLS-1$
if (handleId.length() == 0)
throw new IOException(JarPackagerMessages.JarPackageReader_error_tagHandleIdentifierNotFoundOrEmpty);
IJavaElement je= JavaCore.create(handleId);
if (je == null)
addWarning(JarPackagerMessages.JarPackageReader_warning_javaElementDoesNotExist, null);
else
selectedElements.add(je);
}
private IPackageFragment[] getPackages(NodeList list) throws IOException {
if (list.getLength() > 1)
throw new IOException(Messages.format(JarPackagerMessages.JarPackageReader_error_duplicateTag, list.item(0).getNodeName()));
if (list.getLength() == 0)
return null; // optional entry is not present
NodeList packageNodes= list.item(0).getChildNodes();
List packages= new ArrayList(packageNodes.getLength());
for (int i= 0; i < packageNodes.getLength(); i++) {
Node packageNode= packageNodes.item(i);
if (packageNode.getNodeType() == Node.ELEMENT_NODE && packageNode.getNodeName().equals("package")) { //$NON-NLS-1$
String handleId= ((Element)packageNode).getAttribute("handleIdentifier"); //$NON-NLS-1$
if (handleId.equals("")) //$NON-NLS-1$
throw new IOException(JarPackagerMessages.JarPackageReader_error_tagHandleIdentifierNotFoundOrEmpty);
IJavaElement je= JavaCore.create(handleId);
if (je != null && je.getElementType() == IJavaElement.PACKAGE_FRAGMENT)
packages.add(je);
else
addWarning(JarPackagerMessages.JarPackageReader_warning_javaElementDoesNotExist, null);
}
}
return (IPackageFragment[])packages.toArray(new IPackageFragment[packages.size()]);
}
private IType getMainClass(Element element) {
String handleId= element.getAttribute("mainClassHandleIdentifier"); //$NON-NLS-1$
if (handleId.equals("")) //$NON-NLS-1$
return null; // Main-Class entry is optional or can be empty
IJavaElement je= JavaCore.create(handleId);
if (je != null && je.getElementType() == IJavaElement.TYPE)
return (IType)je;
addWarning(JarPackagerMessages.JarPackageReader_warning_mainClassDoesNotExist, null);
return null;
}
/**
* Returns the status of the reader.
* If there were any errors, the result is a status object containing
* individual status objects for each error.
* If there were no errors, the result is a status object with error code <code>OK</code>.
*
* @return the status of this operation
*/
public IStatus getStatus() {
if (fWarnings.getChildren().length == 0)
return new Status(IStatus.OK, JavaPlugin.getPluginId(), 0, "", null); //$NON-NLS-1$
else
return fWarnings;
}
/**
* Adds a new warning to the list with the passed information.
* Normally the export operation continues after a warning.
* @param message the message
* @param error the throwable that caused the warning, or <code>null</code>
*/
protected void addWarning(String message, Throwable error) {
fWarnings.add(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), 0, message, error));
}
}