/******************************************************************************* * Copyright (c) 2010 itemis AG (http://www.itemis.eu) 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 *******************************************************************************/ package org.jnario.conversion; import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.xtext.conversion.ValueConverterException; import org.eclipse.xtext.conversion.ValueConverterWithValueException; import org.eclipse.xtext.conversion.impl.AbstractLexerBasedConverter; import org.eclipse.xtext.nodemodel.INode; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; /** * @author Sebastian Zarnekow - Initial contribution and API */ public abstract class JnarioAbstractRichTextValueConverter extends AbstractLexerBasedConverter<String> { /** * A list of possible trailing subsequence sorted by length in descending order. */ private List<String> trailingSubsequences; protected abstract String getLeadingTerminal(); protected abstract String getTrailingTerminal(); @Override protected String toEscapedString(String value) { return getLeadingTerminal() + value + getTrailingTerminal(); } @Override protected void assertValidValue(String value) { super.assertValidValue(value); if (value.indexOf('\u00AB') >= 0) { throw new ValueConverterException("Rich string may not contain \"\u00AB\".", null, null); } if (value.indexOf("'''") >= 0) { throw new ValueConverterException("Rich string may not contain \"'''\".", null, null); } } protected List<String> getTrailingSubsequences() { if (trailingSubsequences != null) return trailingSubsequences; String trailingTerminal = getTrailingTerminal(); List<String> result = Collections.emptyList(); if (trailingTerminal.length() >= 1) { Set<String> unique = Sets.newLinkedHashSet(); for(int i = 0; i < trailingTerminal.length() - 1; i++) { addIfAbsent(trailingTerminal.substring(i + 1), unique); addIfAbsent(trailingTerminal.substring(0, i + 1), unique); } result = ImmutableList.copyOf(unique); } trailingSubsequences = result; return result; } protected void addIfAbsent(String value, Set<String> set) { if (!set.contains(value)) set.add(value); } public String toValue(String string, INode node) { if (string == null) return null; try { String leadingTerminal = getLeadingTerminal(); if (string.length() <= leadingTerminal.length()) { throw stringLiteralIsNotClosed(node, ""); } String withoutLeadingTerminal = getWithoutLeadingTerminal(string); String trailingTerminal = getTrailingTerminal(); if (withoutLeadingTerminal.endsWith(trailingTerminal)) { String result = withoutLeadingTerminal.substring(0, withoutLeadingTerminal.length() - trailingTerminal.length()); return result; } List<String> trailingSubsequences = getTrailingSubsequences(); for(String subsequence: trailingSubsequences) { if (withoutLeadingTerminal.endsWith(subsequence)) { throw stringLiteralIsNotClosed(node, withoutLeadingTerminal.substring(0, withoutLeadingTerminal.length() - subsequence.length())); } } throw stringLiteralIsNotClosed(node, withoutLeadingTerminal.substring(0, withoutLeadingTerminal.length())); } catch (StringIndexOutOfBoundsException e) { throw new ValueConverterException(e.getMessage(), node, e); } } private ValueConverterWithValueException stringLiteralIsNotClosed(INode node, String value) { return new ValueConverterWithValueException("String literal is not closed", node, value, null); } protected String getWithoutLeadingTerminal(String string) { return string.substring(getLeadingTerminal().length()); } }