/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* NavAddressHelper.java
* Creation date: Dec 5, 2003
* By: Frank Worsley
*/
package org.openquark.gems.client.navigator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openquark.cal.compiler.CALDocComment;
import org.openquark.cal.compiler.ClassInstance;
import org.openquark.cal.compiler.FieldName;
import org.openquark.cal.compiler.FunctionalAgent;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.PolymorphicVarContext;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.compiler.ScopedEntity;
import org.openquark.cal.compiler.ScopedEntityNamingPolicy;
import org.openquark.cal.compiler.TypeExpr;
import org.openquark.cal.metadata.ArgumentMetadata;
import org.openquark.cal.metadata.CALFeatureMetadata;
import org.openquark.cal.metadata.FunctionMetadata;
import org.openquark.cal.metadata.FunctionalAgentMetadata;
import org.openquark.cal.metadata.InstanceMethodMetadata;
import org.openquark.cal.services.CALFeatureName;
import org.openquark.cal.services.CALWorkspace;
import org.openquark.cal.services.GemEntity;
import org.openquark.gems.client.CollectorGem;
import org.openquark.gems.client.Gem.PartInput;
import org.openquark.gems.client.navigator.NavAddress.NavAddressMethod;
/**
* A utility class that provides helper methods for working with NavAddresses and
* also for working with metadata.
* @author Frank Worsley
*/
public final class NavAddressHelper {
//
// This class is not intended to be instantiated.
//
private NavAddressHelper() {
}
/**
* Gets metadata for the entity the given address is for. This will also
* validate the metadata so that it has the correct number of arguments for
* the entity the address points to.
* @param owner the navigator owner to use to resolve the address
* @param address the address to get metadata for
* @return the metadata associated with the entity the address points to or
* null if there is no metadata associated with the address
*/
public static CALFeatureMetadata getMetadata(NavFrameOwner owner, NavAddress address) {
CALFeatureMetadata metadata = null;
NavAddressMethod method = address.getMethod();
if (method == NavAddress.WORKSPACE_METHOD || method == NavAddress.SEARCH_METHOD) {
return null;
} else if (method == NavAddress.COLLECTOR_METHOD) {
CollectorGem collector = owner.getCollector(address.getBase());
metadata = collector != null ? collector.getDesignMetadata() : null;
} else {
CALFeatureName featureName = address.toFeatureName();
CALWorkspace workspace = owner.getPerspective().getWorkspace();
if (workspace.getMetaModule(featureName.toModuleName()) != null) {
metadata = workspace.getMetadata(featureName, owner.getLocaleForMetadata());
} else {
return null;
}
}
if (metadata == null) {
return null;
}
if (!isMetadataValid(owner, address, metadata)) {
System.out.println("Invalid or missing metadata for "+address);
return null;
}
// Check if this refers to an argument and return argument metadata if that is the case.
if (address.getParameter(NavAddress.ARGUMENT_PARAMETER) != null) {
int argNum = Integer.parseInt(address.getParameter(NavAddress.ARGUMENT_PARAMETER));
ArgumentMetadata[] arguments;
if (metadata instanceof InstanceMethodMetadata) {
arguments = ((InstanceMethodMetadata) metadata).getArguments();
} else {
arguments = ((FunctionalAgentMetadata) metadata).getArguments();
}
if (argNum < 0 || argNum > arguments.length) {
throw new IllegalArgumentException("argument number is invalid: " + argNum);
}
return arguments[argNum];
}
return metadata;
}
/**
* Saves the given metadata for the entity the given address is for.
* @param owner the navigator owner
* @param address the address of the entity to save the metadata for
* @param metadata the metadata to save
* @return true if save successful, false otherwise
*/
public static boolean saveMetadata(NavFrameOwner owner, NavAddress address, CALFeatureMetadata metadata) {
NavAddressMethod method = address.getMethod();
if (method == NavAddress.WORKSPACE_METHOD || method == NavAddress.SEARCH_METHOD) {
return false;
} else if (address.getParameter(NavAddress.ARGUMENT_PARAMETER) != null) {
// We only want to save changes made to the argument metadata. So get the
// latest parent metadata available and simply replace its argument metadata.
int argNum = Integer.parseInt(address.getParameter(NavAddress.ARGUMENT_PARAMETER));
if (address.getMethod() == NavAddress.INSTANCE_METHOD_METHOD) {
NavAddress parentAddress = NavAddress.getAddress(address.toFeatureName()); // this strips out the &argument=n parameter
CALFeatureMetadata parentFeatureMetadata = getMetadata(owner, parentAddress);
if (parentFeatureMetadata == null) {
return false;
}
InstanceMethodMetadata parentMetadata = (InstanceMethodMetadata)parentFeatureMetadata;
ArgumentMetadata[] arguments = parentMetadata.getArguments();
arguments[argNum] = (ArgumentMetadata) metadata;
parentMetadata.setArguments(arguments);
return saveMetadata(owner, parentAddress, parentMetadata);
} else {
NavAddress parentAddress = address.withAllStripped();
CALFeatureMetadata parentFeatureMetadata = getMetadata(owner, parentAddress);
if (parentFeatureMetadata == null) {
return false;
}
FunctionalAgentMetadata parentMetadata = (FunctionalAgentMetadata)parentFeatureMetadata;
ArgumentMetadata[] arguments = parentMetadata.getArguments();
arguments[argNum] = (ArgumentMetadata) metadata;
parentMetadata.setArguments(arguments);
return saveMetadata(owner, parentAddress, parentMetadata);
}
} else if (method == NavAddress.COLLECTOR_METHOD) {
CollectorGem collector = owner.getCollector(address.getBase());
if (collector == null) {
return false;
}
collector.setDesignMetadata((FunctionMetadata) metadata);
// If a collector is not connected, it means it has no arguments.
if (!collector.getCollectingPart().isConnected()) {
return true;
}
// Set the argument metadata for the PartInputs.
List<PartInput> inputs = collector.getTargetInputs();
ArgumentMetadata[] argMetadata = ((FunctionMetadata) metadata).getArguments();
for (int i = 0; i < argMetadata.length; i++) {
inputs.get(i).setDesignMetadata(argMetadata[i]);
}
return true;
} else {
return owner.getPerspective().getWorkspace().saveMetadata(metadata);
}
}
/**
* Refreshes the given metadata with the latest metadata available for the entity
* this address is for. For a collector this means getting the latest collector
* metadata and setting the argument metadata to the latest metadata from the inputs.
* For other entities this simply means loading the latest metadata from the metadata
* manager.
* @param owner the navigator owner
* @param address the address the metadata object is for
* @param metadata the metadata object to refresh
* @return true if the metadata was refreshed, false otherwise
*/
public static boolean refreshMetadata(NavFrameOwner owner, NavAddress address, CALFeatureMetadata metadata) {
CALFeatureMetadata newMetadata = getMetadata(owner, address);
if (metadata == null) {
return false;
}
newMetadata.copyTo(metadata);
return true;
}
/**
* Checks that the metadata is valid for the entity that this address is for. If it
* is not it will modify the metadata to make it valid, if possible. Currently the only
* thing this checks for is that the number of arguments in the metadata matches the number
* of arguments of the entity. If this is not the case the number of arguments stored
* in the metadata is adjusted.
* @param owner the navigator owner
* @param address the address the metadata is for
* @param metadata the metadata to validate
* @return true if the metadata exists and was successfully validated, false otherwise
*/
private static boolean isMetadataValid(NavFrameOwner owner, NavAddress address, CALFeatureMetadata metadata) {
NavAddressMethod method = address.getMethod();
if (method == NavAddress.FUNCTION_METHOD ||
method == NavAddress.CLASS_METHOD_METHOD ||
method == NavAddress.DATA_CONSTRUCTOR_METHOD) {
GemEntity entity = owner.getPerspective().getWorkspace().getGemEntity(address.toFeatureName().toQualifiedName());
if (entity == null) {
return false;
}
return isMetadataValid(entity, (FunctionalAgentMetadata) metadata);
} else if (method == NavAddress.INSTANCE_METHOD_METHOD) {
CALFeatureName featureName = address.toFeatureName();
QualifiedName typeClassName = featureName.toInstanceIdentifier().getTypeClassName();
String methodName = featureName.toInstanceMethodName();
QualifiedName classMethodName = QualifiedName.make(typeClassName.getModuleName(), methodName);
GemEntity entity = owner.getPerspective().getWorkspace().getGemEntity(classMethodName);
if (entity == null) {
return false;
}
return isMetadataValid(entity, (InstanceMethodMetadata) metadata);
} else if (method == NavAddress.COLLECTOR_METHOD) {
CollectorGem collector = owner.getCollector(address.getBase());
if (collector == null) {
return false;
}
return isMetadataValid(collector, (FunctionMetadata) metadata);
}
return true; // No additional validation for other address types
}
/**
* Validates the given metadata object by synchronizing it with the given entity.
* After calling this method the number of arguments stored by the metadata will
* match the number of arguments of the entity.
* @param entity the entity to validate the metadata with
* @param metadata the metadata to validate
* @return true if the metadata is valid, false otherwise
*/
public static boolean isMetadataValid(GemEntity entity, FunctionalAgentMetadata metadata) {
return isMetadataValid(entity.getFunctionalAgent(), metadata);
}
/**
* Validates the given metadata object by synchronizing it with the given entity.
* After calling this method the number of arguments stored by the metadata will
* match the number of arguments of the entity.
* @param entity the entity to validate the metadata with
* @param metadata the metadata to validate
* @return true if the metadata is valid, false otherwise
*/
public static boolean isMetadataValid(FunctionalAgent entity, FunctionalAgentMetadata metadata) {
int numArgs = entity.getTypeExpr().getArity();
ArgumentMetadata[] actualArgs = new ArgumentMetadata[numArgs];
ArgumentMetadata[] currentArgs = metadata.getArguments();
if (actualArgs.length == currentArgs.length) {
return true;
}
int argsToCopy = currentArgs.length > actualArgs.length ? numArgs : currentArgs.length;
System.arraycopy(currentArgs, 0, actualArgs, 0, argsToCopy);
for (int i = argsToCopy; i < actualArgs.length; i++) {
actualArgs[i] = new ArgumentMetadata(CALFeatureName.getArgumentFeatureName(i), metadata.getLocale());
}
metadata.setArguments(actualArgs);
return true;
}
/**
* Validates the given metadata object by synchronizing it with the given entity.
* After calling this method the number of arguments stored by the metadata will
* match the number of arguments of the entity.
* @param entity the entity to validate the metadata with
* @param metadata the metadata to validate
* @return true if the metadata is valid, false otherwise
*/
public static boolean isMetadataValid(GemEntity entity, InstanceMethodMetadata metadata) {
return isMetadataValid(entity.getFunctionalAgent(), metadata);
}
/**
* Validates the given metadata object by synchronizing it with the given entity.
* After calling this method the number of arguments stored by the metadata will
* match the number of arguments of the entity.
* @param entity the entity to validate the metadata with
* @param metadata the metadata to validate
* @return true if the metadata is valid, false otherwise
*/
private static boolean isMetadataValid(FunctionalAgent entity, InstanceMethodMetadata metadata) {
int numArgs = entity.getTypeExpr().getArity();
ArgumentMetadata[] actualArgs = new ArgumentMetadata[numArgs];
ArgumentMetadata[] currentArgs = metadata.getArguments();
if (actualArgs.length == currentArgs.length) {
return true;
}
int argsToCopy = currentArgs.length > actualArgs.length ? numArgs : currentArgs.length;
System.arraycopy(currentArgs, 0, actualArgs, 0, argsToCopy);
for (int i = argsToCopy; i < actualArgs.length; i++) {
actualArgs[i] = new ArgumentMetadata(CALFeatureName.getArgumentFeatureName(i), metadata.getLocale());
}
metadata.setArguments(actualArgs);
return true;
}
/**
* Validates the given metadata object by synchronizing it with the given collector.
* After calling this method the number of arguments stored by the metadata will
* match the number of arguments of the collector. The stored argument metadata will
* also be updated to the latest metadata stored by the collectors target argument inputs.
* @param collector the collector to validate the metadata with
* @param metadata the metadata to validate
* @return True if the metadata was successfully synchronized with the collector
*/
public static boolean isMetadataValid(CollectorGem collector, FunctionMetadata metadata) {
// For our purposes, if the collecting part of a collector is not connected,
// then that means that the collector has no arguments.
if (!collector.getCollectingPart().isConnected()) {
metadata.setArguments(new ArgumentMetadata[0]);
return true;
}
List<PartInput> inputs = collector.getTargetInputs();
ArgumentMetadata[] actualArgs = new ArgumentMetadata[inputs.size()];
for (int i = 0; i < actualArgs.length; i++) {
actualArgs[i] = inputs.get(i).getDesignMetadata();
}
metadata.setArguments(actualArgs);
return true;
}
/**
* If the given address points to an entity with a TypeExpr, then this method will
* return the String form of the TypeExpr's type pieces. An empty array is returned
* if this address does not point to an entity with a TypeExpr.
* @param owner the navigator owner
* @param address the address to get type strings for
* @param namingPolicy the naming policy to use when toString'ing the TypeExpr
* @return string array with the strings for the type pieces or an empty array
* if the address does not point to an entity with a TypeExpr
*/
public static String[] getTypeStrings(NavFrameOwner owner, NavAddress address, ScopedEntityNamingPolicy namingPolicy) {
NavAddressMethod method = address.getMethod();
if (method == NavAddress.CLASS_METHOD_METHOD ||
method == NavAddress.FUNCTION_METHOD ||
method == NavAddress.DATA_CONSTRUCTOR_METHOD) {
GemEntity entity = owner.getPerspective().getWorkspace().getGemEntity(address.toFeatureName().toQualifiedName());
TypeExpr[] typePieces = entity.getTypeExpr().getTypePieces();
String[] typeStrings = new String[typePieces.length];
PolymorphicVarContext polymorphicVarContext = PolymorphicVarContext.make();
for (int i = 0; i < typePieces.length; i++) {
typeStrings[i] = typePieces[i].toString(polymorphicVarContext, namingPolicy);
}
return typeStrings;
} else if (method == NavAddress.INSTANCE_METHOD_METHOD) {
CALFeatureName featureName = address.toFeatureName();
String methodName = featureName.toInstanceMethodName();
ClassInstance instance = owner.getPerspective().getMetaModule(featureName.toModuleName()).getTypeInfo().getClassInstance(featureName.toInstanceIdentifier());
TypeExpr[] typePieces = instance.getInstanceMethodType(methodName).getTypePieces();
String[] typeStrings = new String[typePieces.length];
PolymorphicVarContext polymorphicVarContext = PolymorphicVarContext.make();
for (int i = 0; i < typePieces.length; i++) {
typeStrings[i] = typePieces[i].toString(polymorphicVarContext, namingPolicy);
}
return typeStrings;
} else if (method == NavAddress.COLLECTOR_METHOD) {
CollectorGem collector = owner.getCollector(address.getBase());
if (collector == null || !collector.getCollectingPart().isConnected()) {
return new String[0];
}
List<PartInput> inputs = collector.getTargetInputs();
String[] typeStrings = new String[inputs.size() + 1];
PolymorphicVarContext polymorphicVarContext = PolymorphicVarContext.make();
for (int i = 0, length = typeStrings.length - 1; i < length; i++) {
typeStrings[i] = inputs.get(i).getType().toString(polymorphicVarContext, namingPolicy);
}
typeStrings[typeStrings.length - 1] = collector.getCollectingPart().getType().toString(polymorphicVarContext, namingPolicy);
return typeStrings;
}
return new String[0];
}
/**
* Determines the best display name to use for the entity the address points to.
* If the entity is a scoped entity the QUALIFIED naming policy is used.
* @param owner the navigator owner
* @param address the address to get display text for
* @return the display text for this address
*/
public static String getDisplayText(NavFrameOwner owner, NavAddress address) {
return getDisplayText(owner, address, ScopedEntityNamingPolicy.FULLY_QUALIFIED);
}
/**
* Determines the best display name to use for the entity the address points to.
* If the entity is a scoped entity then the provided naming policy will be used.
* @param owner the navigator owner
* @param address the address to get display text for
* @param namingPolicy the naming policy
* @return the display text for this address
*/
public static String getDisplayText(NavFrameOwner owner, NavAddress address, ScopedEntityNamingPolicy namingPolicy) {
CALFeatureMetadata metadata = getMetadata(owner, address);
NavAddressMethod method = address.getMethod();
// If this feature has no metadata, then there is nothing
// sensible that we can say about it. Just return the
// raw text.
if (metadata == null) {
return address.getBase();
}
if (address.getParameter(NavAddress.ARGUMENT_PARAMETER) != null) {
int argNum = Integer.parseInt(address.getParameter(NavAddress.ARGUMENT_PARAMETER));
if (address.getMethod() == NavAddress.INSTANCE_METHOD_METHOD) {
NavAddress parentAddress = NavAddress.getAddress(address.toFeatureName()); // this strips out the &argument=n parameter
CALFeatureMetadata parentFeatureMetadata = getMetadata(owner, parentAddress);
InstanceMethodMetadata parentMetadata = (InstanceMethodMetadata)parentFeatureMetadata;
ArgumentMetadata[] argMetadata = parentMetadata.getArguments();
adjustArgumentNames(owner, address, argMetadata);
return argMetadata[argNum].getDisplayName();
} else {
FunctionalAgentMetadata parentMetadata = (FunctionalAgentMetadata)getMetadata(owner, address.withAllStripped());
ArgumentMetadata[] argMetadata = parentMetadata.getArguments();
adjustArgumentNames(owner, address.withAllStripped(), argMetadata);
return argMetadata[argNum].getDisplayName();
}
} else if (method == NavAddress.MODULE_METHOD) {
String vault = address.getParameter(NavAddress.VAULT_PARAMETER);
String name = metadata.getDisplayName() != null ? metadata.getDisplayName() : address.getBase();
if (vault == null) {
return name;
} else if (vault.equals(NavAddress.TYPE_VAULT_VALUE)) {
return name + NavigatorMessages.getString("NAV_ModuleTypeVault");
} else if (vault.equals(NavAddress.INSTANCE_VAULT_VALUE)) {
return name + NavigatorMessages.getString("NAV_ModuleInstanceVault");
} else if (vault.equals(NavAddress.CLASS_VAULT_VALUE)) {
return name + NavigatorMessages.getString("NAV_ModuleClassVault");
} else if (vault.equals(NavAddress.FUNCTION_VAULT_VALUE)) {
return name + NavigatorMessages.getString("NAV_ModuleFunctionVault");
}
} else if (method == NavAddress.COLLECTOR_METHOD) {
// Special case collectors since the CAL name of the metadata always
// returns the default collector name.
CollectorGem collector = owner.getCollector(address.getBase());
if (metadata.getDisplayName() != null) {
return metadata.getDisplayName();
}
return collector != null ? collector.getUnqualifiedName() : "Unknown Collector";
} else if (method == NavAddress.CLASS_INSTANCE_METHOD) {
ClassInstance instance = owner.getPerspective().getWorkspace().getClassInstance(address.toFeatureName());
if (metadata.getDisplayName() != null) {
return metadata.getDisplayName();
} else if (instance == null) {
return address.toString();
} else if (namingPolicy != null) {
return instance.getNameWithContext(namingPolicy);
} else {
return instance.getNameWithContext();
}
} else if (method == NavAddress.INSTANCE_METHOD_METHOD) {
String methodName = address.toFeatureName().toInstanceMethodName();
if (metadata.getDisplayName() != null) {
return metadata.getDisplayName();
} else {
return methodName;
}
} else {
CALFeatureName featureName = metadata.getFeatureName();
ScopedEntity entity = owner.getPerspective().getWorkspace().getScopedEntity(featureName);
if (metadata.getDisplayName() != null) {
return metadata.getDisplayName();
} else if (entity == null) {
return address.toString();
} else if (namingPolicy != null) {
return entity.getAdaptedName(namingPolicy);
} else {
return entity.getName().getQualifiedName();
}
}
return address.toString();
}
/**
* Assigns default argument names to the display names of the given argument metadata. If an argument has
* no name this will either assign the default argument name or try to use another name as a base name.
* The other name may be a name from CAL code or the original name of an argument. If the argument already
* has a display name, then that name will not be changed.
* @param owner the navigator owner
* @param address the address of the entity the arguments belong to
* @param arguments the argument metadata objects to adjust
*/
public static void adjustArgumentNames(NavFrameOwner owner, NavAddress address, ArgumentMetadata[] arguments) {
if (address.getMethod() == NavAddress.COLLECTOR_METHOD) {
CollectorGem collector = owner.getCollector(address.getBase());
adjustArgumentNames(collector, arguments);
} else if (address.getMethod() == NavAddress.INSTANCE_METHOD_METHOD) {
CALFeatureName featureName = address.toFeatureName();
ModuleName typeClassModuleName = featureName.toInstanceIdentifier().getTypeClassName().getModuleName();
String methodName = featureName.toInstanceMethodName();
CALWorkspace workspace = owner.getPerspective().getWorkspace();
GemEntity entity = workspace.getGemEntity(QualifiedName.make(typeClassModuleName, methodName));
ClassInstance instance = workspace.getClassInstance(CALFeatureName.getClassInstanceFeatureName(featureName.toInstanceIdentifier(), featureName.toModuleName()));
adjustArgumentNames(entity, instance.getMethodCALDocComment(methodName), arguments);
} else {
GemEntity entity = owner.getPerspective().getWorkspace().getGemEntity(address.toFeatureName().toQualifiedName());
adjustArgumentNames(entity, arguments);
}
}
/**
* @see #adjustArgumentNames(NavFrameOwner, NavAddress, ArgumentMetadata[])
*/
public static void adjustArgumentNames(CollectorGem collector, ArgumentMetadata[] arguments) {
if (!collector.getCollectingPart().isConnected()) {
return;
}
List<PartInput> inputs = collector.getTargetInputs();
String[] originalNames = new String[inputs.size()];
for (int i = 0; i < originalNames.length; i++) {
originalNames[i] = inputs.get(i).getArgumentName().getCompositeName();
}
adjustArgumentNames(originalNames, false, null, arguments);
}
/**
* @see #adjustArgumentNames(NavFrameOwner, NavAddress, ArgumentMetadata[])
*/
public static void adjustArgumentNames(GemEntity entity, ArgumentMetadata[] arguments) {
adjustArgumentNames(entity.getFunctionalAgent(), arguments);
}
/**
* @see #adjustArgumentNames(NavFrameOwner, NavAddress, ArgumentMetadata[])
*/
public static void adjustArgumentNames(GemEntity entity, CALDocComment caldoc, ArgumentMetadata[] arguments) {
adjustArgumentNames(entity.getFunctionalAgent(), caldoc, arguments);
}
/**
* @see #adjustArgumentNames(NavFrameOwner, NavAddress, ArgumentMetadata[])
*/
public static void adjustArgumentNames(FunctionalAgent entity, ArgumentMetadata[] arguments) {
adjustArgumentNames(entity, entity.getCALDocComment(), arguments);
}
/**
* @see #adjustArgumentNames(NavFrameOwner, NavAddress, ArgumentMetadata[])
*/
public static void adjustArgumentNames(FunctionalAgent entity, CALDocComment caldoc, ArgumentMetadata[] arguments) {
int numNames = entity.getNArgumentNames();
String[] codeNames = new String[numNames];
for (int i = 0; i < numNames; i++) {
codeNames[i] = entity.getArgumentName(i);
}
adjustArgumentNames(codeNames, true, caldoc, arguments);
}
/**
* Assigns default argument display names to the arguments that do not have a display
* name. Also disambiguates display names of the arguments.
* @param originalNames original names that can be used if there's no existing name
* @param originalNamesFromEntity whether the original names came from the gem entity
* @param caldoc the CALDoc that may contain '@arg' blocks declaring argument names, or null if there is none.
* @param arguments array of argument metadata for which to adjust the display names
*/
private static void adjustArgumentNames(String[] originalNames, boolean originalNamesFromEntity, CALDocComment caldoc, ArgumentMetadata[] arguments) {
Map<String, Integer> argNameToFrequencyMap = new HashMap<String, Integer>();
Map<String, Integer> argNameToSuffixMap = new HashMap<String, Integer>();
// Assign the original and default names and count the frequency of each argument name.
for (int i = 0; i < arguments.length; i++) {
String argName = arguments[i].getDisplayName();
if (argName == null) {
String nameFromCALDoc = null;
if (caldoc != null && i < caldoc.getNArgBlocks()) {
FieldName argNameAsFieldName = caldoc.getNthArgBlock(i).getArgName();
if (argNameAsFieldName instanceof FieldName.Textual) {
nameFromCALDoc = argNameAsFieldName.getCalSourceForm();
}
}
String originalName = null;
if (i < originalNames.length) {
originalName = originalNames[i];
}
if (originalNamesFromEntity) {
// if the CALDoc name is present, we will use it instead of the name from the gem entity
// since the CALDoc name is specified by the user, where the name from the gem entity
// may have come from an automatically extracted parameter name for a foreign function
if (nameFromCALDoc != null) {
argName = nameFromCALDoc;
} else if (originalName != null) {
argName = originalName;
} else {
argName = ArgumentMetadata.DEFAULT_ARGUMENT_NAME;
}
} else {
// since the original names do not come from the gem entity,
// they take precedence over the names in the CALDoc
if (originalName != null) {
argName = originalName;
} else if (nameFromCALDoc != null) {
argName = nameFromCALDoc;
} else {
argName = ArgumentMetadata.DEFAULT_ARGUMENT_NAME;
}
}
arguments[i].setDisplayName(argName);
}
Integer frequency = argNameToFrequencyMap.get(argName);
frequency = frequency != null ? Integer.valueOf(frequency.intValue() + 1) : Integer.valueOf(1);
argNameToFrequencyMap.put(argName, frequency);
}
// Disambiguate the names that occur more than once.
for (final ArgumentMetadata argumentMetadata : arguments) {
String argName = argumentMetadata.getDisplayName();
int frequency = argNameToFrequencyMap.get(argName).intValue();
if (frequency > 1) {
Integer suffix = argNameToSuffixMap.get(argName);
suffix = suffix != null ? Integer.valueOf(suffix.intValue() + 1) : Integer.valueOf(1);
argNameToSuffixMap.put(argName, suffix);
argName = argName + "_" + suffix;
argumentMetadata.setDisplayName(argName);
}
}
}
}