/******************************************************************************* * Copyright (c) 2011 SAP AG 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: * SAP AG - initial API and implementation ******************************************************************************/ package com.sap.furcas.runtime.tcs; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sap.furcas.metamodel.FURCAS.TCS.AsPArg; import com.sap.furcas.metamodel.FURCAS.TCS.CreateAsPArg; import com.sap.furcas.metamodel.FURCAS.TCS.ForcedLowerPArg; import com.sap.furcas.metamodel.FURCAS.TCS.ForcedUpperPArg; import com.sap.furcas.metamodel.FURCAS.TCS.LookupScopePArg; import com.sap.furcas.metamodel.FURCAS.TCS.ModePArg; import com.sap.furcas.metamodel.FURCAS.TCS.PartialPArg; import com.sap.furcas.metamodel.FURCAS.TCS.PostfixPArg; import com.sap.furcas.metamodel.FURCAS.TCS.PrefixPArg; import com.sap.furcas.metamodel.FURCAS.TCS.PrimitiveTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.Property; import com.sap.furcas.metamodel.FURCAS.TCS.PropertyArg; import com.sap.furcas.metamodel.FURCAS.TCS.ReferenceByPArg; import com.sap.furcas.metamodel.FURCAS.TCS.RefersToPArg; import com.sap.furcas.metamodel.FURCAS.TCS.SeparatorPArg; import com.sap.furcas.metamodel.FURCAS.TCS.Template; /** * Helper utils for the various subclasses of {@link PropertyArgument}. * The subclasses are often called "PArgs". * * @author Stephan Erb * */ public class PropertyArgumentUtil { /** * The pattern to select a 'self' within an OCL entry. */ private static final String selfPatternAsString = "((\\W|\\A))(self)(\\W)"; private static final Pattern selfPattern = Pattern.compile(selfPatternAsString); private static final String OCL_PREFIX = "OCL:"; /** * Returns the first {@link RefersToPArg} of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static RefersToPArg getRefersToPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof RefersToPArg) { return (RefersToPArg) arg; } } return null; } /** * Returns the first {@link LookupScopePArg} of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static LookupScopePArg getLookupScopePArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof LookupScopePArg) { return (LookupScopePArg) arg; } } return null; } /** * Returns the first {@link ReferenceByPArg} of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static ReferenceByPArg getReferenceByPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof ReferenceByPArg) { return (ReferenceByPArg) arg; } } return null; } /** * Returns an OCL query that can be evaluated on types corresponding to the {@link Property} p, which the given * {@link ReferencebyPArg} belongs to. The OCL query returns an identifier suitable to be compared * to the token value that is used to textually reference p. */ public static String getReferenceByAsOCL(ReferenceByPArg referenceByPArg) { String referenceBy = referenceByPArg.getReferenceBy(); if (referenceBy.startsWith(OCL_PREFIX)) { return referenceBy.substring(OCL_PREFIX.length()); } else { // referenceBy contains a simple property name return referenceBy; } } /** * Returns a combined query of the {@link ReferenceByPArg} and {@link LookupScopePArg}. * The query contains a "?" and can be parameterized to directly find the referenced element. */ public static String getCombinedReferenceByLookupOCLQuery(ReferenceByPArg referenceByPArg, LookupScopePArg lookupScopePArg, PrefixPArg prefixPArg, PostfixPArg postfixPArg) { String tokenPlaceholder = getTokenPlaceHolder(prefixPArg, postfixPArg); String referenceByQuery = getReferenceByAsOCL(referenceByPArg); Matcher matcher = selfPattern.matcher(referenceByQuery); if (matcher.find()) { String preSelf = matcher.group(1); String replacementForSelf = "candidate"; // find unique temporary variable while (referenceByQuery.contains(replacementForSelf)) { replacementForSelf = "_" + replacementForSelf; } String postSelf = matcher.group(4); referenceByQuery = matcher.replaceAll(preSelf + replacementForSelf + postSelf); return lookupScopePArg.getQuery() + "->select(" + replacementForSelf + " | " + referenceByQuery + " = " + tokenPlaceholder + ")"; } else { return lookupScopePArg.getQuery() + "->select(" + referenceByQuery + " = " + tokenPlaceholder + ")"; } } /** * Builds the OCL expression "prefix.concat(?).concat(postfix)" */ private static String getTokenPlaceHolder(PrefixPArg prefixPArg, PostfixPArg postfixPArg) { StringBuilder buf = new StringBuilder(); if (prefixPArg == null) { buf.append("?"); } else { buf.append("'").append(prefixPArg.getPrefix()).append("'.concat(?)"); } if (postfixPArg != null) { buf.append(".concat('").append(postfixPArg.getPostfix()).append("')"); } return buf.toString(); } /** * Returns the first PrefixPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static PrefixPArg getPrefixPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof PrefixPArg) { return (PrefixPArg) arg; } } return null; } /** * Returns the first PostfixPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static PostfixPArg getPostfixPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof PostfixPArg) { return (PostfixPArg) arg; } } return null; } public static String stripPrefixPostfix(String string, PrefixPArg prefixPArg, PostfixPArg postfixPArg) { if (prefixPArg != null && string.startsWith(prefixPArg.getPrefix())) { string = string.substring(prefixPArg.getPrefix().length(), string.length()); } if (postfixPArg != null && string.endsWith(postfixPArg.getPostfix())) { string = string.substring(0, string.length() - postfixPArg.getPostfix().length()); } return string; } /** * Returns the first AsPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static AsPArg getAsPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof AsPArg) { return (AsPArg) arg; } } return null; } /** * Returns the PrimitiveTemplate referenced by the given AsPArg. */ public static PrimitiveTemplate getAsTemplate(AsPArg asParg) { if (asParg != null) { Template asTemplate = asParg.getTemplate(); if (asTemplate instanceof PrimitiveTemplate) { return (PrimitiveTemplate) asTemplate; } } return null; } /** * Returns the first PartialPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static PartialPArg getPartialPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof PartialPArg) { return (PartialPArg) arg; } } return null; } /** * Returns the first ForcedUpperPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static ForcedUpperPArg getForcedUpperPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof ForcedUpperPArg) { return (ForcedUpperPArg) arg; } } return null; } /** * Returns the first ForcedLowerPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static ForcedLowerPArg getForcedLowerPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof ForcedLowerPArg) { return (ForcedLowerPArg) arg; } } return null; } /** * Returns the first ModePArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static ModePArg getModePArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof ModePArg) { return (ModePArg) arg; } } return null; } /** * Returns the first SeparatorPArg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static SeparatorPArg getSeparatorPArg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof SeparatorPArg) { return (SeparatorPArg) arg; } } return null; } /** * Returns the first CreateAsParg of Property p. There should only be one. * No error is thrown, if more than one exist. */ public static CreateAsPArg getCreateAsParg(Property p) { for (PropertyArg arg : p.getPropertyArgs()) { if (arg instanceof CreateAsPArg) { return (CreateAsPArg) arg; } } return null; } public static boolean containsAsArg(Property p) { return getAsPArg(p) != null; } public static boolean containsSeparatorArg(Property p) { return getSeparatorPArg(p) != null; } public static boolean containsRefersToArg(Property p) { return getRefersToPArg(p) != null; } public static boolean containsLookupScopePArg(Property p) { return PropertyArgumentUtil.getLookupScopePArg(p) != null; } public static boolean containsReferenceByPArg(Property p) { return PropertyArgumentUtil.getReferenceByPArg(p) != null; } public static boolean containsForcedLowerArg(Property prop) { return (PropertyArgumentUtil.getForcedLowerPArg(prop) != null); } public static boolean containsForcedUpperArgOfOne(Property prop) { ForcedUpperPArg upperArg = PropertyArgumentUtil.getForcedUpperPArg(prop); if (upperArg != null && upperArg.getValue() == 1) { return true; } return false; } public static boolean containsPartialPArg(Property p) { return getPartialPArg(p) != null; } }