blob: 9ae305a286bcd4a381a04c7c01422ff662109b85 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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
* James Blackburn (Broadcom Corp.) - ongoing development
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427
* Mickael Istria (Red Hat Inc.) - Bug 488937
*******************************************************************************/
package org.eclipse.core.internal.resources;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.*;
import org.eclipse.core.internal.watson.IPathRequestor;
//
public class MarkerWriter {
protected MarkerManager manager;
// version numbers
public static final int MARKERS_SAVE_VERSION = 3;
public static final int MARKERS_SNAP_VERSION = 2;
// type constants
public static final byte INDEX = 1;
public static final byte QNAME = 2;
// marker attribute types
public static final byte ATTRIBUTE_NULL = 0;
public static final byte ATTRIBUTE_BOOLEAN = 1;
public static final byte ATTRIBUTE_INTEGER = 2;
public static final byte ATTRIBUTE_STRING = 3;
public MarkerWriter(MarkerManager manager) {
super();
this.manager = manager;
}
/**
* Returns an Object array of length 2. The first element is an Integer which is the number
* of persistent markers found. The second element is an array of boolean values, with a
* value of true meaning that the marker at that index is to be persisted.
*/
private Object[] filterMarkers(IMarkerSetElement[] markers) {
Object[] result = new Object[2];
boolean[] isPersistent = new boolean[markers.length];
int count = 0;
for (int i = 0; i < markers.length; i++) {
MarkerInfo info = (MarkerInfo) markers[i];
if (manager.isPersistent(info)) {
isPersistent[i] = true;
count++;
}
}
result[0] = count;
result[1] = isPersistent;
return result;
}
/**
* <pre> {@code
* SAVE_FILE -> VERSION_ID RESOURCE+
* VERSION_ID -> int
* RESOURCE -> RESOURCE_PATH MARKERS_SIZE MARKER+
* RESOURCE_PATH -> String
* MARKERS_SIZE -> int
* MARKER -> MARKER_ID TYPE ATTRIBUTES_SIZE ATTRIBUTE* CREATION_TIME
* MARKER_ID -> long
* TYPE -> INDEX | QNAME
* INDEX -> byte int
* QNAME -> byte String
* ATTRIBUTES_SIZE -> short
* ATTRIBUTE -> ATTRIBUTE_KEY ATTRIBUTE_VALUE
* ATTRIBUTE_KEY -> String
* ATTRIBUTE_VALUE -> INTEGER_VALUE | BOOLEAN_VALUE | STRING_VALUE | NULL_VALUE
* INTEGER_VALUE -> byte int
* BOOLEAN_VALUE -> byte boolean
* STRING_VALUE -> byte String
* NULL_VALUE -> byte
* CREATION_TIME -> long
* }</pre>
*/
public void save(ResourceInfo info, IPathRequestor requestor, DataOutputStream output, List<String> writtenTypes) throws IOException {
// phantom resources don't have markers
if (info.isSet(ICoreConstants.M_PHANTOM))
return;
MarkerSet markers = info.getMarkers(false);
if (markers == null)
return;
IMarkerSetElement[] elements = markers.elements();
// filter out the markers...determine if there are any persistent ones
Object[] result = filterMarkers(elements);
int count = ((Integer) result[0]).intValue();
if (count == 0)
return;
// if this is the first set of markers that we have written, then
// write the version id for the file.
if (output.size() == 0)
output.writeInt(MARKERS_SAVE_VERSION);
boolean[] isPersistent = (boolean[]) result[1];
output.writeUTF(requestor.requestPath().toString());
output.writeInt(count);
for (int i = 0; i < elements.length; i++)
if (isPersistent[i])
write((MarkerInfo) elements[i], output, writtenTypes);
}
/**
* Snapshot the markers for the specified resource to the given output stream.
*
* <pre> {@code
* SNAP_FILE -> [VERSION_ID RESOURCE]*
* VERSION_ID -> int (used for backwards compatibiliy)
* RESOURCE -> RESOURCE_PATH MARKER_SIZE MARKER+
* RESOURCE_PATH -> String
* MARKER_SIZE -> int
* MARKER -> MARKER_ID TYPE ATTRIBUTES_SIZE ATTRIBUTE* CREATION_TIME
* MARKER_ID -> long
* TYPE -> INDEX | QNAME
* INDEX -> byte int
* QNAME -> byte String
* ATTRIBUTES_SIZE -> short
* ATTRIBUTE -> ATTRIBUTE_KEY ATTRIBUTE_VALUE
* ATTRIBUTE_KEY -> String
* ATTRIBUTE_VALUE -> BOOLEAN_VALUE | INTEGER_VALUE | STRING_VALUE | NULL_VALUE
* BOOLEAN_VALUE -> byte boolean
* INTEGER_VALUE -> byte int
* STRING_VALUE -> byte String
* NULL_VALUE -> byte
* CREATION_TIME -> long
* }</pre>
*/
public void snap(ResourceInfo info, IPathRequestor requestor, DataOutputStream output) throws IOException {
// phantom resources don't have markers
if (info.isSet(ICoreConstants.M_PHANTOM))
return;
if (!info.isSet(ICoreConstants.M_MARKERS_SNAP_DIRTY))
return;
MarkerSet markers = info.getMarkers(false);
if (markers == null)
return;
IMarkerSetElement[] elements = markers.elements();
// filter out the markers...determine if there are any persistent ones
Object[] result = filterMarkers(elements);
int count = ((Integer) result[0]).intValue();
// write the version id for the snapshot.
output.writeInt(MARKERS_SNAP_VERSION);
boolean[] isPersistent = (boolean[]) result[1];
output.writeUTF(requestor.requestPath().toString());
// always write out the count...even if its zero. this will help
// use pick up marker deletions from our snapshot.
output.writeInt(count);
List<String> writtenTypes = new ArrayList<>();
for (int i = 0; i < elements.length; i++)
if (isPersistent[i])
write((MarkerInfo) elements[i], output, writtenTypes);
info.clear(ICoreConstants.M_MARKERS_SNAP_DIRTY);
}
/*
* Write out the given marker attributes to the given output stream.
*/
private void write(Map<String, Object> attributes, DataOutputStream output) throws IOException {
output.writeShort(attributes.size());
for (Map.Entry<String, Object> e : attributes.entrySet()) {
String key = e.getKey();
output.writeUTF(key);
Object value = e.getValue();
if (value instanceof Integer) {
output.writeByte(ATTRIBUTE_INTEGER);
output.writeInt(((Integer) value).intValue());
continue;
}
if (value instanceof Boolean) {
output.writeByte(ATTRIBUTE_BOOLEAN);
output.writeBoolean(((Boolean) value).booleanValue());
continue;
}
if (value instanceof String) {
output.writeByte(ATTRIBUTE_STRING);
output.writeUTF((String) value);
continue;
}
// otherwise we came across an attribute of an unknown type
// so just write out null since we don't know how to marshal it.
output.writeByte(ATTRIBUTE_NULL);
}
}
private void write(MarkerInfo info, DataOutputStream output, List<String> writtenTypes) throws IOException {
output.writeLong(info.getId());
// if we have already written the type once, then write an integer
// constant to represent it instead to remove duplication
String type = info.getType();
int index = writtenTypes.indexOf(type);
if (index == -1) {
output.writeByte(QNAME);
output.writeUTF(type);
writtenTypes.add(type);
} else {
output.writeByte(INDEX);
output.writeInt(index);
}
// write out the size of the attribute table and
// then each attribute.
if (info.getAttributes(false) == null) {
output.writeShort(0);
} else
write(info.getAttributes(false), output);
// write out the creation time
output.writeLong(info.getCreationTime());
}
}