/******************************************************************************* * 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); } }