/* * 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. */ /* * MetaModule.java * Creation date: Oct 2, 2002. * By: Edward Lam */ package org.openquark.cal.services; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.openquark.cal.compiler.ClassInstance; import org.openquark.cal.compiler.DataConstructor; import org.openquark.cal.compiler.FunctionalAgent; import org.openquark.cal.compiler.ModuleName; import org.openquark.cal.compiler.ModuleTypeInfo; import org.openquark.cal.compiler.QualifiedName; import org.openquark.cal.compiler.TypeClass; import org.openquark.cal.compiler.TypeConstructor; import org.openquark.cal.machine.Module; import org.openquark.cal.metadata.CALFeatureMetadata; import org.openquark.cal.metadata.MetadataManager; import org.openquark.cal.metadata.ModuleMetadata; /** * A metamodule encapsulates a module and all related metadata, including source (if any). * @author Edward Lam */ public class MetaModule { /** the compiled machine-specific module code */ private final Module module; /** Map from entity name to the entities held by this module */ private final Map<String, GemEntity> nameToEntityMap; /** List of EnvEntities in this module, in the order that they were added. */ private final List<GemEntity> gemEntityList; /** The manager to manage resources for this module. */ private final VirtualResourceManager virtualResourceManager; /** * Constructor for a MetaModule. * @param module the compiled machine-specific module code. * @param virtualResourceManager the resource manager for the workspace. */ MetaModule(Module module, VirtualResourceManager virtualResourceManager) { this.module = module; this.virtualResourceManager = virtualResourceManager; nameToEntityMap = new HashMap<String, GemEntity>(); gemEntityList = new ArrayList<GemEntity>(); // Populate entity map and list from the module. ModuleTypeInfo typeInfo = module.getModuleTypeInfo(); if (typeInfo != null) { FunctionalAgent[] entities = typeInfo.getFunctionalAgents(); for (int i = 0; i < entities.length; ++i) { FunctionalAgent envEntity = entities [i]; addGemEntity(new GemEntity(envEntity, virtualResourceManager)); } } } /** * Add an entity to this module. * @param gemEntity the entity to add. */ public void addGemEntity(GemEntity gemEntity) { QualifiedName entityName = gemEntity.getName(); if (!entityName.getModuleName().equals(getName())) { throw new IllegalArgumentException("Entity must be a member of module: " + getName()); } GemEntity oldValue = nameToEntityMap.put(gemEntity.getName().getUnqualifiedName(), gemEntity); if (oldValue == null) { gemEntityList.add(gemEntity); } else { // Replacing an old value int oldValueIndex = gemEntityList.indexOf(oldValue); gemEntityList.set(oldValueIndex, gemEntity); } } /** * Get the name of the module. * @return the name of the module */ public ModuleName getName() { return module.getName(); } /** * @return the type info for this module. */ public ModuleTypeInfo getTypeInfo() { return module.getModuleTypeInfo(); } /** * @return the module associated with this MetaModule. */ public Module getModule(){ return module; } /** * Get an entity * @param entityName the unqualified name of the entity * @return the corresponding entity, or null if the entity does not exist in this module. */ public GemEntity getGemEntity(String entityName) { return nameToEntityMap.get(entityName); } /** * Get the number of entities in this module * @return int the number of entities in this module. */ public int getNGemEntities() { return gemEntityList.size(); } /** * Get the nth entity in this module. * @param n 0-based index of the entity to get * @return the nth entity in this module. */ public GemEntity getNthGemEntity(int n) { return gemEntityList.get(n); } /** * Method getImportedModule. * @param workspace * @param importedModuleName * @return ModuleTypeInfo the imported module or null if the module does not import a module with the given name. */ public MetaModule getImportedModule(CALWorkspace workspace, ModuleName importedModuleName) { ModuleTypeInfo importedTypeInfo = module.getModuleTypeInfo().getImportedModule(importedModuleName); return importedTypeInfo == null ? null : workspace.getMetaModule(importedModuleName); } /** * Method getNImportedModules. * @return int the number of modules directly imported into this module. */ public int getNImportedModules() { return module.getModuleTypeInfo().getNImportedModules(); } /** * Method getNthImportedModule. * @param workspace * @param n zero based index * @return ModuleTypeInfo the nth module imported by this module */ public MetaModule getNthImportedModule(CALWorkspace workspace, int n) { return workspace.getMetaModule(module.getModuleTypeInfo().getNthImportedModule(n).getModuleName()); } /** * @param typeConstructorName the name of the type constructor * @return An array with all visible data constructors for the type constructor. * This will be null if the type constructor is not visible or zero length if it has * no visible data constructors. */ public DataConstructor[] getDataConstructorsForType(QualifiedName typeConstructorName) { ModuleTypeInfo currentModuleTypeInfo = module.getModuleTypeInfo(); TypeConstructor typeCons = currentModuleTypeInfo.getVisibleTypeConstructor(typeConstructorName); if (typeCons == null) { return null; } List<DataConstructor> dataConsList = new ArrayList<DataConstructor>(); for (int n = 0, numDataCons = typeCons.getNDataConstructors(); n < numDataCons; n++) { DataConstructor dataCons = typeCons.getNthDataConstructor(n); if (currentModuleTypeInfo.isEntityVisible(dataCons)) { dataConsList.add(dataCons); } } return dataConsList.toArray(new DataConstructor[0]); } /** * Determines all type constructors visible from this module and returns their * type constructor entities. The returned array will be zero-length if there are no * visible types. * @return an array of all visible type constructors */ public TypeConstructor[] getTypeConstructors() { List<TypeConstructor> types = new ArrayList<TypeConstructor>(); ModuleTypeInfo moduleTypeInfo = getTypeInfo(); for (int n = 0, numTypes = moduleTypeInfo.getNTypeConstructors(); n < numTypes; n++) { types.add(moduleTypeInfo.getNthTypeConstructor(n)); } // check for types in the imported modules for (int n = 0, numImports = moduleTypeInfo.getNImportedModules(); n < numImports; n++) { ModuleTypeInfo importedInfo = moduleTypeInfo.getNthImportedModule(n); for (int c = 0, numTypes = importedInfo.getNTypeConstructors(); c < numTypes; c++) { TypeConstructor typeCons = importedInfo.getNthTypeConstructor(c); if (moduleTypeInfo.isEntityVisible(typeCons)) { types.add(typeCons); } } } return types.toArray(new TypeConstructor[0]); } /** * Find out whether a given type constructor is an Enum type with respect to this module. * What this means is that the type is an algebraic data type (introduced by a non-foreign data declaration), * all data constructors have arity 0, and there is at least one data constructor. * @param typeConstructorName the name of the type constructor * @return boolean True if the type constructor exists and is an "enum" (ie. all data constructors take 0 arguments). * False otherwise. */ public boolean isEnumDataType(QualifiedName typeConstructorName) { ModuleTypeInfo currentModuleTypeInfo = module.getModuleTypeInfo(); TypeConstructor typeCons = currentModuleTypeInfo.getVisibleTypeConstructor(typeConstructorName); if (typeCons == null) { return false; } int nDataCons = typeCons.getNDataConstructors(); if (nDataCons == 0) { return false; } boolean hasVisibleConstructor = false; for (int i = 0; i < nDataCons; ++i) { DataConstructor dataCons = typeCons.getNthDataConstructor(i); if (currentModuleTypeInfo.isEntityVisible(dataCons)) { int arity = dataCons.getArity(); if (arity > 0) { return false; } hasVisibleConstructor = true; } } return hasVisibleConstructor; } /** * {@inheritDoc} */ @Override public String toString() { // todo: add entities. return "Metamodule " + getName() + "\nModule: " + module; } /** * @param locale the locale associated with the metadata. * @return the metadata for the module. If the module has no metadata, then default metadata is returned. */ public ModuleMetadata getMetadata(Locale locale) { MetadataManager metadataManager = virtualResourceManager.getMetadataManager(getName()); if (metadataManager == null) { return MetadataManager.getEmptyMetadata(this, locale); } return metadataManager.getMetadata(this, locale); } /** * @param featureName the name of a feature in this module. * @param locale the locale associated with the metadata. * @return the metadata for the feature. If the feature has no metadata, then default metadata is returned. */ public CALFeatureMetadata getMetadata(CALFeatureName featureName, Locale locale) { if (!(featureName.hasModuleName() && featureName.toModuleName().equals(getName()))) { throw new IllegalArgumentException("Feature must be a member of module: " + getName()); } MetadataManager metadataManager = virtualResourceManager.getMetadataManager(getName()); if (metadataManager == null) { return MetadataManager.getEmptyMetadata(featureName, locale); } return metadataManager.getMetadata(featureName, locale); } /** * Returns a List of ResourceNames for the metadata resources associated with the given feature name, across all locales. * @param featureName the name of the feature whose metadata resources across all locales are to be enumerated. * @return a List of ResourceNames, one for each localized metadata resource associated with the given feature name. */ public List<ResourceName> getMetadataResourceNamesForAllLocales(CALFeatureName featureName) { if (!(featureName.hasModuleName() && featureName.toModuleName().equals(getName()))) { throw new IllegalArgumentException("Feature must be a member of module: " + getName()); } MetadataManager metadataManager = virtualResourceManager.getMetadataManager(getName()); if (metadataManager == null) { return Collections.emptyList(); } return metadataManager.getMetadataResourceNamesForAllLocales(featureName); } /** * Get the features associated with this metamodule. * @return the names of features associated with this module. */ public Set<CALFeatureName> getFeatureNames() { // CALFeatureNames for all features in the current program. Set<CALFeatureName> programFeatureNameSet = new HashSet<CALFeatureName>(); // Grab the module names and feature names. ModuleTypeInfo moduleInfo = module.getModuleTypeInfo(); // Module name. programFeatureNameSet.add(CALFeatureName.getModuleFeatureName(this)); // Functional agents. FunctionalAgent[] entities = moduleInfo.getFunctionalAgents(); for (final FunctionalAgent entity : entities) { programFeatureNameSet.add(CALFeatureName.getScopedEntityFeatureName(entity)); } // Type constructors. int constructorCount = moduleInfo.getNTypeConstructors(); for (int i = 0; i < constructorCount; i++) { TypeConstructor typeConstructor = moduleInfo.getNthTypeConstructor(i); programFeatureNameSet.add(CALFeatureName.getScopedEntityFeatureName(typeConstructor)); // Data constructors. int dataConstructorCount = typeConstructor.getNDataConstructors(); for (int n = 0; n < dataConstructorCount; n++) { DataConstructor dataConstructor = typeConstructor.getNthDataConstructor(n); programFeatureNameSet.add(CALFeatureName.getScopedEntityFeatureName(dataConstructor)); } } // Type classes. int classCount = moduleInfo.getNTypeClasses(); for (int i = 0; i < classCount; i++) { TypeClass typeClass = moduleInfo.getNthTypeClass(i); programFeatureNameSet.add(CALFeatureName.getScopedEntityFeatureName(typeClass)); // Class methods. int methodCount = typeClass.getNClassMethods(); for (int n = 0; n < methodCount; n++) { programFeatureNameSet.add(CALFeatureName.getScopedEntityFeatureName(typeClass.getNthClassMethod(n))); } } // Class instances. int instanceCount = moduleInfo.getNClassInstances(); for (int n = 0; n < instanceCount; n++) { ClassInstance instance = moduleInfo.getNthClassInstance(n); programFeatureNameSet.add(CALFeatureName.getClassInstanceFeatureName(instance)); // Instance methods. TypeClass typeClass = instance.getTypeClass(); int methodCount = typeClass.getNClassMethods(); for (int k = 0; k < methodCount; k++) { String methodName = typeClass.getNthClassMethod(k).getName().getUnqualifiedName(); programFeatureNameSet.add(CALFeatureName.getInstanceMethodFeatureName(instance, methodName)); } } return programFeatureNameSet; } }