/* * 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); } } }