/******************************************************************************* * Copyright (c) 2010, 2015 Willink Transformations 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: * E.D.Willink - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.xtext.base.serializer; import java.util.List; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.NamedElement; import org.eclipse.ocl.pivot.utilities.Nameable; import org.eclipse.ocl.xtext.base.as2cs.AliasAnalysis; import org.eclipse.ocl.xtext.base.utilities.BaseCSResource; import org.eclipse.ocl.xtext.basecs.PathElementCS; import org.eclipse.ocl.xtext.basecs.PathElementWithURICS; import org.eclipse.ocl.xtext.basecs.PathNameCS; import org.eclipse.ocl.xtext.basecs.RootPackageCS; import org.eclipse.xtext.CrossReference; import org.eclipse.xtext.conversion.IValueConverterService; import org.eclipse.xtext.conversion.ValueConverterException; import org.eclipse.xtext.linking.impl.LinkingHelper; import org.eclipse.xtext.naming.IQualifiedNameConverter; import org.eclipse.xtext.naming.QualifiedName; import org.eclipse.xtext.resource.IEObjectDescription; import org.eclipse.xtext.scoping.IScope; import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic; import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor; import org.eclipse.xtext.serializer.tokens.CrossReferenceSerializer; import com.google.common.collect.Lists; import com.google.inject.Inject; // FIXME Temporary workaround for Bug 361577 @SuppressWarnings("restriction") public class BaseCrossReferenceSerializer extends CrossReferenceSerializer { protected class AcceptorHelper { protected final EObject semanticObject; protected final CrossReference crossref; protected final EObject target; protected final IScope scope; protected final @Nullable Acceptor errors; private @Nullable List<ISerializationDiagnostic> recordedErrors = null; public AcceptorHelper(EObject semanticObject, CrossReference crossref, EObject target, IScope scope, @Nullable Acceptor errors) { this.semanticObject = semanticObject; this.crossref = crossref; this.target = target; this.scope = scope; this.errors = errors; } public @Nullable String convert(String unconverted, String ruleName) { try { return valueConverter.toString(unconverted, ruleName); } catch (ValueConverterException e) { record(unconverted, e); return null; } } protected @Nullable String convert(List<String> segments, String ruleName) { int iMax = segments.size(); String[] converted = new String[iMax]; String unconverted = null; try { for (int i = 0; i < iMax; i++) { unconverted = segments.get(i); if ((i > 0) && "UnrestrictedName".equals(ruleName)) { converted[i] = valueConverter.toString(unconverted, "UnreservedName"); } else { converted[i] = valueConverter.toString(unconverted, ruleName); } } return qualifiedNameConverter.toString(new QualifiedName(converted) {}); } catch (ValueConverterException e) { record(unconverted, e); return null; } } protected void record(String unconverted, @NonNull ValueConverterException e) { if (errors != null) { List<ISerializationDiagnostic> recordedErrors2 = recordedErrors; if (recordedErrors2 == null) recordedErrors = recordedErrors2 = Lists.newArrayList(); recordedErrors2.add(diagnostics.getValueConversionExceptionDiagnostic(semanticObject, crossref, unconverted, e)); } } protected void report(boolean foundOne) { Acceptor errors2 = errors; if (errors2 != null) { if (recordedErrors != null) for (ISerializationDiagnostic diag : recordedErrors) errors2.accept(diag); if (!foundOne) errors2.accept(diagnostics.getNoEObjectDescriptionFoundDiagnostic(semanticObject, crossref, target, scope)); } } } @Inject private LinkingHelper linkingHelper; @Inject private IQualifiedNameConverter qualifiedNameConverter; @Inject private IValueConverterService valueConverter; @Override protected String getCrossReferenceNameFromScope(EObject semanticObject, CrossReference crossref, EObject target, IScope scope, Acceptor errors) { AcceptorHelper helper = new AcceptorHelper(semanticObject, crossref, target, scope, errors); boolean foundOne = false; final String ruleName = linkingHelper.getRuleNameFrom(crossref); if ("URI".equals(ruleName)) { if (semanticObject instanceof PathElementWithURICS) { PathElementWithURICS pathElementWithURICS = (PathElementWithURICS)semanticObject; String uri = pathElementWithURICS.getUri(); if (uri != null) { String converted = helper.convert(uri, ruleName); if (converted != null) { return converted; } } } // This fallback is used, but perhaps only erroneously tests show one PathElementWithURICS and one IncludeCS //System.out.println(ruleName + " 1=> " + semanticObject.eClass().getName()); Iterable<IEObjectDescription> elements = scope.getElements(target); for (IEObjectDescription desc : elements) { URI uri = URI.createURI(desc.getName().toString()); URI baseURI = semanticObject.eResource().getURI(); URI deresolvedURI = uri.deresolve(baseURI, true, true, false); String unconverted = deresolvedURI.toString(); String converted = helper.convert(unconverted, ruleName); if (converted != null) { return converted; } } } else if (semanticObject instanceof PathElementCS) { // UnrestrictedName or UnreservedName PathElementCS pathElement = (PathElementCS)semanticObject; PathNameCS pathName = pathElement.getOwningPathName(); int index = pathName.getOwnedPathElements().indexOf(pathElement); Element element = pathElement.getReferredElement(); if ((element != null) && !element.eIsProxy()) { Resource csResource = pathElement.eResource(); assert csResource != null; NamedElement namedElement = csResource instanceof BaseCSResource ? ((BaseCSResource)csResource).isPathable(element) : null; if (namedElement != null) { String name = namedElement.getName(); if ((index == 0) && (namedElement instanceof org.eclipse.ocl.pivot.Package)) { EObject root = EcoreUtil.getRootContainer(semanticObject); Resource asResource = null; if (root instanceof RootPackageCS) { EObject root2 = ((RootPackageCS)root).getPivot(); asResource = EcoreUtil.getRootContainer(root2).eResource(); } Resource elementResource = namedElement.eResource(); if ((elementResource != csResource) && (elementResource != asResource)) { AliasAnalysis adapter = AliasAnalysis.getAdapter(csResource); String alias = adapter.getAlias(namedElement, null); if (alias != null) { name = alias; } } } String converted = helper.convert(name, ruleName); if (converted != null) { return converted; } } else { URI uri; EObject eTarget = element.getESObject(); if (eTarget != null) { uri = EcoreUtil.getURI(eTarget); } else { uri = EcoreUtil.getURI(element); } URI baseURI = semanticObject.eResource().getURI(); URI deresolvedURI = uri.deresolve(baseURI, true, true, false); String unconverted = deresolvedURI.toString(); String converted = helper.convert(unconverted, ruleName); if (converted != null) { return converted; } } } // Never get here //System.out.println(ruleName + " 2=> " + semanticObject.eClass().getName()); } else { // Always UnrestrictedName => ReferenceCS //System.out.println(ruleName + " 3=> " + semanticObject.eClass().getName()); Iterable<IEObjectDescription> elements = scope.getElements(target); for (IEObjectDescription desc : elements) { foundOne = true; QualifiedName name = desc.getName(); if (name.getSegmentCount() > 0) { String unconverted = name.getLastSegment(); String converted = helper.convert(unconverted, ruleName); if (converted != null) { return converted; } } } if (target instanceof Nameable) { // OCLstdlib MetaclassNameCS return ((Nameable)target).getName(); } } helper.report(foundOne); return null; } }