blob: 5111b42d14c9771db9f3ea36a48bdaa1ffef57cb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2017 xored software, Inc. 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:
* xored software, Inc. - initial API and Implementation (Andrei Sobolev)
*******************************************************************************/
package org.eclipse.dltk.itcl.internal.core.classes;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
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.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.itcl.internal.core.IncrTCLPlugin;
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 manage per project IncrTcl class name database. Hold classes for
* all projects in workspace.
*/
public class IncrTclClassesManager implements IResourceChangeListener {
private static final String CLASSES_TAG = "classes";
private static final String PATH_ITCL_CLASSES = ".itcl_cl";
private static final String CLASS_TAG = "class";
private static IncrTclClassesManager sInstance;
private boolean dirty = false;
private int changes = 0;
private Set<String> classNames = new HashSet<>();
public void clean() {
this.classNames.clear();
}
public void add(String name) {
classNames.add(name);
dirty = true;
changes++;
if (changes > 10) {
changes = 0;
save();
}
}
public void remove(String name) {
classNames.remove(name);
}
public boolean isClass(String name) {
return classNames.contains(name);
}
public void startup() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
load();
}
private synchronized void load() {
IPath packages = IncrTCLPlugin.getDefault().getStateLocation().append(PATH_ITCL_CLASSES);
File packagesFile = packages.toFile();
if (packagesFile.exists()) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
BufferedInputStream stream = new BufferedInputStream(new FileInputStream(packagesFile));
Document document = builder.parse(stream);
stream.close();
populate(document.getDocumentElement());
} catch (ParserConfigurationException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (SAXException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
dirty = false;
}
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(CLASS_TAG)) {
Element el = (Element) child;
String value = el.getAttribute("value");
if (value.trim().length() > 0) {
add(value);
}
}
}
}
}
private synchronized void save() {
if (!dirty) {
return;
}
dirty = false;
IPath packages = IncrTCLPlugin.getDefault().getStateLocation().append(PATH_ITCL_CLASSES);
File packagesFile = packages.toFile();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
save(document);
FileOutputStream fos = new FileOutputStream(packagesFile, false);
BufferedOutputStream bos = new BufferedOutputStream(fos, 2048);
TransformerFactory serFactory = TransformerFactory.newInstance();
Transformer transformer = serFactory.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(bos);
transformer.transform(source, outputTarget);
bos.close();
fos.close();
} catch (ParserConfigurationException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
} catch (TransformerException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
private void save(Document doc) {
Element packages = doc.createElement(CLASSES_TAG); // $NON-NLS-1$
doc.appendChild(packages);
for (Iterator<String> iterator = this.classNames.iterator(); iterator.hasNext();) {
String value = iterator.next();
Element el = doc.createElement(CLASS_TAG);
el.setAttribute("value", value);
packages.appendChild(el);
}
}
public void shutdown() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
save();
}
public static IncrTclClassesManager getDefault() {
if (sInstance == null) {
sInstance = new IncrTclClassesManager();
}
return sInstance;
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
// TODO Auto-generated method stub
}
public boolean isClass(IProject project, String className) {
return this.classNames.contains(className);
}
}