/*
* 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.
*/
/*
* MetadataPathMapper.java
* Creation date: Nov 23, 2004.
* By: Edward Lam
*/
package org.openquark.cal.metadata;
import java.util.Locale;
import org.openquark.cal.compiler.ClassInstanceIdentifier;
import org.openquark.cal.compiler.LanguageInfo;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.services.CALFeatureName;
import org.openquark.cal.services.FeatureName;
import org.openquark.cal.services.FileSystemResourceHelper;
import org.openquark.cal.services.LocaleUtilities;
import org.openquark.cal.services.LocalizedResourceName;
import org.openquark.cal.services.ResourceName;
import org.openquark.cal.services.ResourcePath;
import org.openquark.cal.services.ResourcePathMapper;
import org.openquark.cal.services.FeatureName.FeatureType;
import org.openquark.cal.services.ResourcePath.FilePath;
import org.openquark.cal.services.ResourcePath.Folder;
/**
* A ResourcePathMapper for Metadata resources.
* @author Edward Lam
*/
public class MetadataPathMapper implements ResourcePathMapper.Module {
/** The file extension for metadata files. */
private static final String METADATA_FILE_EXTENSION = "metadata.xml";
/** The name of the metadata base folder. */
private static final String METADATA_BASE_FOLDER_NAME = "Metadata";
/** The subfolder that contains function metadata files. */
private static final String METADATA_FUNCTION_FOLDER = "Functions";
/** The subfolder that contains class method metadata files. */
private static final String METADATA_CLASS_METHOD_FOLDER = "Class Methods";
/** The subfolder that contains data constructor metadata files. */
private static final String METADATA_DATA_CONSTRUCTOR_FOLDER = "Data Constructors";
/** The subfolder that contains type class metadata files. */
private static final String METADATA_TYPE_CLASS_FOLDER = "Type Classes";
/** The subfolder that contains type constructor metadata files. */
private static final String METADATA_TYPE_CONSTRUCTOR_FOLDER = "Type Constructors";
/** The subfolder that contains class instance metadata files. */
private static final String METADATA_CLASS_INSTANCE_FOLDER = "Class Instances";
/** The subfolder that contains instance method metadata files. */
private static final String METADATA_INSTANCE_METHOD_FOLDER = "Instance Methods";
/** The disambiguating prefix in front of a locale specifier in a generated file name. */
private static final String METADATA_LOCALE_PREFIX = "--"; // must be a string that is not generated by the FileSystemResouceHelper.getFileSystemName mapping.
/** The base folder for this resource. */
private static final ResourcePath.Folder baseMetadataFolder = new ResourcePath.Folder(new String[] {METADATA_BASE_FOLDER_NAME});
/** Singleton instance. */
public static final MetadataPathMapper INSTANCE = new MetadataPathMapper();
/**
* Constructor for a MetadataPathMapper.
*/
private MetadataPathMapper() {
}
/**
* {@inheritDoc}
*/
public Folder getBaseResourceFolder() {
return baseMetadataFolder;
}
/**
* {@inheritDoc}
*/
public ResourcePath getModuleResourcePath(ModuleName moduleName) {
String moduleFolderName = FileSystemResourceHelper.getFileSystemName(moduleName.toSourceText());
return baseMetadataFolder.extendFolder(moduleFolderName);
}
/**
* {@inheritDoc}
*/
public ModuleName getModuleNameFromResourcePath(ResourcePath moduleResourcePath) {
return ModuleName.make(FileSystemResourceHelper.fromFileSystemName(moduleResourcePath.getName()));
}
/**
* {@inheritDoc}
*/
public FilePath getResourcePath(ResourceName resourceName) {
FeatureName featureName = resourceName.getFeatureName();
String featureString = getFeatureString(featureName);
String fileSystemName = FileSystemResourceHelper.getFileSystemName(featureString);
Locale locale = LocalizedResourceName.localeOf(resourceName);
String fileName;
if (!LocaleUtilities.isInvariantLocale(locale)) {
fileName = fileSystemName + "." + METADATA_LOCALE_PREFIX + LocaleUtilities.localeToCanonicalString(locale) + "." + METADATA_FILE_EXTENSION;
} else {
fileName = fileSystemName + "." + METADATA_FILE_EXTENSION;
}
return getFeatureFolder(featureName).extendFile(fileName);
}
/**
* {@inheritDoc}
*/
public ResourceName getResourceNameFromPath(FilePath path) {
return getResourceNameFromFolderAndFileName(path.getFolder(), path.getFileName());
}
/**
* {@inheritDoc}
*/
public ResourceName getResourceNameFromFolderAndFileName(Folder folder, String fileName) {
String[] pathElementsOfFolder = folder.getPathElements();
if (pathElementsOfFolder.length < 1) {
return null;
}
FeatureType featureType = getFeatureTypeFromFolderPathElements(pathElementsOfFolder);
ModuleName moduleName;
if (featureType == CALFeatureName.MODULE) {
moduleName = ModuleName.make(FileSystemResourceHelper.fromFileSystemName(pathElementsOfFolder[pathElementsOfFolder.length - 1]));
} else {
if (pathElementsOfFolder.length < 2) {
return null;
}
moduleName = ModuleName.make(FileSystemResourceHelper.fromFileSystemName(pathElementsOfFolder[pathElementsOfFolder.length - 2]));
}
String extensionWithDot = "." + METADATA_FILE_EXTENSION;
if (fileName.endsWith(extensionWithDot)) {
String strippedFileName = fileName.substring(0, fileName.length() - extensionWithDot.length());
int lastDotInStrippedFileName = strippedFileName.lastIndexOf('.');
if (lastDotInStrippedFileName == -1) {
// no locale
String featureString = FileSystemResourceHelper.fromFileSystemName(strippedFileName);
return new LocalizedResourceName(getFeatureNameFromFeatureString(moduleName, featureType, featureString), LocaleUtilities.INVARIANT_LOCALE);
} else {
String maybeLocaleString = strippedFileName.substring(lastDotInStrippedFileName + 1);
if (maybeLocaleString.startsWith(METADATA_LOCALE_PREFIX)) {
String localeString = maybeLocaleString.substring(METADATA_LOCALE_PREFIX.length());
Locale locale = LocaleUtilities.localeFromCanonicalString(localeString);
String featureString = FileSystemResourceHelper.fromFileSystemName(strippedFileName.substring(0, lastDotInStrippedFileName));
return new LocalizedResourceName(getFeatureNameFromFeatureString(moduleName, featureType, featureString), locale);
} else {
// no locale
String featureString = FileSystemResourceHelper.fromFileSystemName(strippedFileName);
return new LocalizedResourceName(getFeatureNameFromFeatureString(moduleName, featureType, featureString), LocaleUtilities.INVARIANT_LOCALE);
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
public String getFileExtension() {
return METADATA_FILE_EXTENSION;
}
/**
* @param featureName the name of a CAL feature.
* @return the directory path in which the feature's metadata should be stored.
*/
public ResourcePath.Folder getFeatureFolder(FeatureName featureName) {
if (!(featureName instanceof CALFeatureName && ((CALFeatureName)featureName).hasModuleName())) {
throw new IllegalArgumentException("The feature name must represent a cal feature, not the type " + featureName.getType());
}
FeatureType type = featureName.getType();
ModuleName moduleName = ((CALFeatureName)featureName).toModuleName();
return getFeatureFolder(moduleName, type);
}
/**
* @param moduleName the name of a CAL module.
* @param featureType the type of a CAL feature.
* @return the folder in which the feature's metadata should be stored.
*/
public ResourcePath.Folder getFeatureFolder(ModuleName moduleName, FeatureType featureType) {
// Get the subfolder corresponding to the feature type.
String entityFolder = null;
if (featureType == CALFeatureName.MODULE) {
entityFolder = "";
} else if (featureType == CALFeatureName.FUNCTION) {
entityFolder = METADATA_FUNCTION_FOLDER;
} else if (featureType == CALFeatureName.CLASS_METHOD) {
entityFolder = METADATA_CLASS_METHOD_FOLDER;
} else if (featureType == CALFeatureName.DATA_CONSTRUCTOR) {
entityFolder = METADATA_DATA_CONSTRUCTOR_FOLDER;
} else if (featureType == CALFeatureName.TYPE_CLASS) {
entityFolder = METADATA_TYPE_CLASS_FOLDER;
} else if (featureType == CALFeatureName.TYPE_CONSTRUCTOR) {
entityFolder = METADATA_TYPE_CONSTRUCTOR_FOLDER;
} else if (featureType == CALFeatureName.CLASS_INSTANCE) {
entityFolder = METADATA_CLASS_INSTANCE_FOLDER;
} else if (featureType == CALFeatureName.INSTANCE_METHOD) {
entityFolder = METADATA_INSTANCE_METHOD_FOLDER;
} else {
throw new IllegalArgumentException("feature type not supported: " + featureType);
}
// Determine the path to the metadata file
return ((ResourcePath.Folder)getModuleResourcePath(moduleName)).extendFolder(entityFolder);
}
/**
* Returns the feature type associated with a piece of metadata as represented by the path of the metadata resource.
* @param pathElementsOfFolder the elements of the path of the folder containing the metadata resource.
* @return the corresponding feature type.
*/
private FeatureType getFeatureTypeFromFolderPathElements(String[] pathElementsOfFolder) {
String lastElement = pathElementsOfFolder[pathElementsOfFolder.length - 1];
if (lastElement.equals(METADATA_FUNCTION_FOLDER)) {
return CALFeatureName.FUNCTION;
} else if (lastElement.equals(METADATA_CLASS_METHOD_FOLDER)) {
return CALFeatureName.CLASS_METHOD;
} else if (lastElement.equals(METADATA_DATA_CONSTRUCTOR_FOLDER)) {
return CALFeatureName.DATA_CONSTRUCTOR;
} else if (lastElement.equals(METADATA_TYPE_CLASS_FOLDER)) {
return CALFeatureName.TYPE_CLASS;
} else if (lastElement.equals(METADATA_TYPE_CONSTRUCTOR_FOLDER)) {
return CALFeatureName.TYPE_CONSTRUCTOR;
} else if (lastElement.equals(METADATA_CLASS_INSTANCE_FOLDER)) {
return CALFeatureName.CLASS_INSTANCE;
} else if (lastElement.equals(METADATA_INSTANCE_METHOD_FOLDER)) {
return CALFeatureName.INSTANCE_METHOD;
} else {
return CALFeatureName.MODULE;
}
}
/**
* @param featureName the name of the feature.
* @return the string to use to look up that feature.
*/
private String getFeatureString(FeatureName featureName) {
FeatureType type = featureName.getType();
if (featureName instanceof CALFeatureName) {
CALFeatureName calFeatureName = (CALFeatureName)featureName;
// Determine the path to the metadata file
if (calFeatureName.isScopedEntityName()) {
return calFeatureName.toQualifiedName().getUnqualifiedName();
} else if (type == CALFeatureName.MODULE) {
return featureName.getName();
} else if (type == CALFeatureName.CLASS_INSTANCE) {
ClassInstanceIdentifier identifier = calFeatureName.toInstanceIdentifier();
return identifier.getTypeClassName().getQualifiedName() +
" " +
identifier.getTypeIdentifier();
} else if (type == CALFeatureName.INSTANCE_METHOD) {
ClassInstanceIdentifier identifier = calFeatureName.toInstanceIdentifier();
return identifier.getTypeClassName().getQualifiedName() +
" " +
identifier.getTypeIdentifier() +
"@" +
calFeatureName.toInstanceMethodName();
}
}
throw new IllegalArgumentException("feature type not supported: " + type);
}
/**
* Returns the feature name associated with a piece of metadata as represented by its corresponding "feature string".
* @param moduleName the name of the module associated with the faeture.
* @param featureType the feature type of the feature.
* @param featureString the feature string.
* @return the corresponding feature name.
*/
private FeatureName getFeatureNameFromFeatureString(ModuleName moduleName, FeatureType featureType, String featureString) {
if (featureType == CALFeatureName.MODULE) {
return CALFeatureName.getModuleFeatureName(moduleName);
} else if (featureType == CALFeatureName.CLASS_INSTANCE) {
// Get the index of the space separating the type class from the type name.
int spaceIndex = featureString.indexOf(" ");
if (spaceIndex < 0) {
throw new IllegalArgumentException();
}
// Get the two parts.
String typeClassString = featureString.substring(0, spaceIndex);
String typeIdentifier = featureString.substring(spaceIndex + 1);
if (!QualifiedName.isValidCompoundName(typeClassString)) {
throw new IllegalArgumentException();
}
// Convert to qualified name.
QualifiedName typeClassName = QualifiedName.makeFromCompoundName(typeClassString);
return CALFeatureName.getClassInstanceFeatureName(ClassInstanceIdentifier.make(typeClassName, typeIdentifier), moduleName);
} else if (featureType == CALFeatureName.INSTANCE_METHOD) {
// Get the index of the space separating the type class from the type name.
int spaceIndex = featureString.indexOf(" ");
if (spaceIndex < 0) {
throw new IllegalArgumentException();
}
// Get the index of the '@' separating the type name from the method name.
int atIndex = featureString.indexOf("@");
if (atIndex < 0) {
throw new IllegalArgumentException();
}
// Get the three parts.
String typeClassString = featureString.substring(0, spaceIndex);
String typeIdentifier = featureString.substring(spaceIndex + 1, atIndex);
String methodName = featureString.substring(atIndex + 1);
if (!QualifiedName.isValidCompoundName(typeClassString)) {
throw new IllegalArgumentException();
}
if (!LanguageInfo.isValidClassMethodName(methodName)) {
throw new IllegalArgumentException();
}
// Convert to qualified name.
QualifiedName typeClassName = QualifiedName.makeFromCompoundName(typeClassString);
return CALFeatureName.getInstanceMethodFeatureName(ClassInstanceIdentifier.make(typeClassName, typeIdentifier), moduleName, methodName);
} else if (CALFeatureName.isScopedEntityFeatureType(featureType)) {
return new CALFeatureName(featureType, QualifiedName.make(moduleName, featureString).getQualifiedName());
} else {
throw new IllegalArgumentException("feature type not supported: " + featureType);
}
}
}