All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.core.internal.registry.TableWriter Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2004, 2016 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.core.internal.registry;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.spi.RegistryContributor;

public class TableWriter {
	private static final byte fileError = 0;

	File mainDataFile;
	File extraDataFile;
	File tableFile;
	File contributionsFile;
	File contributorsFile;
	File namespacesFile;
	File orphansFile;

	void setMainDataFile(File main) {
		mainDataFile = main;
	}

	void setExtraDataFile(File extra) {
		extraDataFile = extra;
	}

	void setTableFile(File table) {
		tableFile = table;
	}

	void setContributionsFile(File fileName) {
		contributionsFile = fileName;
	}

	void setContributorsFile(File fileName) {
		contributorsFile = fileName;
	}

	void setNamespacesFile(File fileName) {
		namespacesFile = fileName;
	}

	void setOrphansFile(File orphan) {
		orphansFile = orphan;
	}

	DataOutputStream mainOutput;
	DataOutputStream extraOutput;
	FileOutputStream mainFileOutput = null;
	FileOutputStream extraFileOutput = null;

	private OffsetTable offsets;

	private final ExtensionRegistry registry;
	private RegistryObjectManager objectManager;

	public TableWriter(ExtensionRegistry registry) {
		this.registry = registry;
	}

	private int getExtraDataPosition() {
		return extraOutput.size();
	}

	public boolean saveCache(RegistryObjectManager objectManager, long timestamp) {
		this.objectManager = objectManager;
		try {
			if (!openFiles())
				return false;
			try {
				saveExtensionRegistry(timestamp);
			} catch (IOException io) {
				log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheWriteProblems, io));
				return false;
			}
		} finally {
			closeFiles();
		}
		return true;
	}

	private boolean openFiles() {
		try {
			mainFileOutput = new FileOutputStream(mainDataFile);
			mainOutput = new DataOutputStream(new BufferedOutputStream(mainFileOutput));
			extraFileOutput = new FileOutputStream(extraDataFile);
			extraOutput = new DataOutputStream(new BufferedOutputStream(extraFileOutput));
		} catch (FileNotFoundException e) {
			if (mainFileOutput != null)
				try {
					mainFileOutput.close();
				} catch (IOException e1) {
					//Ignore
				}

			log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_unableToCreateCache, e));
			return false;
		}
		return true;
	}

	private void closeFiles() {
		try {
			if (mainOutput != null) {
				mainOutput.flush();
				if (mainFileOutput.getFD().valid()) {
					mainFileOutput.getFD().sync();
				}
				mainOutput.close();
			}
		} catch (IOException e) {
			log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheWriteProblems, e));
			e.printStackTrace();
		}
		try {
			if (extraOutput != null) {
				extraOutput.flush();
				if (extraFileOutput.getFD().valid()) {
					extraFileOutput.getFD().sync();
				}
				extraOutput.close();
			}
		} catch (IOException e) {
			log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, fileError, RegistryMessages.meta_registryCacheWriteProblems, e));
			e.printStackTrace();
		}
	}

	private void saveExtensionRegistry(long timestamp) throws IOException {
		ExtensionPointHandle[] points = objectManager.getExtensionPointsHandles();
		offsets = new OffsetTable(objectManager.getNextId());
		for (ExtensionPointHandle point : points) {
			saveExtensionPoint(point);
		}
		saveOrphans();
		saveContributions(objectManager.getContributions());
		saveContributors(objectManager.getContributors());
		saveNamespaces(objectManager.getNamespacesIndex());
		closeFiles(); //Close the files here so we can write the appropriate size information in the table file.
		saveTables(timestamp); //Write the table last so if that is something went wrong we can know
	}

	private void saveContributions(KeyedHashSet[] contributions) throws IOException {
		try (FileOutputStream fosNamespace = new FileOutputStream(contributionsFile);
				DataOutputStream outputNamespace = new DataOutputStream(new BufferedOutputStream(fosNamespace))) {
			KeyedElement[] newElements = contributions[0].elements();
			KeyedElement[] formerElements = contributions[1].elements();

			// get count of contributions that will be cached
			int cacheSize = 0;
			for (KeyedElement newElement : newElements) {
				if (((Contribution) newElement).shouldPersist()) {
					cacheSize++;
				}
			}
			for (KeyedElement formerElement : formerElements) {
				if (((Contribution) formerElement).shouldPersist()) {
					cacheSize++;
				}
			}
			outputNamespace.writeInt(cacheSize);

			for (KeyedElement newElement : newElements) {
				Contribution element = (Contribution) newElement;
				if (element.shouldPersist()) {
					writeStringOrNull(element.getContributorId(), outputNamespace);
					saveArray(filterContributionChildren(element), outputNamespace);
				}
			}
			for (KeyedElement formerElement : formerElements) {
				Contribution element = (Contribution) formerElement;
				if (element.shouldPersist()) {
					writeStringOrNull(element.getContributorId(), outputNamespace);
					saveArray(filterContributionChildren(element), outputNamespace);
				}
			}
			outputNamespace.flush();
			fosNamespace.getFD().sync();
		}
	}

	// Contribution has raw children in a unique format that combines extensions and extension points.
	// To filter, need to dis-assmeble, filter, and then re-assemble its raw children
	private int[] filterContributionChildren(Contribution element) {
		int[] extensionPoints = filter(element.getExtensionPoints());
		int[] extensions = filter(element.getExtensions());
		int[] filteredRawChildren = new int[2 + extensionPoints.length + extensions.length];
		System.arraycopy(extensionPoints, 0, filteredRawChildren, 2, extensionPoints.length);
		System.arraycopy(extensions, 0, filteredRawChildren, 2 + extensionPoints.length, extensions.length);
		filteredRawChildren[Contribution.EXTENSION_POINT] = extensionPoints.length;
		filteredRawChildren[Contribution.EXTENSION] = extensions.length;
		return filteredRawChildren;
	}

	private void saveNamespaces(KeyedHashSet namespacesIndex) throws IOException {
		try (FileOutputStream fosNamespace = new FileOutputStream(namespacesFile);
				DataOutputStream outputNamespace = new DataOutputStream(new BufferedOutputStream(fosNamespace))) {
			KeyedElement[] elements = namespacesIndex.elements();

			KeyedElement[] cachedElements = new KeyedElement[elements.length];
			int cacheSize = 0;
			for (KeyedElement e : elements) {
				RegistryIndexElement element = (RegistryIndexElement) e;
				int[] extensionPoints = filter(element.getExtensionPoints());
				int[] extensions = filter(element.getExtensions());
				if (extensionPoints.length == 0 && extensions.length == 0)
					continue;
				RegistryIndexElement cachedElement = new RegistryIndexElement((String) element.getKey(),
						extensionPoints, extensions);
				cachedElements[cacheSize] = cachedElement;
				cacheSize++;
			}

			outputNamespace.writeInt(cacheSize);
			for (int i = 0; i < cacheSize; i++) {
				RegistryIndexElement element = (RegistryIndexElement) cachedElements[i];
				writeStringOrNull((String) element.getKey(), outputNamespace);
				saveArray(element.getExtensionPoints(), outputNamespace); // it was pre-filtered as we counted the
																			// number of
																			// elements
				saveArray(element.getExtensions(), outputNamespace); // it was pre-filtered as we counted the number of
																		// elements
			}
			outputNamespace.flush();
			fosNamespace.getFD().sync();
		}
	}

	private void saveContributors(HashMap contributors) throws IOException {
		try (FileOutputStream fosContributors = new FileOutputStream(contributorsFile);
				DataOutputStream outputContributors = new DataOutputStream(new BufferedOutputStream(fosContributors))) {

			Collection entries = contributors.values();
			outputContributors.writeInt(entries.size());

			for (Object entry : entries) {
				RegistryContributor contributor = (RegistryContributor) entry;
				writeStringOrNull(contributor.getActualId(), outputContributors);
				writeStringOrNull(contributor.getActualName(), outputContributors);
				writeStringOrNull(contributor.getId(), outputContributors);
				writeStringOrNull(contributor.getName(), outputContributors);
			}

			outputContributors.flush();
			fosContributors.getFD().sync();
			outputContributors.close();
		}
	}

	private void saveTables(long registryTimeStamp) throws IOException {
		try (FileOutputStream fosTable = new FileOutputStream(tableFile);
				DataOutputStream outputTable = new DataOutputStream(new BufferedOutputStream(fosTable))) {
			writeCacheHeader(outputTable, registryTimeStamp);
			outputTable.writeInt(objectManager.getNextId());
			offsets.save(outputTable);
			objectManager.getExtensionPoints().save(outputTable, objectManager); // uses writer to filter contents
			outputTable.flush();
			fosTable.getFD().sync();
		}
	}

	private void writeCacheHeader(DataOutputStream output, long registryTimeStamp) throws IOException {
		output.writeInt(TableReader.CACHE_VERSION);
		output.writeLong(registry.computeState());
		output.writeLong(registryTimeStamp);
		output.writeLong(mainDataFile.length());
		output.writeLong(extraDataFile.length());
		output.writeLong(contributionsFile.length());
		output.writeLong(contributorsFile.length());
		output.writeLong(namespacesFile.length());
		output.writeLong(orphansFile.length());
		output.writeUTF(RegistryProperties.getProperty(IRegistryConstants.PROP_OS, RegistryProperties.empty));
		output.writeUTF(RegistryProperties.getProperty(IRegistryConstants.PROP_WS, RegistryProperties.empty));
		output.writeUTF(RegistryProperties.getProperty(IRegistryConstants.PROP_NL, RegistryProperties.empty));
		output.writeBoolean(registry.isMultiLanguage());
	}

	private void saveArray(int[] array, DataOutputStream out) throws IOException {
		if (array == null) {
			out.writeInt(0);
			return;
		}
		out.writeInt(array.length);
		for (int element : array) {
			out.writeInt(element);
		}
	}

	private void saveExtensionPoint(ExtensionPointHandle xpt) throws IOException {
		if (!xpt.shouldPersist())
			return;
		//save the file position
		offsets.put(xpt.getId(), mainOutput.size());
		//save the extensionPoint
		mainOutput.writeInt(xpt.getId());
		saveArray(filter(xpt.getObject().getRawChildren()), mainOutput);
		mainOutput.writeInt(getExtraDataPosition());
		saveExtensionPointData(xpt);

		saveExtensions(xpt.getExtensions(), mainOutput);
	}

	private void saveExtension(ExtensionHandle ext, DataOutputStream outputStream) throws IOException {
		if (!ext.shouldPersist())
			return;
		offsets.put(ext.getId(), outputStream.size());
		outputStream.writeInt(ext.getId());
		writeStringOrNull(ext.getSimpleIdentifier(), outputStream);
		writeStringOrNull(ext.getNamespaceIdentifier(), outputStream);
		saveArray(filter(ext.getObject().getRawChildren()), outputStream);
		outputStream.writeInt(getExtraDataPosition());
		saveExtensionData(ext);
	}

	private void writeStringArray(String[] array, DataOutputStream outputStream) throws IOException {
		outputStream.writeInt(array == null ? 0 : array.length);
		for (int i = 0; i < (array == null ? 0 : array.length); i++) {
			writeStringOrNull(array[i], outputStream);
		}
	}

	private void writeStringArray(String[] array, int size, DataOutputStream outputStream) throws IOException {
		outputStream.writeInt(array == null ? 0 : size);
		if (array == null)
			return;
		for (int i = 0; i < size; i++) {
			writeStringOrNull(array[i], outputStream);
		}
	}

	//Save Configuration elements depth first
	private void saveConfigurationElement(ConfigurationElementHandle element, DataOutputStream outputStream, DataOutputStream extraOutputStream, int depth) throws IOException {
		if (!element.shouldPersist())
			return;
		DataOutputStream currentOutput = outputStream;
		if (depth > 2)
			currentOutput = extraOutputStream;

		offsets.put(element.getId(), currentOutput.size());

		currentOutput.writeInt(element.getId());
		ConfigurationElement actualCe = (ConfigurationElement) element.getObject();

		writeStringOrNull(actualCe.getContributorId(), currentOutput);
		writeStringOrNull(actualCe.getName(), currentOutput);
		currentOutput.writeInt(actualCe.parentId);
		currentOutput.writeByte(actualCe.parentType);
		currentOutput.writeInt(depth > 1 ? extraOutputStream.size() : -1);
		writeStringArray(actualCe.getPropertiesAndValue(), currentOutput);
		//save the children
		saveArray(filter(actualCe.getRawChildren()), currentOutput);

		if (actualCe instanceof ConfigurationElementMulti) {
			ConfigurationElementMulti multiCE = (ConfigurationElementMulti) actualCe;
			int NLs = multiCE.getNumCachedLocales();
			currentOutput.writeInt(NLs);
			if (NLs != 0) {
				writeStringArray(multiCE.getCachedLocales(), NLs, currentOutput);
				String[][] translated = multiCE.getCachedTranslations();
				for (int i = 0; i < NLs; i++) {
					writeStringArray(translated[i], currentOutput);
				}
			}
		}

		ConfigurationElementHandle[] childrenCEs = (ConfigurationElementHandle[]) element.getChildren();
		for (ConfigurationElementHandle childrenCE : childrenCEs) {
			saveConfigurationElement(childrenCE, outputStream, extraOutputStream, depth + 1);
		}

	}

	private void saveExtensions(IExtension[] exts, DataOutputStream outputStream) throws IOException {
		for (IExtension ext : exts) {
			saveExtension((ExtensionHandle) ext, outputStream);
		}
		for (IExtension ext : exts) {
			if (!((ExtensionHandle) ext).shouldPersist()) {
				continue;
			}
			IConfigurationElement[] ces = ext.getConfigurationElements();
			int countCElements = 0;
			boolean[] save = new boolean[ces.length];
			for (int j = 0; j < ces.length; j++) {
				if (((ConfigurationElementHandle) ces[j]).shouldPersist()) {
					save[j] = true;
					countCElements++;
				} else
					save[j] = false;
			}
			outputStream.writeInt(countCElements);
			for (int j = 0; j < ces.length; j++) {
				if (save[j])
					saveConfigurationElement((ConfigurationElementHandle) ces[j], outputStream, extraOutput, 1);
			}
		}
	}

	private void saveExtensionPointData(ExtensionPointHandle xpt) throws IOException {
		writeStringOrNull(xpt.getLabelAsIs(), extraOutput);
		writeStringOrNull(xpt.getSchemaReference(), extraOutput);
		writeStringOrNull(xpt.getUniqueIdentifier(), extraOutput);
		writeStringOrNull(xpt.getNamespaceIdentifier(), extraOutput);
		writeStringOrNull(((ExtensionPoint) xpt.getObject()).getContributorId(), extraOutput);
	}

	private void saveExtensionData(ExtensionHandle extension) throws IOException {
		writeStringOrNull(extension.getLabelAsIs(), extraOutput);
		writeStringOrNull(extension.getExtensionPointUniqueIdentifier(), extraOutput);
		writeStringOrNull(extension.getContributorId(), extraOutput);
	}

	private void writeStringOrNull(String string, DataOutputStream out) throws IOException {
		if (string == null)
			out.writeByte(TableReader.NULL);
		else {
			byte[] data = string.getBytes(StandardCharsets.UTF_8);
			if (data.length > 65535) {
				out.writeByte(TableReader.LOBJECT);
				out.writeInt(data.length);
				out.write(data);
			} else {
				out.writeByte(TableReader.OBJECT);
				out.writeUTF(string);
			}
		}
	}

	private void saveOrphans() throws IOException {
		Map orphans = objectManager.getOrphanExtensions();
		Map filteredOrphans = new HashMap<>();
		for (Entry entry : orphans.entrySet()) {
			int[] filteredValue = filter(entry.getValue());
			if (filteredValue.length != 0)
				filteredOrphans.put(entry.getKey(), filteredValue);
		}
		try (FileOutputStream fosOrphan = new FileOutputStream(orphansFile);
				DataOutputStream outputOrphan = new DataOutputStream(new BufferedOutputStream(fosOrphan))) {
			outputOrphan.writeInt(filteredOrphans.size());
			Set> elements = filteredOrphans.entrySet();
			for (Entry entry : elements) {
				outputOrphan.writeUTF(entry.getKey());
				saveArray(entry.getValue(), outputOrphan);
			}
			for (Entry entry : elements) {
				mainOutput.writeInt(entry.getValue().length);
				saveExtensions(
						(IExtension[]) objectManager.getHandles(entry.getValue(), RegistryObjectManager.EXTENSION),
						mainOutput);
			}
			outputOrphan.flush();
			fosOrphan.getFD().sync();
		}
	}

	private void log(Status status) {
		registry.log(status);
	}

	// Filters out registry objects that should not be cached
	private int[] filter(int[] input) {
		boolean[] save = new boolean[input.length];
		int resultSize = 0;
		for (int i = 0; i < input.length; i++) {
			if (objectManager.shouldPersist(input[i])) {
				save[i] = true;
				resultSize++;
			} else
				save[i] = false;
		}
		int[] result = new int[resultSize];
		int pos = 0;
		for (int i = 0; i < input.length; i++) {
			if (save[i]) {
				result[pos] = input[i];
				pos++;
			}
		}
		return result;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy