/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ivyde.internal.eclipse.cpcontainer;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.ivyde.eclipse.cp.IvyClasspathContainerHelper;
import org.apache.ivyde.internal.eclipse.IvyDEMessage;
import org.apache.ivyde.internal.eclipse.IvyPlugin;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class IvyClasspathContainerSerializer {
private static final String ROOT = "ivydecontainers";
private static final String IVYCP = "ivycp";
private static final String PATH = "path";
private static final String PROJECT = "project";
private static final String CPENTRIES = "cpentries";
private static final String CPATTRS = "cpattrs";
private static final String ATTR = "attr";
private static final String NAME = "name";
private static final String VALUE = "value";
private static final String CPENTRY = "cpentry";
private static final String KIND = "kind";
private static final String SOURCE = "source";
private static final String ACCESS_RULES = "accessRules";
private static final String RULE = "rule";
private static final String PATTERN = "pattern";
private File containersStateDir;
private IvyAttachementManager ivyAttachementManager;
public IvyClasspathContainerSerializer(File containersStateDir,
IvyAttachementManager ivyAttachementManager) {
this.containersStateDir = containersStateDir;
this.ivyAttachementManager = ivyAttachementManager;
}
public void save(IJavaProject project) {
List/* <IvyClasspathContainer> */ivycps = IvyClasspathContainerHelper
.getContainers(project);
try {
File file = new File(containersStateDir, project.getProject().getName() + ".xml");
IvyDEMessage.verbose("Saving the state of the containers of the project "
+ project.getProject().getName() + " into " + file);
FileOutputStream out = new FileOutputStream(file);
try {
write(out, ivycps);
} finally {
try {
out.close();
} catch (IOException e) {
// don't care
}
}
} catch (Exception ioe) {
IvyPlugin.logWarn("IvyDE container states of the project "
+ project.getProject().getName() + " cound not be saved", ioe);
}
}
public Map/* <IPath, IvyClasspathContainer> */read(IJavaProject project) {
File file = new File(containersStateDir, project.getProject().getName() + ".xml");
IvyDEMessage.verbose("Loading the state of the containers of the project "
+ project.getProject().getName() + " from " + file);
if (!file.exists()) {
IvyPlugin.logWarn("IvyDE container states of the project "
+ project.getProject().getName() + " doesn't exist.");
return null;
}
try {
FileInputStream in = new FileInputStream(file);
try {
return read(in);
} finally {
try {
in.close();
} catch (IOException e) {
// don't care
}
}
} catch (Exception ioe) {
IvyPlugin.logWarn("IvyDE container states of the project "
+ project.getProject().getName() + " cound not be read", ioe);
return null;
}
}
private void write(OutputStream out, List/* <IvyClasspathContainer> */containers)
throws IOException {
try {
StreamResult result = new StreamResult(out);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
Node root = document.createElement(ROOT);
document.appendChild(root);
Iterator it = containers.iterator();
while (it.hasNext()) {
IvyClasspathContainerImpl ivycp = (IvyClasspathContainerImpl) it.next();
Node node = document.createElement(IVYCP);
root.appendChild(node);
NamedNodeMap attributes = node.getAttributes();
Attr attr = document.createAttribute(PATH);
attr.setValue(ivycp.getPath().toString());
attributes.setNamedItem(attr);
attr = document.createAttribute(PROJECT);
attr.setValue(ivycp.getConf().getProject().getName());
attributes.setNamedItem(attr);
writeCpEntries(ivycp, document, node, ivycp.getClasspathEntries());
writeCpAttr(ivycp, document, node, ivycp.getConf().getAttributes());
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
DOMSource source = new DOMSource(document);
transformer.transform(source, result);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (TransformerException e) {
if (e.getException() instanceof IOException) {
throw (IOException) e.getException();
}
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
}
}
private void writeCpEntries(IvyClasspathContainerImpl ivycp, Document document, Node node,
IClasspathEntry[] classpathEntries) {
if (classpathEntries == null) {
return;
}
Node cpEntriesNode = document.createElement(CPENTRIES);
node.appendChild(cpEntriesNode);
for (int i = 0; i < classpathEntries.length; i++) {
Node cpEntryNode = document.createElement(CPENTRY);
cpEntriesNode.appendChild(cpEntryNode);
int kind = classpathEntries[i].getEntryKind();
NamedNodeMap attributes = cpEntryNode.getAttributes();
Attr attr = document.createAttribute(KIND);
attr.setValue(Integer.toString(kind));
attributes.setNamedItem(attr);
attr = document.createAttribute(PATH);
attr.setValue(classpathEntries[i].getPath().toString());
attributes.setNamedItem(attr);
IPath source = classpathEntries[i].getSourceAttachmentPath();
if (source != null) {
attr = document.createAttribute(SOURCE);
attr.setValue(source.toString());
attributes.setNamedItem(attr);
}
writeAccessRules(ivycp, document, cpEntryNode, classpathEntries[i].getAccessRules());
writeCpAttr(ivycp, document, cpEntryNode, classpathEntries[i].getExtraAttributes());
}
}
private void writeAccessRules(IvyClasspathContainerImpl ivycp, Document document, Node cpEntryNode,
IAccessRule[] accessRules) {
if (accessRules == null) {
return;
}
Node accessRulesNode = document.createElement(ACCESS_RULES);
cpEntryNode.appendChild(accessRulesNode);
for (int i = 0; i < accessRules.length; i++) {
Node accessRuleNode = document.createElement(RULE);
accessRulesNode.appendChild(accessRuleNode);
NamedNodeMap attributes = accessRuleNode.getAttributes();
Attr attr = document.createAttribute(PATTERN);
attr.setValue(accessRules[i].getPattern().toString());
attributes.setNamedItem(attr);
attr = document.createAttribute(KIND);
attr.setValue(Integer.toString(accessRules[i].getKind()));
attributes.setNamedItem(attr);
}
}
private void writeCpAttr(IvyClasspathContainerImpl ivycp, Document document, Node node,
IClasspathAttribute[] attrs) {
if (attrs == null) {
return;
}
Node cpAttrsNode = document.createElement(CPATTRS);
node.appendChild(cpAttrsNode);
for (int i = 0; i < attrs.length; i++) {
Node attrNode = document.createElement(ATTR);
cpAttrsNode.appendChild(attrNode);
NamedNodeMap attributes = attrNode.getAttributes();
Attr attr = document.createAttribute(NAME);
attr.setValue(attrs[i].getName());
attributes.setNamedItem(attr);
attr = document.createAttribute(VALUE);
attr.setValue(attrs[i].getValue());
attributes.setNamedItem(attr);
}
}
public Map/* <IPath, IvyClasspathContainer> */read(InputStream in) throws IOException,
SAXException {
try {
InputSource source = new InputSource(in);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
Document document = parser.parse(source);
NodeList elements = document.getElementsByTagName(IVYCP);
Map/* <IPath, IvyClasspathContainer> */ivycps = new HashMap();
int count = elements.getLength();
for (int i = 0; i != count; i++) {
Node node = elements.item(i);
NamedNodeMap attributes = node.getAttributes();
IPath path = new Path(getMandatoryAttribute(attributes, PATH, IVYCP));
IProject p = ResourcesPlugin.getWorkspace().getRoot()
.getProject(getMandatoryAttribute(attributes, PROJECT, IVYCP));
IJavaProject project = JavaCore.create(p);
IClasspathEntry[] cpEntries = new IClasspathEntry[0];
IClasspathAttribute[] cpAttributes = null;
NodeList children = node.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
Node item = children.item(j);
if (item.getNodeName().equals(CPENTRIES)) {
cpEntries = readCpEntries(item);
} else if (item.getNodeName().equals(CPATTRS)) {
cpAttributes = readCpAttr(item);
}
}
IvyClasspathContainerImpl ivycp = new IvyClasspathContainerImpl(project, path, cpEntries,
cpAttributes);
ivycps.put(path, ivycp);
}
return ivycps;
} catch (ParserConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private IClasspathEntry[] readCpEntries(Node cpEntries) throws IOException {
List/* <IClasspathEntry> */entries = new ArrayList();
NodeList children = cpEntries.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node item = children.item(i);
if (item.getNodeName().equals(CPENTRY)) {
IClasspathEntry cpEntry = readCpEntry(item);
if (cpEntry != null) {
entries.add(cpEntry);
}
}
}
return (IClasspathEntry[]) entries.toArray(new IClasspathEntry[entries.size()]);
}
private IClasspathEntry readCpEntry(Node cpEntryNode) throws IOException {
NamedNodeMap attributes = cpEntryNode.getAttributes();
int kind = Integer.parseInt(getMandatoryAttribute(attributes, KIND, CPENTRY));
IPath path = new Path(getMandatoryAttribute(attributes, PATH, CPENTRY));
String source = getAttribute(attributes, SOURCE);
IPath sourcePath = null;
if (source != null) {
sourcePath = new Path(source);
}
IClasspathAttribute[] cpAttrs = null;
IAccessRule[] accessRules = null;
NodeList children = cpEntryNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node item = children.item(i);
if (item.getNodeName().equals(CPATTRS)) {
cpAttrs = readCpAttr(item);
} else if (item.getNodeName().equals(ACCESS_RULES)) {
accessRules = readAccessRules(item);
}
}
IClasspathEntry entry;
switch (kind) {
case IClasspathEntry.CPE_PROJECT:
entry = JavaCore.newProjectEntry(path, accessRules, true, cpAttrs, true);
break;
case IClasspathEntry.CPE_LIBRARY:
IPath sources = ivyAttachementManager.getSourceAttachment(path, sourcePath);
IPath sourcesRoot = ivyAttachementManager.getSourceAttachmentRoot(path, sourcePath);
entry = JavaCore.newLibraryEntry(path, sources, sourcesRoot, accessRules, cpAttrs,
false);
break;
default:
return null;
}
return entry;
}
private IAccessRule[] readAccessRules(Node accessRulesNode) throws IOException {
List/* <IAccessRule> */rules = new ArrayList();
NodeList children = accessRulesNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node item = children.item(i);
if (item.getNodeName().equals(RULE)) {
IAccessRule rule = readAccessRule(item);
if (rule != null) {
rules.add(rule);
}
}
}
return (IAccessRule[]) rules.toArray(new IAccessRule[rules.size()]);
}
private IAccessRule readAccessRule(Node ruleNode) throws IOException {
NamedNodeMap attributes = ruleNode.getAttributes();
int kind = Integer.parseInt(getMandatoryAttribute(attributes, KIND, RULE));
IPath pattern = new Path(getMandatoryAttribute(attributes, PATTERN, RULE));
return JavaCore.newAccessRule(pattern, kind);
}
private IClasspathAttribute[] readCpAttr(Node cpAttrsNode) throws IOException {
List/* <IClasspathAttribute> */attrs = new ArrayList();
NodeList children = cpAttrsNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node item = children.item(i);
if (item.getNodeName().equals(ATTR)) {
IClasspathAttribute attr = readAttr(item);
if (attr != null) {
attrs.add(attr);
}
}
}
return (IClasspathAttribute[]) attrs.toArray(new IClasspathAttribute[attrs.size()]);
}
private IClasspathAttribute readAttr(Node attrNode) throws IOException {
NamedNodeMap attributes = attrNode.getAttributes();
String name = getMandatoryAttribute(attributes, NAME, ATTR);
String value = getMandatoryAttribute(attributes, VALUE, ATTR);
return JavaCore.newClasspathAttribute(name, value);
}
private String getMandatoryAttribute(NamedNodeMap attributes, String name, String owner)
throws IOException {
String att = getAttribute(attributes, name);
if (att == null) {
throw new IOException("Incorrect saved classpath: no '" + name + "' attribute on '"
+ name + "'");
}
return att;
}
private String getAttribute(NamedNodeMap attributes, String name) throws IOException {
Node node = attributes.getNamedItem(name);
if (node == null) {
return null;
}
return node.getNodeValue();
}
}