All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kurento.modulecreator.definition.ModuleDefinition Maven / Gradle / Ivy

Go to download

Tool that generates code for RPC between the Kurento Media Server and remote libraries.

There is a newer version: 7.1.0
Show newest version
/*
 * (C) Copyright 2016 Kurento (http://kurento.org/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.kurento.modulecreator.definition;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.kurento.modulecreator.KurentoModuleCreatorException;
import org.kurento.modulecreator.ModuleManager;
import org.kurento.modulecreator.VersionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ModuleDefinition {

  private static final String FILTERS_MODULE = "filters";
  private static final String ELEMENTS_MODULE = "elements";
  private static final String CORE_MODULE = "core";

  private static final Set AUTO_IMPORTED_MODULES = new HashSet<>(
      Arrays.asList(CORE_MODULE, ELEMENTS_MODULE, FILTERS_MODULE));

  private static enum ResolutionState {
    NO_RESOLVED, IN_PROCESS, RESOLVED
  }

  public static final PrimitiveType STRING = new PrimitiveType("String");
  public static final PrimitiveType BOOLEAN = new PrimitiveType("boolean");
  public static final PrimitiveType INT = new PrimitiveType("int");
  public static final PrimitiveType FLOAT = new PrimitiveType("float");
  public static final PrimitiveType DOUBLE = new PrimitiveType("double");
  public static final PrimitiveType INT64 = new PrimitiveType("int64");

  private static Logger log = LoggerFactory.getLogger(ModuleDefinition.class);

  /* Kmd file info */
  private String name;
  private String version;

  private String kurentoVersion;
  private String kurentoMavenVersion;
  private String kurentoNpmVersion;

  private List imports;
  private String repository;

  private Code code;

  private List remoteClasses;
  private List complexTypes;
  private List events;

  /* Derived properties */
  private transient Map remoteClassesMap;
  private transient Map eventsMap;
  private transient Map complexTypesMap;

  private transient Map types;

  private transient ResolutionState resolutionState = ResolutionState.NO_RESOLVED;
  private transient Map allTypes;

  public ModuleDefinition(String name, String version) {
    this();
    this.name = name;
    this.version = version;
  }

  public ModuleDefinition() {
    this.remoteClasses = new ArrayList<>();
    this.complexTypes = new ArrayList<>();
    this.events = new ArrayList<>();
    this.imports = new ArrayList<>();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    ModuleDefinition other = (ModuleDefinition) obj;
    if (events == null) {
      if (other.events != null) {
        return false;
      }
    } else if (!events.equals(other.events)) {
      return false;
    }
    if (remoteClasses == null) {
      if (other.remoteClasses != null) {
        return false;
      }
    } else if (!remoteClasses.equals(other.remoteClasses)) {
      return false;
    }
    if (complexTypes == null) {
      if (other.complexTypes != null) {
        return false;
      }
    } else if (!complexTypes.equals(other.complexTypes)) {
      return false;
    }
    return true;
  }

  public List getEvents() {
    return events;
  }

  public List getRemoteClasses() {
    return remoteClasses;
  }

  public List getComplexTypes() {
    return complexTypes;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((events == null) ? 0 : events.hashCode());
    result = prime * result + ((remoteClasses == null) ? 0 : remoteClasses.hashCode());
    result = prime * result + ((complexTypes == null) ? 0 : complexTypes.hashCode());
    return result;
  }

  public void addEvent(Event event) {
    this.events.add(event);
  }

  public void addRemoteClass(RemoteClass remoteClass) {
    this.remoteClasses.add(remoteClass);
  }

  public void addType(ComplexType type) {
    this.complexTypes.add(type);
  }

  public void setEvents(List events) {
    this.events = events;
  }

  public void setRemoteClasses(List remoteClasses) {
    this.remoteClasses = remoteClasses;
  }

  public void setComplexTypes(List types) {
    this.complexTypes = types;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getKurentoVersion() {
    return kurentoVersion;
  }

  public String getVersion() {
    return version;
  }

  public void setVersion(String version) {
    this.version = version;
  }

  public RemoteClass getRemoteClass(String remoteClassName) {
    return remoteClassesMap.get(remoteClassName);
  }

  public ComplexType getType(String typeName) {
    return complexTypesMap.get(typeName);
  }

  public Event getEvent(String eventName) {
    return eventsMap.get(eventName);
  }

  public String getRepository() {
    return repository;
  }

  public Code getCode() {
    return code;
  }

  public List getImports() {
    return imports;
  }

  public Collection getAllImports() {

    Map allImports = new HashMap();
    getAllImports(allImports);
    return allImports.values();
  }

  private void getAllImports(Map allImports) {
    for (Import importInfo : imports) {
      if (allImports.get(importInfo.getName()) == null) {
        allImports.put(importInfo.getName(), importInfo);
        importInfo.getModule().getAllImports(allImports);
      }
    }
  }

  @Override
  public String toString() {
    return "Model [name=" + name + ", version=" + version + ", remoteClasses=" + remoteClasses
        + ", types=" + complexTypes + ", events=" + events + "]";
  }

  public void validateModule() {

    if (name == null) {
      throw new KurentoModuleCreatorException("Name is mandatory at least in one of the files");
    }

    if (kurentoVersion == null) {
      if (AUTO_IMPORTED_MODULES.contains(name)) {
        kurentoVersion = version;
      } else {
        throw new KurentoModuleCreatorException(
            "Kurento version is mandatory at least in one of the files describing: " + name);
      }
    }

    if (version == null) {
      throw new KurentoModuleCreatorException("Version is mandatory at least in one of the files");
    }

    if (VersionManager.isReleaseVersion(version)) {
      for (Import importInfo : this.imports) {
        if (!VersionManager.isReleaseVersion(importInfo.getVersion())) {
          throw new KurentoModuleCreatorException(
              "All dependencies of a release version must be also release versions. Import '"
                  + importInfo.getName() + "' is in non release version "
                  + importInfo.getVersion());
        }
      }
    }
  }

  public void resolveModel() {
    resolveModule(null);
  }

  public void resolveModule(ModuleManager moduleManager) {

    setModuleToTypes();

    if (resolutionState == ResolutionState.IN_PROCESS) {
      throw new KurentoModuleCreatorException(
          "Found a dependency cycle in plugin '" + this.name + "'");
    }

    if (resolutionState == ResolutionState.RESOLVED) {
      log.debug("Module '" + name + "' yet resolved");
      return;
    }

    log.debug("Resolving module '" + name + "'");

    this.resolutionState = ResolutionState.IN_PROCESS;

    if (kurentoVersion == null && version != null) {
      kurentoVersion = version;
    }

    resolveImports(moduleManager);
    resolveTypes(moduleManager);
    addInfoForGeneration(moduleManager);

    log.debug("Module '" + name + "' resolved");

    this.resolutionState = ResolutionState.RESOLVED;
  }

  private void setModuleToTypes() {
    for (ComplexType complexType : complexTypes) {
      complexType.setModule(this);
    }

    for (RemoteClass remoteClass : remoteClasses) {
      remoteClass.setModule(this);
    }

    for (Event event : events) {
      event.setModule(this);
    }
  }

  private void addInfoForGeneration(ModuleManager moduleManager) {
    if (this.code == null) {
      this.code = new Code();
    }
    this.code.completeInfo(this, moduleManager);
  }

  private void resolveTypes(ModuleManager moduleManager) {

    remoteClassesMap = resolveNamedElements(this.remoteClasses);
    eventsMap = resolveNamedElements(this.events);
    complexTypesMap = resolveNamedElements(this.complexTypes);

    types = new HashMap();
    types.putAll(remoteClassesMap);
    types.putAll(eventsMap);
    types.putAll(complexTypesMap);

    put(types, BOOLEAN);
    put(types, STRING);
    put(types, INT);
    put(types, FLOAT);
    put(types, DOUBLE);
    put(types, INT64);

    allTypes = new HashMap(types);

    for (Import importEntry : this.imports) {
      allTypes.putAll(importEntry.getModule().getAllTypes());
    }

    resolveTypeRefs(remoteClasses, allTypes);
    resolveTypeRefs(events, allTypes);
    resolveTypeRefs(complexTypes, allTypes);
  }

  private void resolveImports(ModuleManager moduleManager) {

    autoImportModules(moduleManager);

    for (Import importEntry : this.imports) {

      ModuleDefinition dependencyModule = null;

      if (moduleManager != null) {
        dependencyModule = moduleManager.getModule(importEntry.getName());
      }

      if (dependencyModule == null) {
        throw new KurentoModuleCreatorException(
            "Import '" + importEntry.getName() + "' not found in dependencies in any version");
      } else {

        if (!VersionManager.compatibleVersion(importEntry.getVersion(),
            dependencyModule.getVersion())) {

          if (VersionManager.devCompatibleVersion(importEntry.getVersion(),
              dependencyModule.getVersion())) {

            log.info("[WARNING] Dependency on module '" + importEntry.getName() + "' version '"
                + importEntry.getVersion() + "' is satisfied with version '"
                + dependencyModule.getVersion() + "'");
          } else {

            throw new KurentoModuleCreatorException("Import '" + importEntry.getName()
                + "' with version " + importEntry.getVersion()
                + " not found in dependencies, found version: " + dependencyModule.getVersion());
          }
        }
      }

      dependencyModule.resolveModule(moduleManager);
      importEntry.setModule(dependencyModule);

      if (importEntry.getMavenVersion() == null) {
        importEntry.setMavenVersion(VersionManager.convertToMavenImport(importEntry.getVersion()));
      }

      if (importEntry.getNpmVersion() == null) {
        importEntry.setNpmVersion(VersionManager.convertToNpmImport(
            dependencyModule.getCode().getApi().get("js").get("npmGit"), importEntry.getVersion()));
      }
    }
  }

  private void autoImportModules(ModuleManager moduleManager) {

    if (!CORE_MODULE.equals(this.name)) {
      this.imports
          .add(new Import(CORE_MODULE, kurentoVersion, kurentoMavenVersion, kurentoNpmVersion));

      if (!ELEMENTS_MODULE.equals(this.name)) {
        this.imports.add(
            new Import(ELEMENTS_MODULE, kurentoVersion, kurentoMavenVersion, kurentoNpmVersion));

        if (!FILTERS_MODULE.equals(this.name)) {
          this.imports.add(
              new Import(FILTERS_MODULE, kurentoVersion, kurentoMavenVersion, kurentoNpmVersion));
        }
      }
    }
  }

  private Map getAllTypes() {
    return allTypes;
  }

  private void put(Map types, Type type) {
    types.put(type.getName(), type);
  }

  private void resolveTypeRefs(List moduleElements,
      Map types) {

    for (ModelElement moduleElement : moduleElements) {

      if (moduleElement instanceof TypeRef) {
        resolveTypeRef((TypeRef) moduleElement, types);
      } else {
        // A moduleElement can be null if in original Json there is a
        // comma in the last element of an array
        if (moduleElement != null) {
          resolveTypeRefs(moduleElement.getChildren(), types);
        }
      }
    }
  }

  private void resolveTypeRef(TypeRef typeRef, Map types) {

    Type type = types.get(typeRef.getQualifiedName());

    if (type == null) {

      if (typeRef.getModuleName() == null) {

        // Maybe this type is declared in this module
        typeRef.setModuleName(this.name);
        type = types.get(typeRef.getQualifiedName());

        if (type == null) {
          throw new KurentoModuleCreatorException("The type '" + typeRef.getName()
              + "' is not defined in module " + this.name + " neither in kurento. Used in module: "
              + name + ".\nThe available types are: " + types.keySet());
        }

      } else {

        throw new KurentoModuleCreatorException("The type '" + typeRef.getName()
            + "' is not defined in module " + typeRef.getModuleName() + ". Used in module: " + name
            + ".\nThe available types are: " + types.keySet());

      }
    }

    typeRef.setType(type);
  }

  @SuppressWarnings("unchecked")
  private  Map resolveNamedElements(List elements) {

    Map elementsMap = new HashMap();
    for (NamedElement element : elements) {

      if (AUTO_IMPORTED_MODULES.contains(this.name)) {
        // Only types of imported modules can be referenced without
        // module name
        elementsMap.put(element.getName(), (T) element);
      } else {
        elementsMap.put(this.name + "." + element.getName(), (T) element);
      }
    }
    return elementsMap;
  }

  public void expandMethodsWithOpsParams() {
    for (RemoteClass remoteClass : remoteClassesMap.values()) {
      remoteClass.expandMethodsWithOpsParams();
    }
  }

  public void fusionModules(ModuleDefinition module) {

    // TODO Generalize this

    if (this.name == null) {
      this.name = module.name;
    } else {
      if (module.name != null) {
        throw new KurentoModuleCreatorException("Name can only be set in one kmd file");
      }
    }

    if (this.kurentoVersion == null) {
      this.kurentoVersion = module.kurentoVersion;
    } else {
      if (module.kurentoVersion != null) {
        throw new KurentoModuleCreatorException("Kurento version can only be set in one kmd file");
      }
    }

    if (this.version == null) {
      this.version = module.version;
    } else {
      if (module.version != null) {
        throw new KurentoModuleCreatorException("Version can only be set in one kmd file");
      }
    }

    if (this.imports.isEmpty()) {
      this.imports = module.imports;
    } else {
      if (!module.imports.isEmpty()) {
        throw new KurentoModuleCreatorException("Imports section can only be set in one kmd file");
      }
    }

    if (this.code == null) {
      this.code = module.code;
    } else {
      if (module.code != null) {
        throw new KurentoModuleCreatorException("Code section can only be set in one kmd file");
      }
    }

    this.complexTypes.addAll(module.complexTypes);
    this.remoteClasses.addAll(module.remoteClasses);
    this.events.addAll(module.events);
  }

  public boolean hasKmdSection() {
    if (code == null) {
      return false;
    }

    return code.getKmd() != null;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy