/**
   * Create a {@link ServiceElement}.
   *
   * @param deployment The {@link ServiceDeployment}, must not be {@code null}.
   * @return A {@code ServiceElement}
   * @throws ConfigurationException if there are problem reading the configuration
   */
  public static ServiceElement create(final ServiceDeployment deployment)
      throws IOException, ConfigurationException, ResolverException, URISyntaxException {
    String configurationFilePath;
    if (Artifact.isArtifact(deployment.getConfig())) {
      logger.info("Resolve " + deployment.getConfig());
      Resolver resolver = ResolverHelper.getResolver();
      Artifact artifact = new Artifact(deployment.getConfig());
      URL configLocation = resolver.getLocation(artifact.getGAV(), artifact.getType());
      configurationFilePath = new File(configLocation.toURI()).getPath();
    } else {
      configurationFilePath = deployment.getConfig();
    }
    logger.info("Loading " + configurationFilePath);
    Configuration configuration = Configuration.getInstance(configurationFilePath);
    String component = "sorcer.core.provider.ServiceProvider";

    String name = deployment.getName();
    if (name == null) {
      name = configuration.getEntry(component, "name", String.class, null);
    }
    String[] interfaces =
        configuration.getEntry(
            "sorcer.core.exertion.deployment", "interfaces", String[].class, new String[0]);
    if (interfaces.length == 0 && deployment.getServiceType() != null) {
      interfaces = new String[] {deployment.getServiceType()};
    }

    String[] codebaseJars = deployment.getCodebaseJars();
    if (codebaseJars == null) {
      codebaseJars =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "codebaseJars", String[].class, new String[0]);
    }
    String[] implJars = deployment.getClasspathJars();
    if (implJars == null) {
      implJars =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "implJars", String[].class, new String[0]);
    }
    String jvmArgs = deployment.getJvmArgs();
    if (jvmArgs == null) {
      jvmArgs =
          configuration.getEntry("sorcer.core.exertion.deployment", "jvmArgs", String.class, null);
    }
    Boolean fork = deployment.getFork();
    if (fork == null) {
      fork =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "fork", Boolean.class, Boolean.FALSE);
    }
    String architecture = deployment.getArchitecture();
    if (architecture == null) {
      architecture =
          configuration.getEntry("sorcer.core.exertion.deployment", "arch", String.class, null);
    }
    String[] operatingSystems = deployment.getOperatingSystems();
    if (operatingSystems.length == 0) {
      operatingSystems =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "opSys", String[].class, new String[0]);
    }
    String[] ips = deployment.getIps();
    if (ips.length == 0) {
      ips =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "ips", String[].class, new String[0]);
    }
    String[] excludeIPs = deployment.getExcludeIps();
    if (excludeIPs.length == 0) {
      excludeIPs =
          configuration.getEntry(
              "sorcer.core.exertion.deployment", "ips_exclude", String[].class, new String[0]);
    }
    String providerClass =
        configuration.getEntry(
            "sorcer.core.exertion.deployment", "providerClass", String.class, null);
    int maxPerNode = deployment.getMaxPerCybernode();
    if (maxPerNode == 0) {
      maxPerNode =
          configuration.getEntry("sorcer.core.exertion.deployment", "perNode", int.class, 1);
    }
    String webster =
        configuration.getEntry("sorcer.core.exertion.deployment", "webster", String.class, null);

    ServiceDetails serviceDetails =
        new ServiceDetails(
            name,
            interfaces,
            codebaseJars,
            implJars,
            providerClass,
            jvmArgs,
            fork,
            maxPerNode,
            architecture,
            operatingSystems,
            ips,
            excludeIPs,
            webster);
    ServiceElement service = create(serviceDetails, deployment);
    if (logger.isDebugEnabled())
      logger.debug(
          String.format(
              "Created ServiceElement\n=================\n%s\n=================\nFrom [%s]",
              service, deployment));
    return service;
  }
  static ServiceElement create(
      final ServiceDetails serviceDetails, final ServiceDeployment deployment) throws IOException {
    ServiceElement service = new ServiceElement();

    String websterUrl;
    if (serviceDetails.webster == null) {
      if (deployment.getWebsterUrl() == null) {
        websterUrl = Sorcer.getWebsterUrl();
        if (logger.isDebugEnabled())
          logger.debug("Set code base derived from Sorcer.getWebsterUrl: " + websterUrl);
      } else {
        websterUrl = deployment.getWebsterUrl();
        if (logger.isDebugEnabled())
          logger.debug("Set code base derived from Deployment: " + websterUrl);
      }
    } else {
      websterUrl = serviceDetails.webster;
    }
    /* Create client (export) ClassBundle */
    List<ClassBundle> exports = new ArrayList<ClassBundle>();
    for (String s : serviceDetails.interfaces) {
      ClassBundle export = new ClassBundle(s);
      if (serviceDetails.codebaseJars.length == 1
          && Artifact.isArtifact(serviceDetails.codebaseJars[0])) {
        export.setArtifact(serviceDetails.codebaseJars[0]);
      } else {
        export.setJARs(appendJars(commonDLJars, serviceDetails.codebaseJars));
        export.setCodebase(websterUrl);
      }
      exports.add(export);
    }

    /* Create service implementation ClassBundle */
    ClassBundle main =
        new ClassBundle(
            serviceDetails.providerClass == null
                ? deployment.getImpl()
                : serviceDetails.providerClass);
    if (serviceDetails.implJars.length == 1 && Artifact.isArtifact(serviceDetails.implJars[0])) {
      main.setArtifact(serviceDetails.implJars[0]);
    } else {
      main.setJARs(serviceDetails.implJars);
      main.setCodebase(websterUrl);
    }

    /* Set ClassBundles to ServiceElement */
    service.setComponentBundle(main);
    service.setExportBundles(exports.toArray(new ClassBundle[exports.size()]));

    String serviceName;
    if (serviceDetails.name == null) {
      /* Get the (simple) name from the fully qualified interface */
      if (deployment.getName() == null) {
        StringBuilder nameBuilder = new StringBuilder();
        for (String s : serviceDetails.interfaces) {
          String value;
          int ndx = s.lastIndexOf(".");
          if (ndx > 0) {
            value = s.substring(ndx + 1);
          } else {
            value = s;
          }
          if (nameBuilder.length() > 0) {
            nameBuilder.append(" | ");
          }
          nameBuilder.append(value);
        }
        serviceName = nameBuilder.toString();
      } else {
        serviceName = deployment.getName();
      }
    } else {
      serviceName = serviceDetails.name;
    }

    if (serviceDetails.maxPerNode > 0) {
      service.setMaxPerMachine(serviceDetails.maxPerNode);
    }
    if (serviceDetails.architecture != null || serviceDetails.operatingSystems.length > 0) {
      ServiceLevelAgreements slas = new ServiceLevelAgreements();
      SystemRequirements systemRequirements = new SystemRequirements();
      if (serviceDetails.architecture != null) {
        Map<String, Object> attributeMap = new HashMap<String, Object>();
        attributeMap.put(ProcessorArchitecture.ARCHITECTURE, serviceDetails.architecture);
        SystemComponent systemComponent =
            new SystemComponent("Processor", ProcessorArchitecture.class.getName(), attributeMap);
        systemRequirements.addSystemComponent(systemComponent);
      }
      for (String s : serviceDetails.operatingSystems) {
        String opSys = checkAndMaybeFixOpSys(s);
        Map<String, Object> attributeMap = new HashMap<String, Object>();
        attributeMap.put(OperatingSystem.NAME, opSys);
        SystemComponent operatingSystem =
            new SystemComponent("OperatingSystem", OperatingSystem.class.getName(), attributeMap);
        systemRequirements.addSystemComponent(operatingSystem);
      }
      slas.setServiceRequirements(systemRequirements);
      service.setServiceLevelAgreements(slas);
    }
    if (serviceDetails.ips.length > 0) {
      SystemRequirements systemRequirements =
          service.getServiceLevelAgreements().getSystemRequirements();
      systemRequirements.addSystemComponent(getSystemComponentAddresses(false, serviceDetails.ips));
    }

    if (serviceDetails.excludeIps.length > 0) {
      SystemRequirements systemRequirements =
          service.getServiceLevelAgreements().getSystemRequirements();
      systemRequirements.addSystemComponent(
          getSystemComponentAddresses(true, serviceDetails.excludeIps));
    }

    /* Create simple ServiceBeanConfig */
    Map<String, Object> configMap = new HashMap<String, Object>();
    configMap.put(ServiceBeanConfig.NAME, serviceName);
    configMap.put(ServiceBeanConfig.GROUPS, Sorcer.getLookupGroups());
    ServiceBeanConfig sbc = new ServiceBeanConfig(configMap, new String[] {deployment.getConfig()});
    sbc.addAdditionalEntries(
        new DeployInfo(
            deployment.getType().name(), deployment.getUnique().name(), deployment.getIdle()));
    service.setServiceBeanConfig(sbc);
    service.setPlanned(deployment.getMultiplicity());

    /* If the service is to be forked, create an ExecDescriptor */
    if (serviceDetails.fork) {
      service.setFork(true);
      if (serviceDetails.jvmArgs != null) {
        ExecDescriptor execDescriptor = new ExecDescriptor();
        execDescriptor.setInputArgs(serviceDetails.jvmArgs);
        service.setExecDescriptor(execDescriptor);
      }
    }
    if (logger.isDebugEnabled()) logger.debug("Generated Service Element :" + service);
    return service;
  }