/**
   * Discriminate special NF interfaces
   *
   * <ul>
   *   <li>COLLECTION: ignored, they are dynamically generated
   *   <li>CONTENT: if primitive, ignore it
   *   <li>BINDING: if primitive and DOESN'T HAVE F client interfaces, ignore it
   * </ul>
   *
   * @return true if 'special case', faslse otherwise
   */
  private boolean specialCasesForNfType(
      String itfName, PAGCMInterfaceType itfType, boolean isPrimitive) {

    // COLLECTION interfaces are ignored, because they are generated dynamically
    if (itfType.isFcCollectionItf()) {
      return true;
    }

    // CONTENT controller is not created for primitives
    if (Constants.CONTENT_CONTROLLER.equals(itfName)
        && !itfType.isFcClientItf()
        && !itfType.isInternal()
        && isPrimitive) {
      // logger.warn("Ignored NF Interface '"+ Constants.CONTENT_CONTROLLER +"' declared for
      // component '"+ this.componentParameters.getName() + "'");
      return true;
    }

    // BINDING controller is not created for primitives without client interfaces except if it has
    // an internal server interface
    if (Constants.BINDING_CONTROLLER.equals(itfName)
        && !itfType.isFcClientItf()
        && !itfType.isInternal()
        && isPrimitive) {
      if ((Utils.getClientItfTypes(this.componentParameters.getComponentType()).length == 0)
          && !hasNfInternalServerInterfaces()) {
        // logger.warn("Ignored NF Interface '"+ Constants.BINDING_CONTROLLER +"' declared for
        // component '"+ this.componentParameters.getName() + "'");
        return true;
      }
    }

    return false;
  }
 public static Component[] getSubComponent(Component component, String subComponentName)
     throws NoSuchInterfaceException {
   List<Component> list = new ArrayList<Component>();
   for (Component subComp : Utils.getPAContentController(component).getFcSubComponents()) {
     String subCompName =
         ((PAComponent) subComp).getComponentParameters().getControllerDescription().getName();
     if (subCompName.equals(subComponentName)) {
       list.add(subComp);
     }
   }
   return list.toArray(new Component[list.size()]);
 }
  @org.junit.Before
  public void deployHelloWorldComponent() {

    try {
      url = AbstractWebServicesFactory.getLocalUrl();

      Component boot = Utils.getBootstrapComponent();

      GCMTypeFactory tf = GCM.getGCMTypeFactory(boot);
      GenericFactory cf = GCM.getGenericFactory(boot);

      ComponentType typeComp =
          tf.createFcType(
              new InterfaceType[] {
                tf.createFcItfType(
                    "hello-world", HelloWorldItf.class.getName(), false, false, false),
                tf.createFcItfType(
                    "good-bye-world", GoodByeWorldItf.class.getName(), false, false, false)
              });

      String controllersConfigFileLocation =
          AbstractPAWebServicesControllerImpl.getControllerFileUrl("cxf").getPath();
      ControllerDescription cd =
          new ControllerDescription(
              "composite", Constants.PRIMITIVE, controllersConfigFileLocation);
      comp =
          cf.newFcInstance(
              typeComp, cd, new ContentDescription(HelloWorldComponent.class.getName(), null));

      GCM.getGCMLifeCycleController(comp).startFc();

      // Deploying the service in the Active Object way
      WebServicesFactory wsf = AbstractWebServicesFactory.getWebServicesFactory("cxf");
      ws = wsf.getWebServices(url);
      ws.exposeComponentAsWebService(comp, "server", new String[] {"hello-world"});
      ws.exposeComponentAsWebService(comp, "server2");

      // Deploying the service using the web service controller
      wsc =
          org.objectweb.proactive.extensions.webservices.component.Utils.getPAWebServicesController(
              comp);
      wsc.initServlet();
      wsc.setUrl(url);
      wsc.exposeComponentAsWebService("server3", new String[] {"hello-world"});
      wsc.exposeComponentAsWebService("server4");

    } catch (Exception e) {
      e.printStackTrace();
      assertTrue(false);
    }
  }
  /**
   * Returns the component bound to this "itfName" interface. If this is a multicast interface, it
   * will try to return one of the, possible many, bound components. If something goes wrong, a null
   * value will be returned.
   *
   * @param component The client component
   * @param itfName The name the interface
   * @return A bound component, or null if no server component is bound to this interface
   * @throws NoSuchInterfaceException
   */
  public static Component getBindComponent(Component component, String itfName)
      throws NoSuchInterfaceException {

    PAInterface itf = (PAInterface) Utils.getPABindingController(component).lookupFc(itfName);
    if (itf != null) {
      if (((PAGCMInterfaceType) itf.getFcItfType()).isGCMMulticastItf()) {
        // TODO: this is not ok, fin other way to deal with multicast interfaces.
        return getMulticastBindComponenents(component, itfName)[0];
      } else {
        return itf.getFcItfOwner();
      }
    }

    return null;
  }
  /**
   * Discriminate special controller interfaces
   *
   * <ul>
   *   <li>COLLECTION: ignored??? (TODO:check if this is needed)
   *   <li>CONTENT: if primitive, ignore it
   *   <li>BINDING: if primitive and DOESN'T HAVE F client interfaces, ignore it
   *   <li>Avoid duplicates
   * </ul>
   *
   * @param controllerName
   * @param itfType
   * @param isPrimitive
   * @return
   */
  private boolean specialCasesForController(
      String controllerName,
      PAGCMInterfaceType itfType,
      boolean isPrimitive,
      String controllersConfigFileLocation) {

    // COLLECTION interfaces are ignored, because they are generated dynamically (and an object
    // controller shouldn't be a collection, right?)
    // if(itfType.isFcCollectionItf()) {
    //	return true;
    // }

    // CONTENT controller is not created for primitives
    if (Constants.CONTENT_CONTROLLER.equals(controllerName)
        && !itfType.isFcClientItf()
        && !itfType.isInternal()
        && isPrimitive) {
      // logger.warn("Ignored controller '"+ Constants.CONTENT_CONTROLLER +"' declared for component
      // '"+ this.componentParameters.getName() + "' in file: "+ controllersConfigFileLocation);
      return true;
    }

    // BINDING controller is not created for primitives without client interfaces except if it has
    // an internal server interface
    if (Constants.BINDING_CONTROLLER.equals(controllerName)
        && !itfType.isFcClientItf()
        && !itfType.isInternal()
        && isPrimitive) {
      if ((Utils.getClientItfTypes(this.componentParameters.getComponentType()).length == 0)
          && !hasNfInternalServerInterfaces()) {
        // logger.warn("Ignored controller '"+ Constants.BINDING_CONTROLLER +"' declared for
        // component '"+ this.componentParameters.getName() + "' in file: "+
        // controllersConfigFileLocation);
        return true;
      }
    }

    // Controller interface had already been declared (f.e., in the NF Type). Do not create this
    // controller.
    if (existsNfInterface(controllerName)) {
      // logger.warn("Controller interface '"+ controllerName +"' already created. Ignoring this
      // controller.");
      return true;
    }

    return false;
  }
  /**
   * Returns the array of components bound the "multicastItfName" multicast interface, or null if it
   * fails to getting them.
   *
   * @param component The client component
   * @param multicastItfName The name of the multicast interface
   * @return Array of bound components, or null if it fails
   */
  public static Component[] getMulticastBindComponenents(
      Component component, String multicastItfName) {
    try {
      Object[] destinationItfs =
          Utils.getPAMulticastController(component).lookupGCMMulticast(multicastItfName);
      Component[] destinationComps = new Component[destinationItfs.length];

      for (int i = 0; i < destinationItfs.length; i++) {
        destinationComps[i] = ((PAInterface) destinationItfs[i]).getFcItfOwner();
      }

      return destinationComps;

    } catch (NoSuchInterfaceException e) {
      e.printStackTrace();
      return null;
    }
  }
  private void addControllers(Map<String, String> controllersConfiguration) {
    // create the interface references tables
    // the size is the addition of :
    // - 1 for the current ItfRef (that is at the same time a binding controller, lifecycle
    // controller,
    // content controller and name controller
    // - the number of client functional interfaces
    // - the number of server functional interfaces
    // ArrayList interface_references_list = new ArrayList(1
    // +componentType.getFcInterfaceTypes().length+controllersConfiguration.size());
    this.nfItfs = new HashMap<String, Interface>(1 + controllersConfiguration.size());

    // add controllers
    // Enumeration controllersInterfaces = controllersConfiguration.propertyNames();
    Iterator<String> iteratorOnControllers = controllersConfiguration.keySet().iterator();
    Class<?> controllerClass = null;
    AbstractPAController currentController;
    PAInterface currentInterface = null;
    Class<?> controllerItf;
    Vector<InterfaceType> nfType = new Vector<InterfaceType>();
    while (iteratorOnControllers.hasNext()) {
      String controllerItfName = iteratorOnControllers.next();
      try {
        controllerItf = Class.forName(controllerItfName);
        controllerClass = Class.forName(controllersConfiguration.get(controllerItf.getName()));
        Constructor<?> controllerClassConstructor =
            controllerClass.getConstructor(new Class<?>[] {Component.class});
        currentController =
            (AbstractPAController) controllerClassConstructor.newInstance(new Object[] {this});
        currentInterface =
            RepresentativeInterfaceClassGenerator.instance()
                .generateControllerInterface(
                    currentController.getFcItfName(),
                    this,
                    (PAGCMInterfaceType) currentController.getFcItfType());
        ((StubObject) currentInterface).setProxy(this.proxy);

      } catch (Exception e) {
        logger.error(
            "could not create controller "
                + controllersConfiguration.get(controllerItfName)
                + " : "
                + e.getMessage());
        continue;
      }

      if (BindingController.class.isAssignableFrom(controllerClass)) {
        if ((this.componentParameters.getHierarchicalType().equals(Constants.PRIMITIVE)
            && (Utils.getClientItfTypes(this.componentParameters.getComponentType()).length == 0)
            && !hasNfInternalServerInterfaces())) {
          if (logger.isDebugEnabled()) {
            logger.debug(
                "user component class of this component does not have any client interface. It will have no BindingController");
          }
          continue;
        }
      }
      if (ContentController.class.isAssignableFrom(controllerClass)) {
        if (Constants.PRIMITIVE.equals(this.componentParameters.getHierarchicalType())) {
          // no content controller here
          continue;
        }
      }
      if (currentInterface != null) {
        this.nfItfs.put(currentController.getFcItfName(), currentInterface);
        nfType.add((InterfaceType) currentInterface.getFcItfType());
      }
    }

    try { // Setting the real NF type, as some controllers may not be generated
      Component boot = Utils.getBootstrapComponent();
      PAGCMTypeFactory type_factory = Utils.getPAGCMTypeFactory(boot);
      InterfaceType[] fItfTypes =
          ((PAComponentType) this.componentParameters.getComponentType()).getFcInterfaceTypes();
      InterfaceType[] nfItfTypes = nfType.toArray(new InterfaceType[] {});
      this.componentParameters.setComponentType(type_factory.createFcType(fItfTypes, nfItfTypes));
    } catch (Exception e) {
      e.printStackTrace();
      logger.warn("NF type could not be set");
    }
  }
  /**
   * Create and add the NF Interfaces using both a component configuration file, and an NF Type.
   *
   * <ol>
   *   <li>Creates NF Interfaces from the declared NF Type. If there is non NF Type, this step is
   *       ignored.
   *   <li>Creates Object Controllers from the Controllers Configuration File. If some of them
   *       duplicates interfaces declared in the NF Type, they are ignored. In other words, the
   *       declared NF Type has priority over the Controllers Configuration File.
   *   <li>Checks that the mandatory interfaces are declared. In particular, if the membrane
   *       controller has been previously declared, it is created here.
   *   <li>Updates the NF Type of the Component.
   * </ol>
   *
   * NOTE: When an NF interface is described in the ADL file, the Factory adds the
   * 'membrane-controller' default implementation automatically, so that it is not necessary to
   * specify the 'membrane-controller' explicitly.
   */
  private void addControllerInterfaces() {

    // Vector to collect the real NF type
    Vector<InterfaceType> nfType = new Vector<InterfaceType>();

    boolean isPrimitive =
        Constants.PRIMITIVE.equals(this.componentParameters.getHierarchicalType());

    // ------------------------------------------------------------
    // 1. Create interfaces from the declared NF type
    // Read the NF Type
    PAComponentType componentType = (PAComponentType) this.componentParameters.getComponentType();
    InterfaceType[] nfItfTypes = componentType.getNfFcInterfaceTypes();
    PAGCMInterfaceType[] pagcmNfItfTypes = new PAGCMInterfaceType[nfItfTypes.length];
    System.arraycopy(nfItfTypes, 0, pagcmNfItfTypes, 0, nfItfTypes.length);
    // Class<?> controllerItf = null;

    for (PAGCMInterfaceType pagcmNfItfType : pagcmNfItfTypes) {

      String itfName = pagcmNfItfType.getFcItfName();
      PAInterface itfRef = null;

      try {
        // some controllers interfaces are ignored
        if (specialCasesForNfType(itfName, pagcmNfItfType, isPrimitive)) continue;

        // TODO: check the case MULTICAST && CLIENT, treated in
        // PAComponentImpl.addControllerInterfaces, but not here

        // Generate the representative interface
        itfRef =
            RepresentativeInterfaceClassGenerator.instance()
                .generateInterface(
                    pagcmNfItfType.getFcItfName(),
                    this,
                    pagcmNfItfType,
                    pagcmNfItfType.isInternal(),
                    false);

        // update the hashmap and the vector of NF types
        this.nfItfs.put(itfName, itfRef);
        nfType.add((InterfaceType) itfRef.getFcItfType());

      } catch (Exception e) {
        throw new ProActiveRuntimeException(
            "Could not create NF interface reference'"
                + itfName
                + "' while instantiating component'"
                + this.componentParameters.getName()
                + "'. "
                + e.getMessage(),
            e);
      }
    }

    // ------------------------------------------------------------
    // 2. Create interfaces from the Controller Configuration file

    // read the Controller Configuration File
    Map<String, String> controllerEntries = null;
    if (this.componentParameters.getControllerDescription().configFileIsSpecified()) {
      // Parse controller config file
      String controllersConfigFileLocation =
          this.componentParameters.getControllerDescription().getControllersConfigFileLocation();
      loggerADL.debug("Parsing Controller Configuration File: " + controllersConfigFileLocation);
      ComponentConfigurationHandler componentConfiguration =
          PAComponentImpl.loadControllerConfiguration(controllersConfigFileLocation);
      controllerEntries = componentConfiguration.getControllers();

      // Create controller objects from the Controller Configuration File
      for (Map.Entry<String, String> controllerEntry : controllerEntries.entrySet()) {

        String controllerName = null;
        String controllerItfName = controllerEntry.getKey();
        String controllerClassName = controllerEntry.getValue();
        Class<?> controllerItf = null;
        Class<?> controllerClass = null;
        AbstractPAController controller = null;
        PAInterface itfRef = null;
        PAGCMInterfaceType controllerItfType = null;

        try {
          // fetch the classes
          controllerItf = Class.forName(controllerItfName);
          controllerClass = Class.forName(controllerClassName);
          // Instantiates the controller object, using 'this' component as owner.
          Constructor<?> controllerClassConstructor =
              controllerClass.getConstructor(new Class[] {Component.class});
          controller =
              (AbstractPAController) controllerClassConstructor.newInstance(new Object[] {this});

          // Obtains the controller interfaceType as declared by the object (in the method
          // setControllerItfType)
          controllerItfType = (PAGCMInterfaceType) controller.getFcItfType();
          // now we can know the name of the controller, and discriminate special cases
          controllerName = controllerItfType.getFcItfName();

          // Some controllers are not created
          if (specialCasesForController(
              controllerName, controllerItfType, isPrimitive, controllersConfigFileLocation)) {
            continue;
          }

          if (!controllerItf.isAssignableFrom(controllerClass)) {
            logger.error(
                "Could not create controller. Class '"
                    + controllerClassName
                    + " does not implement interface '"
                    + controllerItfName
                    + ". Check controller configuration file.");
            continue;
          }

          // Generate the representative interface
          itfRef =
              RepresentativeInterfaceClassGenerator.instance()
                  .generateControllerInterface(controllerName, this, controllerItfType);
          ((StubObject) itfRef).setProxy(this.proxy);

        } catch (Exception e) {
          throw new ProActiveRuntimeException(
              "Could not create representative interface for controller '"
                  + controllerClassName
                  + "' while instantiating component'"
                  + this.componentParameters.getName()
                  + "'. Check your configuration file "
                  + this.componentParameters
                      .getControllerDescription()
                      .getControllersConfigFileLocation()
                  + " : "
                  + e.getMessage(),
              e);
        }

        // add the controller to the controllers interfaces map, and add the controller type to the
        // NF type
        nfItfs.put(controllerName, itfRef);
        nfType.add((InterfaceType) itfRef.getFcItfType());
      }
    }

    // ------------------------------------------------------------
    // 3. Check that the mandatory controllers have been created
    checkMandatoryControllers(nfType);

    // ------------------------------------------------------------
    // 4. Set the real NF type, after having created all the NF interfaces
    try {
      Component boot = Utils.getBootstrapComponent();
      PAGCMTypeFactory tf = Utils.getPAGCMTypeFactory(boot);
      InterfaceType[] f = this.componentParameters.getComponentType().getFcInterfaceTypes();
      InterfaceType[] nf = nfType.toArray(new InterfaceType[] {});
      // Re-Set the real ComponentType
      this.componentParameters.setComponentType(tf.createFcType(f, nf));
    } catch (Exception e) {
      logger.error("NF type could not be set");
      e.printStackTrace();
    }
  }
  private void registerMethods() {
    PAActiveObject.setImmediateService(
        "getGCMStatistics",
        new Class[] {String.class, String.class, (new Class<?>[] {}).getClass()});
    PAActiveObject.setImmediateService("getAllGCMStatistics");

    statistics = Collections.synchronizedMap(new HashMap<String, Object>());
    keysList = new HashMap<String, String>();
    NameController nc = null;
    try {
      nc = GCM.getNameController(owner);
    } catch (NoSuchInterfaceException e) {
      e.printStackTrace();
    }
    String name = nc.getFcName();
    Object[] itfs = owner.getFcInterfaces();
    for (int i = 0; i < itfs.length; i++) {
      Interface itf = (Interface) itfs[i];
      InterfaceType itfType = (InterfaceType) itf.getFcItfType();
      try {
        if (!Utils.isControllerItfName(itf.getFcItfName()) && (!itfType.isFcClientItf())) {
          List<MonitorController> subcomponentMonitors = new ArrayList<MonitorController>();
          if (isComposite()) {
            Iterator<Component> bindedComponentsIterator = null;
            if (!((GCMInterfaceType) itfType).isGCMMulticastItf()) {
              List<Component> bindedComponent = new ArrayList<Component>();
              bindedComponent.add(
                  ((PAInterface) ((PAInterface) itf).getFcItfImpl()).getFcItfOwner());
              bindedComponentsIterator = bindedComponent.iterator();
            } else {
              try {
                PAMulticastControllerImpl multicastController =
                    (PAMulticastControllerImpl)
                        ((PAInterface) GCM.getMulticastController(owner)).getFcItfImpl();
                Iterator<PAInterface> delegatee =
                    multicastController.getDelegatee(itf.getFcItfName()).iterator();
                List<Component> bindedComponents = new ArrayList<Component>();
                while (delegatee.hasNext()) {
                  bindedComponents.add(delegatee.next().getFcItfOwner());
                }
                bindedComponentsIterator = bindedComponents.iterator();
              } catch (NoSuchInterfaceException e) {
                e.printStackTrace();
              }
            }
            try {
              while (bindedComponentsIterator.hasNext()) {
                MonitorController monitor =
                    GCM.getMonitorController(bindedComponentsIterator.next());
                monitor.startGCMMonitoring();
                subcomponentMonitors.add(monitor);
              }
            } catch (NoSuchInterfaceException e) {
              e.printStackTrace();
            }
          }
          Class<?> klass =
              ClassLoader.getSystemClassLoader().loadClass(itfType.getFcItfSignature());
          Method[] methods = klass.getDeclaredMethods();
          for (Method m : methods) {
            Class<?>[] parametersTypes = m.getParameterTypes();
            String key =
                PAMonitorControllerHelper.generateKey(
                    itf.getFcItfName(), m.getName(), parametersTypes);
            keysList.put(m.getName(), key);
            if (subcomponentMonitors.isEmpty()) {
              statistics.put(
                  key,
                  new MethodStatisticsPrimitiveImpl(
                      itf.getFcItfName(), m.getName(), parametersTypes));
            } else {
              statistics.put(
                  key,
                  new MethodStatisticsCompositeImpl(
                      itf.getFcItfName(), m.getName(), parametersTypes, subcomponentMonitors));
            }
            controllerLogger.debug(
                m.getName() + " (server) added to monitoring on component " + name + "!!!");
          }
        }
      } catch (ClassNotFoundException e) {
        throw new ProActiveRuntimeException("The interface " + itfType + "cannot be found", e);
      }
    }
  }
  /**
   * Runs the activity as defined in @see ComponentRunActive. The default behaviour is to serve
   * non-functional requests in FIFO order, until the component is started. Then the functional
   * activity (as defined in @see InitActive, @see RunActive and @see EndActive) begins.
   *
   * <p>When redefining the @see RunActive#runActivity(Body) method, the @see Body#isActive()
   * returns true as long as the lifecycle of the component is @see LifeCycleController#STARTED.
   * When the lifecycle of the component is @see LifeCycleController#STOPPED, @see Body#isActive()
   * returns false.
   */
  @Override
  public void runActivity(Body body) {
    if ((componentRunActive != null) && (componentRunActive != this)) {
      componentRunActive.runActivity(body);
    } else {
      // this is the default activity of the active object
      // the activity of the component has been initialized and started, now
      // what we have to do is to manage the life cycle, i.e. start and stop the
      // activity
      // that can be redefined on the reified object.
      try {
        Service componentService = new Service(body);
        NFRequestFilterImpl nfRequestFilter = new NFRequestFilterImpl();
        MembraneControllerRequestFilter memRequestFilter = new MembraneControllerRequestFilter();
        while (body.isActive()) {
          ComponentBody componentBody = (ComponentBody) body;

          /*
           * While the membrane is stopped, serve calls only on the Membrane Controller
           */
          while (Utils.getPAMembraneController(componentBody.getPAComponentImpl())
              .getMembraneState()
              .equals(PAMembraneController.MEMBRANE_STOPPED)) {
            componentService.blockingServeOldest(memRequestFilter);
          }

          while (LifeCycleController.STOPPED.equals(
              GCM.getGCMLifeCycleController(componentBody.getPAComponentImpl()).getFcState())) {
            PriorityController pc = GCM.getPriorityController(componentBody.getPAComponentImpl());
            NF3RequestFilter nf3RequestFilter = new NF3RequestFilter(pc);
            if (componentService.getOldest(nf3RequestFilter) != null) {
              // NF3 bypass all other request
              // System.err.println(
              //   "STOPPED ComponentActivity : NF3");
              componentService.blockingServeOldest(nf3RequestFilter);
            } else {
              componentService.blockingServeOldest(nfRequestFilter);
            }

            if (!body.isActive()) {
              // in case of a migration
              break;
            }
          }
          if (!body.isActive()) {
            // in case of a migration
            break;
          }

          // 3.1. init object Activity
          // life cycle started : starting activity of the object
          if (functionalInitActive != null) {
            functionalInitActive.initActivity(body);
            // functionalInitActive = null; // we won't do it again
          }

          ((ComponentBody) body).startingFunctionalActivity();
          // 3.2 while object activity
          // componentServe (includes filter on priority)
          functionalRunActive.runActivity(body);
          ((ComponentBody) body).finishedFunctionalActivity();
          if (functionalEndActive != null) {
            functionalEndActive.endActivity(body);
          }

          /*
           * While the membrane is started, serve non-functional calls with priority (the
           * same as for Lifecycle Stopped)
           */
          while (Utils.getPAMembraneController(componentBody.getPAComponentImpl())
              .getMembraneState()
              .equals(PAMembraneController.MEMBRANE_STARTED)) {
            PriorityController pc = GCM.getPriorityController(componentBody.getPAComponentImpl());
            NF3RequestFilter nf3RequestFilter = new NF3RequestFilter(pc);
            if (componentService.getOldest(nf3RequestFilter) != null) {
              // NF3 bypass all other request
              // System.err.println(
              //   "STOPPED ComponentActivity : NF3");
              componentService.blockingServeOldest(nf3RequestFilter);
            } else {
              componentService.blockingServeOldest(nfRequestFilter);
            }
            if (!body.isActive()) { // Don't know if this is OK
              // in case of a migration
              break;
            }
          }
        }
      } catch (NoSuchInterfaceException e) {
        logger.error(
            "could not retreive an interface, probably the life cycle controller of this component; terminating the component. Error message is : "
                + e.getMessage());
      }
    }
  }