blob: 5b4b1ae0d02e133f895333953615bb3eb4e51b92 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation 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:
* 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 488938, 488937
*******************************************************************************/
package org.eclipse.core.internal.resources;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.internal.utils.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.osgi.util.NLS;
public class MarkerInfo implements IMarkerSetElement, Cloneable, IStringPoolParticipant {
// well known Integer values
protected static final Integer INTEGER_ONE = 1;
protected static final Integer INTEGER_TWO = 2;
protected static final Integer INTEGER_ZERO = 0;
//
protected static final long UNDEFINED_ID = -1;
/** The store of attributes for this marker. */
protected Map<String, Object> attributes = null;
/** The creation time for this marker. */
protected long creationTime = 0;
/** Marker identifier. */
protected long id = UNDEFINED_ID;
/** The type of this marker. */
protected String type = null;
/**
* Returns whether the given object is a valid attribute value. Returns
* either the attribute or an equal canonical substitute.
*/
protected static Object checkValidAttribute(Object value) {
if (value == null)
return null;
if (value instanceof String) {
//we cannot write attributes whose UTF encoding exceeds 65535 bytes.
String valueString = (String) value;
//optimized test based on maximum 3 bytes per character
if (valueString.length() < 21000)
return value;
byte[] bytes = valueString.getBytes(StandardCharsets.UTF_8);
if (bytes.length > 65535) {
String msg = "Marker property value is too long: " + valueString.substring(0, 10000); //$NON-NLS-1$
Assert.isTrue(false, msg);
}
return value;
}
if (value instanceof Boolean) {
//return canonical boolean
return ((Boolean) value).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
}
if (value instanceof Integer) {
//replace common integers with canonical values
switch (((Integer) value).intValue()) {
case 0 :
return INTEGER_ZERO;
case 1 :
return INTEGER_ONE;
case 2 :
return INTEGER_TWO;
}
return value;
}
//if we got here, it's an invalid attribute value type
throw new IllegalArgumentException(NLS.bind(Messages.resources_wrongMarkerAttributeValueType, value.getClass().getName()));
}
public MarkerInfo() {
super();
}
/**
* See Object#clone.
*/
@Override
public Object clone() {
try {
MarkerInfo copy = (MarkerInfo) super.clone();
//copy the attribute table contents
copy.attributes = getAttributes(true);
return copy;
} catch (CloneNotSupportedException e) {
//cannot happen because this class implements Cloneable
return null;
}
}
public Object getAttribute(String attributeName) {
return attributes == null ? null : attributes.get(attributeName);
}
public Map<String, Object> getAttributes() {
return getAttributes(true);
}
public Map<String, Object> getAttributes(boolean makeCopy) {
if (attributes == null)
return null;
return makeCopy ? new MarkerAttributeMap<>(attributes) : attributes;
}
public Object[] getAttributes(String[] attributeNames) {
Object[] result = new Object[attributeNames.length];
for (int i = 0; i < attributeNames.length; i++)
result[i] = getAttribute(attributeNames[i]);
return result;
}
public long getCreationTime() {
return creationTime;
}
@Override
public long getId() {
return id;
}
public String getType() {
return type;
}
public void internalSetAttributes(Map<String, Object> map) {
//the cast effectively acts as an assertion to make sure
//the right kind of map is being used
attributes = map;
}
public void setAttribute(String attributeName, Object value, boolean validate) {
if (validate)
value = checkValidAttribute(value);
if (attributes == null) {
if (value == null)
return;
attributes = new MarkerAttributeMap<>();
attributes.put(attributeName, value);
} else {
if (value == null) {
attributes.remove(attributeName);
if (attributes.isEmpty())
attributes = null;
} else {
attributes.put(attributeName, value);
}
}
}
public void setAttributes(Map<String, ? extends Object> map, boolean validate) {
if (map == null)
attributes = null;
else {
attributes = new MarkerAttributeMap<>(map.size());
for (Entry<String, ?> entry : map.entrySet()) {
Object key = entry.getKey();
Assert.isTrue(key instanceof String);
Object value = entry.getValue();
setAttribute((String) key, value, validate);
}
}
}
public void setAttributes(String[] attributeNames, Object[] values, boolean validate) {
Assert.isTrue(attributeNames.length == values.length);
for (int i = 0; i < attributeNames.length; i++)
setAttribute(attributeNames[i], values[i], validate);
}
public void setCreationTime(long value) {
creationTime = value;
}
public void setId(long value) {
id = value;
}
public void setType(String value) {
type = value;
}
/* (non-Javadoc
* Method declared on IStringPoolParticipant
*/
@Override
public void shareStrings(StringPool set) {
type = set.add(type);
Map<String, Object> map = attributes;
if (map instanceof IStringPoolParticipant)
((IStringPoolParticipant) map).shareStrings(set);
}
}