net.sf.okapi.common.annotation.GenericAnnotation Maven / Gradle / Ivy
/*===========================================================================
Copyright (C) 2012-2019 by the Okapi Framework contributors
-----------------------------------------------------------------------------
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
===========================================================================*/
package net.sf.okapi.common.annotation;
import net.sf.okapi.common.Util;
import net.sf.okapi.common.exceptions.OkapiException;
import net.sf.okapi.common.resource.Code;
import net.sf.okapi.common.resource.ITextUnit;
import net.sf.okapi.common.resource.InlineAnnotation;
import net.sf.okapi.common.resource.TextContainer;
import java.security.InvalidParameterException;
import java.util.LinkedHashMap;
import java.util.Set;
/**
* Generic annotation allowing access with field names and multiple instance on the same object.
*/
public class GenericAnnotation extends InlineAnnotation {
private static final String FIELD_SEPARATOR = "\u009B";
private static final String PART_SEPARATOR = "\u0099";
private String type;
private LinkedHashMap map;
/**
* Creates a new GenericAnnotation object from a storage string.
* @param storage the serialized representation of the object.
* @return a new GenericAnnotation object.
*/
static public GenericAnnotation createFromString (String storage) {
GenericAnnotation annotation = new GenericAnnotation();
annotation.fromString(storage);
return annotation;
}
/**
* Adds an annotation to a text unit. If the text unit has
* no annotation set attached yet one is created and attached,
* otherwise the annotation to add is added to the existing set.
* @param tu the text unit where to attach the annotation.
* @param ann the annotation to attach (if null, nothing is attached).
*/
static public void addAnnotation (ITextUnit tu,
GenericAnnotation ann)
{
if ( ann == null ) return;
GenericAnnotations anns = tu.getAnnotation(GenericAnnotations.class);
if ( anns == null ) {
anns = new GenericAnnotations();
tu.setAnnotation(anns);
}
anns.add(ann);
}
/**
* Adds an annotation to a text container. If the text container has
* no annotation set attached yet one is created and attached,
* otherwise the annotation to add is added to the existing set.
* @param tc the text container where to attach the annotation.
* @param ann the annotation to attach (if null, nothing is attached).
*/
static public void addAnnotation (TextContainer tc,
GenericAnnotation ann)
{
if ( ann == null ) return;
GenericAnnotations anns = tc.getAnnotation(GenericAnnotations.class);
if ( anns == null ) {
anns = new GenericAnnotations();
tc.setAnnotation(anns);
}
anns.add(ann);
}
/**
* Adds an annotation to an inline code. If the inline code has
* no annotation set attached yet one is created and attached,
* otherwise the annotation to add is added to the existing set.
* @param code the code where to add the annotation.
* @param ann the annotation to add (if null, nothing is attached).
*/
static public void addAnnotation (Code code,
GenericAnnotation ann)
{
if ( ann == null ) return;
GenericAnnotations anns = (GenericAnnotations)code.getAnnotation(GenericAnnotationType.GENERIC);
if ( anns == null ) {
anns = new GenericAnnotations();
code.setAnnotation(GenericAnnotationType.GENERIC, anns);
}
anns.add(ann);
}
public GenericAnnotation () {
map = null;
}
/**
* Creates a new annotation for a given type.
* Note that it is technically to have two annotations with the same type but different fields.
* This is a side effect of the capability to access the annotation in a generic way.
* The user is responsible for keeping consistent types of annotations.
* @param type the identifier of the type (cannot be null or empty).
*/
public GenericAnnotation (String type) {
if ( Util.isEmpty(type) ) {
throw new InvalidParameterException("The type of an annotation must not be null or empty.");
}
this.map = null;
this.type = type;
}
/**
* Creates a new annotation for a given type.
* With a list of fields. This method simply call the {@link #setFields(Object...)} method after
* creating the annotation.
* @param type the identifier of the type (cannot be null or empty).
* @param list the list of key+value pairs to set.
*/
public GenericAnnotation (String type, Object ... list) {
this(type);
setFields(list);
}
/**
* Sets a list of key+values pairs for this annotation.
* Each pair must be made of a string that is the name of the field, and an object that is the value to set.
* The object can be null in that case: the key is not set or deleted.
* Only supported types must be used.
* @param list the list of key+value pairs to set.
*/
public void setFields (Object ... list) {
for ( int i=0; i getNames() {
return map.keySet();
}
public void remove(String name) {
map.remove(name);
}
private void setObject (String name,
Object value)
{
if ( Util.isEmpty(name) ) {
throw new InvalidParameterException("The field name must not be null or empty.");
}
// Create the map if needed
if ( map == null ) map = new LinkedHashMap<>();
// Remove or set the value
if ( value == null ) map.remove(name);
else map.put(name, value);
}
}