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

net.sf.okapi.common.resource.TextUnit Maven / Gradle / Ivy

There is a newer version: 1.47.0
Show newest version
/*===========================================================================
  Copyright (C) 2008-2011 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.resource;

import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import net.sf.okapi.common.IResource;
import net.sf.okapi.common.ISegmenter;
import net.sf.okapi.common.ISkeleton;
import net.sf.okapi.common.LocaleId;
import net.sf.okapi.common.exceptions.OkapiException;

/**
 * Basic unit of extraction from a filter and also the resource associated with
 * the filter event TEXT_UNIT.
 * The TextUnit object holds the extracted source text in one or more versions,
 * all its properties and annotations, and any target corresponding data.
 */
public class TextUnit extends BaseReferenceable implements ITextUnit {

	private static int TARGETS_INITCAP = 2;

	private int refCount;
	private String type;
	private boolean isTranslatable = true;
	private boolean preserveWS;

	private TextContainer source;
	private ConcurrentHashMap targets = new ConcurrentHashMap<>(TARGETS_INITCAP);

	public TextUnit() {
		create(null, null, false, null);
	}

	/**
	 * Creates a new TextUnit object with its identifier.
	 *
	 * @param id the identifier of this resource.
	 */
	public TextUnit(String id) {
		create(id, null, false, null);
	}

	/**
	 * Creates a new TextUnit object with its identifier and a text.
	 *
	 * @param id         the identifier of this resource.
	 * @param sourceText the initial text of the source.
	 */
	public TextUnit(String id, String sourceText) {
		create(id, sourceText, false, null);
	}

	/**
	 * Creates a new TextUnit object with its ID, a text, and a flag indicating if
	 * it is a referent or not.
	 *
	 * @param id         the identifier of this resource.
	 * @param sourceText the initial text of the source (can be null).
	 * @param isReferent indicates if this resource is a referent (i.e. is referred
	 *                   to by another resource) or not.
	 */
	public TextUnit(String id, String sourceText, boolean isReferent) {
		create(id, sourceText, isReferent, null);
	}

	/**
	 * Creates a new TextUnit object with its identifier, a text, a flag indicating
	 * if it is a referent or not, and a given MIME type.
	 *
	 * @param id         the identifier of this resource.
	 * @param sourceText the initial text of the source (can be null).
	 * @param isReferent indicates if this resource is a referent (i.e. is referred
	 *                   to by another resource) or not.
	 * @param mimeType   the MIME type identifier for the content of this TextUnit.
	 */
	public TextUnit(String id, String sourceText, boolean isReferent, String mimeType) {
		create(id, sourceText, isReferent, mimeType);
	}

	private void create(String id, String sourceText, boolean isReferent, String mimeType) {
		this.id = id;
		refCount = (isReferent ? 1 : 0);
		this.mimeType = mimeType;

		source = new TextContainer(sourceText);
	}

	@Override
	public boolean isEmpty() {
		return getSource().isEmpty();
	}

	@Override
	public TextContainer getSource() {
		return source;
	}

	@Override
	public TextContainer setSource(TextContainer textContainer) {
		source = textContainer;
		return source;
	}

	@Override
	public TextFragment setSourceContent(TextFragment content) {
		getSource().setContent(content);
		return getSource().getFirstContent();
	}

	@Override
	public TextContainer createTarget(LocaleId targetLocale, boolean overwriteExisting, int creationOptions) {
		TextContainer trgCont = targets.get(targetLocale);
		if ((trgCont == null) || overwriteExisting) {
			trgCont = getSource().clone((creationOptions & INameable.COPY_PROPERTIES) == INameable.COPY_PROPERTIES);
			if ((creationOptions & INameable.COPY_SEGMENTATION) != INameable.COPY_SEGMENTATION) {
				trgCont.joinAll();
			}
			if ((creationOptions & INameable.COPY_CONTENT) != INameable.COPY_CONTENT) {
				for (Segment seg : trgCont.getSegments()) {
					seg.text.clear();
				}
			}
			targets.put(targetLocale, trgCont);
		}
		return trgCont;
	}

	@Override
	public TextContainer getTarget(LocaleId locId) {
		if (locId == null) {
			// no target, just return empty text container
			return new TextContainer();
		}
		return targets.get(locId);
	}

	@Override
	public TextContainer setTarget(LocaleId locId, TextContainer text) {
		targets.put(locId, text);
		return text;
	}

	@Override
	public void removeTarget(LocaleId locId) {
		if (hasTarget(locId)) {
			targets.remove(locId);
		}
	}

	@Override
	public boolean hasTarget(LocaleId locId) {
		// ConcurrentHashMap doesn't allow nulls so no need to check for null
		return targets.containsKey(locId);
	}

	@Override
	public TextFragment setTargetContent(LocaleId locId, TextFragment content) {
		TextContainer tc = createTarget(locId, false, INameable.CREATE_EMPTY);
		tc.setContent(content);
		// We can use this because the setContent() removed any segmentation
		return tc.getSegments().getFirstContent();
	}

	@Override
	public IAlignedSegments getAlignedSegments() {
		return new AlignedSegments(this);
	}

	@Override
	public ISegments getSourceSegments() {
		return getSource().getSegments();
	}

	@Override
	public Segment getSourceSegment(String segId, boolean createIfNeeded) {
		Segment seg = getSource().getSegments().get(segId);
		if ((seg == null) && createIfNeeded) {
			seg = new Segment(segId);
			getSource().getSegments().append(seg);
		}
		return seg;
	}

	@Override
	public ISegments getTargetSegments(LocaleId trgLoc) {
		return createTarget(trgLoc, false, INameable.COPY_SEGMENTATION).getSegments();
	}

	@Override
	public Segment getTargetSegment(LocaleId trgLoc, String segId, boolean createIfNeeded) {
		Segment seg = createTarget(trgLoc, false, INameable.COPY_SEGMENTATION).getSegments().get(segId);
		if ((seg == null) && createIfNeeded) {
			// If the segment does not exists: create a new one if requested
			seg = new Segment(segId);
			getTarget(trgLoc).getSegments().append(seg);
			// TODO consider appending a segment to variant source if present
		}
		return seg;
	}

	@Override
	public Set getTargetLocales() {
		return targets.keySet();
	}

	@Override
	public String getType() {
		return type;
	}

	@Override
	public void setType(String value) {
		type = value;
	}

	@Override
	public boolean isTranslatable() {
		return isTranslatable;
	}

	@Override
	public void setIsTranslatable(boolean value) {
		isTranslatable = value;
	}

	@Override
	public boolean preserveWhitespaces() {
		return preserveWS;
	}

	@Override
	public void setPreserveWhitespaces(boolean value) {
		preserveWS = value;
	}

	@Override
	public void setSkeleton(ISkeleton skeleton) {
		if (skeleton != null)
			skeleton.setParent(this);
		super.setSkeleton(skeleton);
	}

	@Override
	public boolean isReferent() {
		return (refCount > 0);
	}

	@Override
	public void setIsReferent(boolean value) {
		refCount = (value ? 1 : 0);
	}

	@Override
	public int getReferenceCount() {
		return refCount;
	}

	@Override
	public void setReferenceCount(int value) {
		refCount = value;
	}

	/**
	 * Gets the string representation of the default source container. If the
	 * container is segmented, the representation shows the merged segments. Inline
	 * codes are also included.
	 *
	 * @return the string representation of the source container.
	 */
	@Override
	public String toString() {
		return getSource().toString();
	}

	/**
	 * Clones this TextUnit.
	 *
	 * @return A new TextUnit object that is a copy of this one.
	 */
	@Override
	public TextUnit clone() {
		TextUnit tu = new TextUnit(getId());
		tu.setIsReferent(isReferent());
		tu.setIsTranslatable(isTranslatable);
		tu.setMimeType(getMimeType());
		tu.setName(getName());
		tu.setPreserveWhitespaces(preserveWS);
		tu.setReferenceCount(getReferenceCount());
		tu.setSource(getSource().clone());
		tu.setType(getType());

		// Copy all the targets
		for (Entry entry : targets.entrySet()) {
			tu.setTarget(entry.getKey(), entry.getValue().clone());
		}

		IWithProperties.copy(this, tu);
		IWithTargetProperties.copy(this, tu);
		IWithSourceProperties.copy(this, tu);
		IWithAnnotations.copy(this, tu);

		if (getSkeleton() != null) {
			ISkeleton skel = getSkeleton().clone();
			tu.setSkeleton(skel);
		}

		return tu;
	}

	@Override
	public void removeAllSegmentations () {
		// Desegment the source if needed
		if ( getSource().hasBeenSegmented() ) {
			getSource().joinAll();
		}

		// Desegment all targets as needed
		for (Entry entry : targets.entrySet()) {
			if ( entry.getValue().hasBeenSegmented() ) {
				entry.getValue().joinAll();
			}
		}
	}

	@Override
	public void createSourceSegmentation(ISegmenter segmenter) {
		segmenter.computeSegments(getSource());
		getSource().getSegments().create(segmenter.getRanges());
	}

	@Override
	public void createTargetSegmentation(ISegmenter segmenter, LocaleId targetLocale)
	{
		TextContainer tc = getTarget(targetLocale);
		if ( tc == null ) {
			throw new OkapiException(String.format("There is no target content for '%s'", targetLocale.toString()));
		}
		segmenter.computeSegments(tc);
		tc.getSegments().create(segmenter.getRanges());
	}
	/*
	 * ITextUnit delegates source and target properties to TextContainer
	 */

	@Override
	public Property getSourceProperty(String name) {
		return getSource().getProperty(name);
	}

	@Override
	public Property setSourceProperty(Property property) {
		return getSource().setProperty(property);
	}

	// for source of active locale
	@Override
	public void removeSourceProperty(String name) {
		getSource().removeProperty(name);
	}

	@Override
	public Set getSourcePropertyNames() {
		return getSource().getPropertyNames();
	}

	@Override
	public boolean hasSourceProperty(String name) {
		return getSource().hasProperty(name);
	}

	@Override
	public Property getTargetProperty(LocaleId locId, String name) {
		if (!hasTarget(locId))
			return null;
		return getTarget(locId).getProperty(name);
	}

	@Override
	public Property setTargetProperty(LocaleId locId, Property property) {
		return createTarget(locId, false, IResource.COPY_SEGMENTATION).setProperty(property);
	}

	@Override
	public void removeTargetProperty(LocaleId locId, String name) {
		if (hasTarget(locId)) {
			getTarget(locId).removeProperty(name);
		}
	}

	@Override
	public Set getTargetPropertyNames(LocaleId locId) {
		if (hasTarget(locId)) {
			return getTarget(locId).getPropertyNames();
		}
		return Collections.emptySet();
	}

	@Override
	public boolean hasTargetProperty(LocaleId locId, String name) {
		TextContainer tc = getTarget(locId);
		if (tc == null)
			return false;
		return (tc.getProperty(name) != null);
	}

	@Override
	public Map getSourceProperties() {
		return getSource().getProperties();
	}

	@Override
	public Property createTargetProperty(LocaleId locId, String name, boolean overwriteExisting, int creationOptions) {
		// Get the target or create an isEmpty one
		TextContainer tc = createTarget(locId, false, CREATE_EMPTY);
		// Get the property if it exists
		Property prop = tc.getProperty(name);
		// If it does not exists or if we overwrite: create a new one
		if ((prop == null) || overwriteExisting) {
			// Get the source property
			prop = getSource().getProperty(name);
			if (prop == null) {
				// If there is no source, create an isEmpty property
				return tc.setProperty(new Property(name, "", false));
			} else { // If there is a source property
						// Create a copy, isEmpty or not depending on the options
				if (creationOptions == CREATE_EMPTY) {
					return tc.setProperty(new Property(name, "", prop.isReadOnly()));
				} else {
					return tc.setProperty(prop.clone());
				}
			}
		}
		return prop;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy