blob: 24a6f32533919dfa8c235ed8c53a4af7a3f3d8d3 [file] [log] [blame]
/*
* 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.uima.ruta.ide.core.packages;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.commons.io.IOUtils;
import org.apache.uima.internal.util.XMLUtils;
import org.apache.uima.ruta.ide.RutaIdeCorePlugin;
import org.apache.uima.ruta.ide.core.packages.DLTKRutaHelper.RutaPackage;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.launching.IInterpreterInstall;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This class persistently holds all required information for specified interpreter package to path
* associations.
*/
public class PackagesManager {
private static final String DEPENDENCY_TAG = "dependency"; //$NON-NLS-1$
private static final String INTERPRETER_TAG = "interpreter"; //$NON-NLS-1$
private static final String VALUE_ATTR = "value"; //$NON-NLS-1$
private static final String PACKAGES_FILE = "packages.txt"; //$NON-NLS-1$
private static final String PACKAGES_TAG = "packages"; //$NON-NLS-1$
private static final String PACKAGE_TAG = "package"; //$NON-NLS-1$
private static final String INTERPRETER_ATTR = INTERPRETER_TAG;
private static final String NAME_ATTR = "name"; //$NON-NLS-1$
private static final String PATH_TAG = "path"; //$NON-NLS-1$
private static PackagesManager manager;
/**
* Contains association of PackageKey to PackageInformation
*/
private Map packages = new HashMap();
/**
* Contains set of interpreter to list of packages association.
*/
private Map interpreterToPackages = new HashMap();
private Map packsWithDeps = new HashMap();
public static synchronized PackagesManager getInstance() {
if (manager == null) {
manager = new PackagesManager();
}
return manager;
}
private PackagesManager() {
initialize();
}
private static class PackageKey {
private String packageName;
private String interpreterPath;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((interpreterPath == null) ? 0 : interpreterPath.hashCode());
result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PackageKey other = (PackageKey) obj;
if (interpreterPath == null) {
if (other.interpreterPath != null)
return false;
} else if (!interpreterPath.equals(other.interpreterPath))
return false;
if (packageName == null) {
if (other.packageName != null)
return false;
} else if (!packageName.equals(other.packageName))
return false;
return true;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getInterpreterPath() {
return interpreterPath;
}
public void setInterpreterPath(String interpreterPath) {
this.interpreterPath = interpreterPath;
}
}
public static class PackageInformation {
private final Set paths = new HashSet();
private final Set dependencies = new HashSet();
public Set getPaths() {
return paths;
}
public Set getDependencies() {
return dependencies;
}
}
private void initialize() {
IPath packagesPath = RutaIdeCorePlugin.getDefault().getStateLocation().append(PACKAGES_FILE);
File packagesFile = packagesPath.toFile();
if (packagesFile.exists()) {
try {
DocumentBuilderFactory documentBuilderFactory = XMLUtils.createDocumentBuilderFactory();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(packagesFile),
2048)) {
Document document = builder.parse(bis);
populate(document.getDocumentElement());
}
} catch (SAXException | IOException | ParserConfigurationException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
}
private void save() {
IPath packagesPath = RutaIdeCorePlugin.getDefault().getStateLocation().append(PACKAGES_FILE);
File packagesFile = packagesPath.toFile();
OutputStream os = null;
try {
DocumentBuilderFactory documentBuilderFactory = XMLUtils.createDocumentBuilderFactory();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
Document document = builder.newDocument();
save(document);
os = new BufferedOutputStream(new FileOutputStream(packagesFile, false), 2048);
TransformerFactory transformerFactory = XMLUtils.createTransformerFactory();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
DOMSource source = new DOMSource(document);
StreamResult outputTarget = new StreamResult(os);
transformer.transform(source, outputTarget);
} catch (IOException | TransformerException | ParserConfigurationException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} finally {
IOUtils.closeQuietly(os);
}
}
private synchronized void save(Document doc) {
Element packagesElement = doc.createElement(PACKAGES_TAG);
doc.appendChild(packagesElement);
for (Iterator iterator = this.packages.keySet().iterator(); iterator.hasNext();) {
PackageKey key = (PackageKey) iterator.next();
Element packageElement = doc.createElement(PACKAGE_TAG);
packageElement.setAttribute(NAME_ATTR, key.getPackageName());
packageElement.setAttribute(INTERPRETER_ATTR, key.getInterpreterPath());
PackageInformation info = (PackageInformation) this.packages.get(key);
Set paths = info.getPaths();
for (Iterator iterator2 = paths.iterator(); iterator2.hasNext();) {
IPath path = (IPath) iterator2.next();
Element pathElement = doc.createElement(PATH_TAG);
pathElement.setAttribute(VALUE_ATTR, path.toOSString());
packageElement.appendChild(pathElement);
}
Set deps = info.getDependencies();
for (Iterator iterator2 = deps.iterator(); iterator2.hasNext();) {
String pkgName = (String) iterator2.next();
Element pkgElement = doc.createElement(DEPENDENCY_TAG);
pkgElement.setAttribute(NAME_ATTR, pkgName);
packageElement.appendChild(pkgElement);
}
packagesElement.appendChild(packageElement);
}
for (Iterator iterator = this.interpreterToPackages.keySet().iterator(); iterator.hasNext();) {
String interpreter = (String) iterator.next();
Element interpreterElement = doc.createElement(INTERPRETER_TAG);
interpreterElement.setAttribute(NAME_ATTR, interpreter);
Set pkgs = (Set) this.interpreterToPackages.get(interpreter);
for (Iterator iterator2 = pkgs.iterator(); iterator2.hasNext();) {
String pkgName = (String) iterator2.next();
Element pathElement = doc.createElement(PACKAGE_TAG);
pathElement.setAttribute(VALUE_ATTR, pkgName);
interpreterElement.appendChild(pathElement);
}
packagesElement.appendChild(interpreterElement);
}
}
private synchronized void populate(Element documentElement) {
NodeList childNodes = documentElement.getChildNodes();
int length = childNodes.getLength();
for (int i = 0; i < length; i++) {
Node child = childNodes.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (child.getNodeName().equalsIgnoreCase(PACKAGE_TAG)) {
Element e = (Element) child;
String packageName = e.getAttribute(NAME_ATTR);
String interpreter = e.getAttribute(INTERPRETER_ATTR);
PackageInformation packageInfo = new PackageInformation();
NodeList childrens = e.getChildNodes();
for (int j = 0; j < childrens.getLength(); j++) {
Node path = childrens.item(j);
if (path.getNodeType() == Node.ELEMENT_NODE) {
if (path.getNodeName().equalsIgnoreCase(PATH_TAG)) {
String pathValue = ((Element) path).getAttribute(VALUE_ATTR);
packageInfo.getPaths().add(new Path(pathValue));
} else if (path.getNodeName().equalsIgnoreCase(DEPENDENCY_TAG)) {
String pkgName = ((Element) path).getAttribute(NAME_ATTR);
packageInfo.getDependencies().add(pkgName);
}
}
}
this.packages.put(makeKey(packageName, interpreter), packageInfo);
} else if (child.getNodeName().equalsIgnoreCase(INTERPRETER_TAG)) {
Element e = (Element) child;
String interpreter = e.getAttribute(NAME_ATTR);
NodeList paths = e.getChildNodes();
Set packagesSet = new HashSet();
for (int j = 0; j < paths.getLength(); j++) {
Node packageNode = paths.item(j);
if (packageNode.getNodeType() == Node.ELEMENT_NODE) {
if (packageNode.getNodeName().equalsIgnoreCase(PACKAGE_TAG)) {
String packageNameValue = ((Element) packageNode).getAttribute(VALUE_ATTR);
packagesSet.add(packageNameValue);
}
}
}
this.interpreterToPackages.put(interpreter, packagesSet);
}
}
}
}
private PackageKey makeKey(String packageName, String interpreter) {
PackageKey key = new PackageKey();
key.setPackageName(packageName);
key.setInterpreterPath(interpreter);
return key;
}
public synchronized IPath[] getPathsForPackage(IInterpreterInstall install, String packageName) {
PackageKey key = makeKey(packageName, getInterpreterKey(install));
if (this.packages.containsKey(key)) {
PackageInformation info = (PackageInformation) this.packages.get(key);
Set els = info.getPaths();
return (IPath[]) els.toArray(new IPath[els.size()]);
}
// Retrieve paths from interpreter with all dependencies.
RutaPackage[] srcs = DLTKRutaHelper.getSrcs(install.getExecEnvironment(),
install.getInstallLocation(), install.getEnvironmentVariables(), packageName);
PackageInformation resultInfo = null;
for (int i = 0; i < srcs.length; i++) {
Set paths2 = srcs[i].getPaths();
PackageKey okey = makeKey(srcs[i].getName(), getInterpreterKey(install));
PackageInformation info;
if (this.packages.containsKey(okey)) {
info = (PackageInformation) this.packages.get(okey);
} else {
info = new PackageInformation();
}
info.getPaths().addAll(paths2);
info.getDependencies().addAll(srcs[i].getDependencies());
this.packages.put(okey, info);
if (okey.equals(key)) {
resultInfo = info;
}
}
// Follow all dependencies
if (resultInfo == null) {
this.packages.put(key, new PackageInformation());
return new IPath[0];
}
Set resultPaths = new HashSet();
resultPaths.addAll(resultInfo.getPaths());
save();
return (IPath[]) resultPaths.toArray(new IPath[resultPaths.size()]);
}
public synchronized Map getDependencies(String pkgName, IInterpreterInstall install) {
Set checkedPackages = new HashSet();
Map packagesSet = new HashMap();
PackageKey key = makeKey(pkgName, install);
PackageInformation info = (PackageInformation) this.packages.get(key);
if (info != null) {
traverseDependencies(packagesSet, checkedPackages, info, install);
}
return packagesSet;
}
private PackageKey makeKey(String pkgName, IInterpreterInstall install) {
return makeKey(pkgName, getInterpreterKey(install));
}
private synchronized void traverseDependencies(Map packagesSet, Set checkedPackages,
PackageInformation resultInfo, IInterpreterInstall install) {
Set dependencies = resultInfo.getDependencies();
for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
String pkgName = (String) iterator.next();
if (!checkedPackages.contains(pkgName)) {
checkedPackages.add(pkgName);
PackageKey pkgKey = makeKey(pkgName, getInterpreterKey(install));
if (this.packages.containsKey(pkgKey)) {
PackageInformation depInfo = (PackageInformation) this.packages.get(pkgKey);
packagesSet.put(pkgName, depInfo);
traverseDependencies(packagesSet, checkedPackages, depInfo, install);
}
}
}
}
public synchronized Set getPackageNames(IInterpreterInstall install) {
String key = getInterpreterKey(install);
if (this.interpreterToPackages.containsKey(key)) {
Set set = (Set) this.interpreterToPackages.get(key);
return set;
}
// Evaluate
Set packs = DLTKRutaHelper.getPackages(install);
this.interpreterToPackages.put(key, packs);
save();
return packs;
}
private String getInterpreterKey(IInterpreterInstall install) {
if (install == null) {
return "";
}
return install.getInstallLocation().toOSString() + ":" //$NON-NLS-1$
+ install.getEnvironment().getId();
}
private String getInterpreterProjectKey(IInterpreterInstall install, String projectName) {
return "internal|||" + projectName + "|||" //$NON-NLS-1$ //$NON-NLS-2$
+ getInterpreterKey(install);
}
public Set getInternalPackageNames(IInterpreterInstall install, IScriptProject project) {
return getInternalPackageNames(install, project.getElementName());
}
public synchronized Set getInternalPackageNames(IInterpreterInstall install, IProject project) {
return getInternalPackageNames(install, project.getName());
}
public synchronized Set getInternalPackageNames(IInterpreterInstall install, String projectName) {
final String key = getInterpreterProjectKey(install, projectName);
if (this.interpreterToPackages.containsKey(key)) {
return (Set) this.interpreterToPackages.get(key);
}
return Collections.EMPTY_SET;
}
public synchronized void setInternalPackageNames(IInterpreterInstall install,
IScriptProject project, Set names) {
String key = getInterpreterProjectKey(install, project.getElementName());
// TODO compare and save only if there are changes
this.interpreterToPackages.put(key, new HashSet(names));
save();
}
public synchronized IPath[] getPathsForPackages(IInterpreterInstall install,
Set packagesInBuild) {
StringBuffer buf = new StringBuffer();
String[] pkgs = (String[]) packagesInBuild.toArray(new String[packagesInBuild.size()]);
for (int i = 0; i < pkgs.length; i++) {
buf.append(pkgs[i]).append(" "); //$NON-NLS-1$
}
PackageKey key = makeKey(buf.toString(), getInterpreterKey(install));
if (this.packages.containsKey(key)) {
PackageInformation info = (PackageInformation) this.packages.get(key);
Set paths = info.getPaths();
return (IPath[]) paths.toArray(new IPath[paths.size()]);
}
// Retrieve paths from interpreter with all dependencies.
RutaPackage[] srcs = DLTKRutaHelper.getSrcs(install.getExecEnvironment(),
install.getInstallLocation(), install.getEnvironmentVariables(), buf.toString());
Set result = new HashSet();
if (srcs == null) {
return new IPath[0];
}
for (int i = 0; i < srcs.length; i++) {
Set paths2 = srcs[i].getPaths();
PackageKey okey = makeKey(srcs[i].getName(), getInterpreterKey(install));
PackageInformation info = null;
if (this.packages.containsKey(okey)) {
info = (PackageInformation) this.packages.get(okey);
} else {
info = new PackageInformation();
}
result.addAll(paths2);
info.getPaths().addAll(paths2);
info.getDependencies().addAll(srcs[i].getDependencies());
this.packages.put(okey, info);
}
PackageInformation info = new PackageInformation();
info.getPaths().addAll(result);
this.packages.put(key, info);
for (int i = 0; i < pkgs.length; i++) {
PackageKey lkey = makeKey(pkgs[i], getInterpreterKey(install));
if (!this.packages.containsKey(lkey)) {
this.packages.put(lkey, new PackageInformation());
}
}
save();
return (IPath[]) result.toArray(new IPath[result.size()]);
}
public IPath[] getAllPaths(String pkgName, IInterpreterInstall install) {
Set result = new HashSet();
IPath[] paths = this.getPathsForPackage(install, pkgName);
result.addAll(Arrays.asList(paths));
Map dependencies = this.getDependencies(pkgName, install);
for (Iterator iterator = dependencies.keySet().iterator(); iterator.hasNext();) {
String packageName = (String) iterator.next();
PackageInformation info = (PackageInformation) dependencies.get(packageName);
result.addAll(info.getPaths());
}
return (IPath[]) result.toArray(new IPath[result.size()]);
}
public synchronized void removeInterprterInfo(IInterpreterInstall install) {
// Remove interpreter to packages set
String interpreterPath = getInterpreterKey(install);
this.interpreterToPackages.remove(interpreterPath);
// Remove all values stored for interpreter packages
for (Iterator iterator = this.packages.keySet().iterator(); iterator.hasNext();) {
PackageKey key = (PackageKey) iterator.next();
String path = key.getInterpreterPath();
if (path.equals(interpreterPath)) {
iterator.remove();
}
}
save();
}
/**
* Clears all cached information.
*/
public synchronized void clearCache() {
this.interpreterToPackages.clear();
this.packages.clear();
this.packsWithDeps.clear();
save();
}
public IPath[] getPathsForPackageWithDeps(IInterpreterInstall install, String name) {
Set result = new HashSet();
IPath[] paths = this.getPathsForPackage(install, name);
result.addAll(Arrays.asList(paths));
Map dependencies = getDependencies(name, install);
for (Iterator iterator = dependencies.keySet().iterator(); iterator.hasNext();) {
String pkgName = (String) iterator.next();
result.addAll(Arrays.asList(getPathsForPackage(install, pkgName)));
}
return (IPath[]) result.toArray(new IPath[result.size()]);
}
public IPath[] getPathsForPackagesWithDeps(IInterpreterInstall install, Set packagesSet) {
String pkey = makePKey(packagesSet);
if (this.packsWithDeps.containsKey(pkey)) {
return (IPath[]) this.packsWithDeps.get(pkey);
}
Set result = new HashSet();
IPath[] paths = this.getPathsForPackages(install, packagesSet);
result.addAll(Arrays.asList(paths));
for (Iterator jiterator = packagesSet.iterator(); jiterator.hasNext();) {
String name = (String) jiterator.next();
Map dependencies = getDependencies(name, install);
for (Iterator iterator = dependencies.keySet().iterator(); iterator.hasNext();) {
String pkgName = (String) iterator.next();
result.addAll(Arrays.asList(getPathsForPackage(install, pkgName)));
}
}
IPath[] array = (IPath[]) result.toArray(new IPath[result.size()]);
this.packsWithDeps.put(pkey, array);
return array;
}
private String makePKey(Set packagesSet) {
StringBuffer buffer = new StringBuffer();
List l = new ArrayList();
l.addAll(packagesSet);
Collections.sort(l);
for (Iterator iterator = l.iterator(); iterator.hasNext();) {
String object = (String) iterator.next();
buffer.append(object);
}
return buffer.toString();
}
}