/******************************************************************************* * Copyright (c) 2000, 2017 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.dltk.internal.core; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Path; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IAccessRule; import org.eclipse.dltk.core.IBuildpathAttribute; import org.eclipse.dltk.core.IBuildpathEntry; import org.eclipse.dltk.internal.core.util.Messages; 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; /** * Internal model element to represent a user library and code to serialize / * deserialize. */ public class UserLibrary { private static final String CURRENT_VERSION = "1"; //$NON-NLS-1$ private static final String TAG_VERSION = "version"; //$NON-NLS-1$ private static final String TAG_USERLIBRARY = "userlibrary"; //$NON-NLS-1$ private static final String TAG_PATH = "path"; //$NON-NLS-1$ private static final String TAG_ARCHIVE = "archive"; //$NON-NLS-1$ private static final String TAG_SYSTEMLIBRARY = "systemlibrary"; //$NON-NLS-1$ private static final String ATTRIBUTE_PREFIX = "__attribute__"; //$NON-NLS-1$ private boolean isSystemLibrary; private IBuildpathEntry[] entries; private Map<String, String> attributes; public UserLibrary(IBuildpathEntry[] entries, boolean isSystemLibrary) { this(entries, isSystemLibrary, null); } public UserLibrary(IBuildpathEntry[] entries, boolean isSystemLibrary, Map<String, String> attributes) { Assert.isNotNull(entries); this.entries = entries; this.isSystemLibrary = isSystemLibrary; this.attributes = new HashMap<>(); if (attributes != null) { this.attributes.putAll(attributes); } } public IBuildpathEntry[] getEntries() { return this.entries; } public boolean isSystemLibrary() { return this.isSystemLibrary; } public String getAttribute(String name) { return attributes.get(name); } public Map<String, String> getAttributes() { return attributes; } @Override public boolean equals(Object obj) { if (obj != null && obj.getClass() == getClass()) { UserLibrary other = (UserLibrary) obj; if (this.entries.length == other.entries.length && this.isSystemLibrary == other.isSystemLibrary && attributes.size() == other.attributes.size()) { if (!Arrays.equals(this.entries, other.entries)) { return false; } if (!this.attributes.equals(other.attributes)) { return false; } return true; } } return false; } @Override public int hashCode() { int hashCode = 0; if (this.isSystemLibrary()) { hashCode++; } for (int i = 0; i < this.entries.length; i++) { hashCode = hashCode * 17 + this.entries[i].hashCode(); } return hashCode; } public static String serialize(IBuildpathEntry[] entries, boolean isSystemLibrary) throws IOException { return serialize(entries, isSystemLibrary, null); } public static String serialize(IBuildpathEntry[] entries, boolean isSystemLibrary, Map<String, String> attributes) throws IOException { ByteArrayOutputStream s = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$ XMLWriter xmlWriter = new XMLWriter(writer, null/* * use the workspace line delimiter */, true/* * print XML version */); HashMap<String, String> library = new HashMap<>(); library.put(TAG_VERSION, String.valueOf(CURRENT_VERSION)); library.put(TAG_SYSTEMLIBRARY, String.valueOf(isSystemLibrary)); if (attributes != null) { for (String key : attributes.keySet()) { library.put(ATTRIBUTE_PREFIX + key, attributes.get(key)); } } xmlWriter.printTag(TAG_USERLIBRARY, library, true, true, false); for (int i = 0, length = entries.length; i < length; ++i) { BuildpathEntry cpEntry = (BuildpathEntry) entries[i]; HashMap<String, String> archive = new HashMap<>(); archive.put(TAG_PATH, cpEntry.getPath().toString()); boolean hasExtraAttributes = cpEntry.extraAttributes != null && cpEntry.extraAttributes.length != 0; boolean hasRestrictions = cpEntry.getAccessRuleSet() != null; // access // rule // set // is // null // if // no // access // rules xmlWriter.printTag(TAG_ARCHIVE, archive, true, true, !(hasExtraAttributes || hasRestrictions)); // write extra attributes if necessary if (hasExtraAttributes) { cpEntry.encodeExtraAttributes(xmlWriter, true, true); } // write extra attributes and restriction if necessary if (hasRestrictions) { cpEntry.encodeAccessRules(xmlWriter, true, true); } // write archive end tag if necessary if (hasExtraAttributes || hasRestrictions) { xmlWriter.endTag(TAG_ARCHIVE, true/* insert tab */, true/* * insert new line */); } } xmlWriter.endTag(TAG_USERLIBRARY, true/* insert tab */, true/* * insert new line */); writer.flush(); writer.close(); return s.toString("UTF8");//$NON-NLS-1$ } public static UserLibrary createFromString(Reader reader) throws IOException { Element cpElement; try { DocumentBuilder parser = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); cpElement = parser.parse(new InputSource(reader)) .getDocumentElement(); } catch (SAXException e) { throw new IOException(Messages.file_badFormat); } catch (ParserConfigurationException e) { throw new IOException(Messages.file_badFormat); } finally { reader.close(); } if (!cpElement.getNodeName().equalsIgnoreCase(TAG_USERLIBRARY)) { throw new IOException(Messages.file_badFormat); } // String version= cpElement.getAttribute(TAG_VERSION); // in case we update the format: add code to read older versions boolean isSystem = Boolean .valueOf(cpElement.getAttribute(TAG_SYSTEMLIBRARY)) .booleanValue(); Map<String, String> attributes = new HashMap<>(); for (int i = 0; i < cpElement.getAttributes().getLength(); i++) { Node node = cpElement.getAttributes().item(i); if (node.getNodeName().startsWith(ATTRIBUTE_PREFIX)) { String name = node.getNodeName() .substring(ATTRIBUTE_PREFIX.length()); attributes.put(name, node.getNodeValue()); } } NodeList list = cpElement.getChildNodes(); int length = list.getLength(); ArrayList<IBuildpathEntry> res = new ArrayList<>(length); for (int i = 0; i < length; ++i) { Node node = list.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; if (element.getNodeName().equals(TAG_ARCHIVE)) { String path = element.getAttribute(TAG_PATH); NodeList children = element.getElementsByTagName("*"); //$NON-NLS-1$ boolean[] foundChildren = new boolean[children.getLength()]; NodeList attributeList = BuildpathEntry.getChildAttributes( BuildpathEntry.TAG_ATTRIBUTES, children, foundChildren); IBuildpathAttribute[] extraAttributes = BuildpathEntry .decodeExtraAttributes(attributeList); attributeList = BuildpathEntry.getChildAttributes( BuildpathEntry.TAG_ACCESS_RULES, children, foundChildren); IAccessRule[] accessRules = BuildpathEntry .decodeAccessRules(attributeList); IBuildpathEntry entry = DLTKCore.newLibraryEntry( Path.fromPortableString(path), accessRules, extraAttributes, false, true); res.add(entry); } } } IBuildpathEntry[] entries = res .toArray(new IBuildpathEntry[res.size()]); return new UserLibrary(entries, isSystem, attributes); } @Override public String toString() { if (this.entries == null) return "null"; //$NON-NLS-1$ StringBuffer buffer = new StringBuffer(); int length = this.entries.length; for (int i = 0; i < length; i++) { buffer.append(this.entries[i].toString() + '\n'); } return buffer.toString(); } }