I setup three rabbitmq queues with spring cloud, one of the queues randomly fails












1















What I am trying to do is, When I receive a message at consumer, I filter that message based on there content the filter will send messages to 3 different queues with the help of three different producers.




this is the configuration for three queues :




  cloud:
stream:
bindings:
QuickScore:
concurrency: 5
destination: quickScore
content-type: application/json
group: quickScoreGroup
maxConcurrency: 10
recoveryInterval: 10000
SuitabilityScore:
concurrency: 5
destination: suitabilityScore
content-type: application/json
group: suitabilityScore
maxConcurrency: 10
recoveryInterval: 10000
CompletenessScore:
concurrency: 5
destination: completenessScore
content-type: application/json
group: completenessScore
maxConcurrency: 10
recoveryInterval: 10000

rabbitmq:
host: ${rabbitmq.host:localhost}
username: guest
password: guest
port: 5672



Custom channel for queues




public interface CustomChannels {

@Output("QuickScore")
MessageChannel publishMessageToQuickScore();

@Input("QuickScore")
SubscribableChannel receivedAtQuickScore();

@Output("CompletenessScore")
MessageChannel publishMessageToCompletenessScore();

@Input("CompletenessScore")
SubscribableChannel receivedAtCompletenessScore();

@Output("SuitabilityScore")
MessageChannel publishMessageToSuitabilityScore();

@Input("SuitabilityScore")
SubscribableChannel receivedAtSuitabilityScore();
}



producers for queues :




@Autowired
private CustomChannels customChannels;

public void sendToQuickScore(UpdatedFieldsEntity updatedFieldsEntity) {
customChannels
.publishMessageToQuickScore().send(MessageBuilder.withPayload(updatedFieldsEntity).build());
log.info("sending to Quick score" + updatedFieldsEntity.toString());
}

public void sendToCompletenessScore(UpdatedFieldsEntity updatedFieldsEntity) {
customChannels
.publishMessageToCompletenessScore()
.send(MessageBuilder.withPayload(updatedFieldsEntity).build());
log.info("sending to completeness score" + updatedFieldsEntity.toString());
}

public void sendToSuitabilityScore(UpdatedFieldsEntity updatedFieldsEntity) {
customChannels
.publishMessageToSuitabilityScore()
.send(MessageBuilder.withPayload(updatedFieldsEntity).build());
log.info("sending to suitability score" + updatedFieldsEntity.toString());
}
}


And this is how I am filtering and publishing in different queues :



 @Autowired
private EventProducer producer;

public UpdatedFieldsEntity CheckUpdatedKey(UpdatedFieldsEntity updatedFieldsEntity)
throws RezoomexException {
logger.info("nn Checking UpdateKeys " + updatedFieldsEntity.toString());
if (updatedFieldsEntity == null) {
RezoomexException exception = new RezoomexException("update message is null");
throw exception;
}
for (UpdatedFields updatedFields : updatedFieldsEntity.getUpdatedFields()) {
UpdateKey element = updatedFields.getUpdateKey();
if (element.toString().equals(TECHNOLOGIES_UNDER_SKILLSET) || element.toString()
.equals(TOTAL_EXPERIENCE_VALUE)
|| element.toString().equals(TECHNOLOGIES) || element.toString()
.equals(TOTAL_EXPERIENCE_SUFFIX)) {
IsThreeScores = true;
}

}
if (IsThreeScores == true) {
logger.info("nnn publishing message to all Q");
producer.sendToQuickScore(updatedFieldsEntity);
producer.sendToSuitabilityScore(updatedFieldsEntity);
producer.sendToCompletenessScore(updatedFieldsEntity);
IsThreeScores = false;
} else {
logger.info("nnn publishing message to 2 Q");
producer.sendToSuitabilityScore(updatedFieldsEntity);
producer.sendToCompletenessScore(updatedFieldsEntity);
}
return updatedFieldsEntity;
}
}


The very first time all queues consumes the message , but at second time any of the three queues throws exception as :



    org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception

Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:154) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
... 43 common frames omitted









share|improve this question



























    1















    What I am trying to do is, When I receive a message at consumer, I filter that message based on there content the filter will send messages to 3 different queues with the help of three different producers.




    this is the configuration for three queues :




      cloud:
    stream:
    bindings:
    QuickScore:
    concurrency: 5
    destination: quickScore
    content-type: application/json
    group: quickScoreGroup
    maxConcurrency: 10
    recoveryInterval: 10000
    SuitabilityScore:
    concurrency: 5
    destination: suitabilityScore
    content-type: application/json
    group: suitabilityScore
    maxConcurrency: 10
    recoveryInterval: 10000
    CompletenessScore:
    concurrency: 5
    destination: completenessScore
    content-type: application/json
    group: completenessScore
    maxConcurrency: 10
    recoveryInterval: 10000

    rabbitmq:
    host: ${rabbitmq.host:localhost}
    username: guest
    password: guest
    port: 5672



    Custom channel for queues




    public interface CustomChannels {

    @Output("QuickScore")
    MessageChannel publishMessageToQuickScore();

    @Input("QuickScore")
    SubscribableChannel receivedAtQuickScore();

    @Output("CompletenessScore")
    MessageChannel publishMessageToCompletenessScore();

    @Input("CompletenessScore")
    SubscribableChannel receivedAtCompletenessScore();

    @Output("SuitabilityScore")
    MessageChannel publishMessageToSuitabilityScore();

    @Input("SuitabilityScore")
    SubscribableChannel receivedAtSuitabilityScore();
    }



    producers for queues :




    @Autowired
    private CustomChannels customChannels;

    public void sendToQuickScore(UpdatedFieldsEntity updatedFieldsEntity) {
    customChannels
    .publishMessageToQuickScore().send(MessageBuilder.withPayload(updatedFieldsEntity).build());
    log.info("sending to Quick score" + updatedFieldsEntity.toString());
    }

    public void sendToCompletenessScore(UpdatedFieldsEntity updatedFieldsEntity) {
    customChannels
    .publishMessageToCompletenessScore()
    .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
    log.info("sending to completeness score" + updatedFieldsEntity.toString());
    }

    public void sendToSuitabilityScore(UpdatedFieldsEntity updatedFieldsEntity) {
    customChannels
    .publishMessageToSuitabilityScore()
    .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
    log.info("sending to suitability score" + updatedFieldsEntity.toString());
    }
    }


    And this is how I am filtering and publishing in different queues :



     @Autowired
    private EventProducer producer;

    public UpdatedFieldsEntity CheckUpdatedKey(UpdatedFieldsEntity updatedFieldsEntity)
    throws RezoomexException {
    logger.info("nn Checking UpdateKeys " + updatedFieldsEntity.toString());
    if (updatedFieldsEntity == null) {
    RezoomexException exception = new RezoomexException("update message is null");
    throw exception;
    }
    for (UpdatedFields updatedFields : updatedFieldsEntity.getUpdatedFields()) {
    UpdateKey element = updatedFields.getUpdateKey();
    if (element.toString().equals(TECHNOLOGIES_UNDER_SKILLSET) || element.toString()
    .equals(TOTAL_EXPERIENCE_VALUE)
    || element.toString().equals(TECHNOLOGIES) || element.toString()
    .equals(TOTAL_EXPERIENCE_SUFFIX)) {
    IsThreeScores = true;
    }

    }
    if (IsThreeScores == true) {
    logger.info("nnn publishing message to all Q");
    producer.sendToQuickScore(updatedFieldsEntity);
    producer.sendToSuitabilityScore(updatedFieldsEntity);
    producer.sendToCompletenessScore(updatedFieldsEntity);
    IsThreeScores = false;
    } else {
    logger.info("nnn publishing message to 2 Q");
    producer.sendToSuitabilityScore(updatedFieldsEntity);
    producer.sendToCompletenessScore(updatedFieldsEntity);
    }
    return updatedFieldsEntity;
    }
    }


    The very first time all queues consumes the message , but at second time any of the three queues throws exception as :



        org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception

    Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:154) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
    ... 43 common frames omitted









    share|improve this question

























      1












      1








      1








      What I am trying to do is, When I receive a message at consumer, I filter that message based on there content the filter will send messages to 3 different queues with the help of three different producers.




      this is the configuration for three queues :




        cloud:
      stream:
      bindings:
      QuickScore:
      concurrency: 5
      destination: quickScore
      content-type: application/json
      group: quickScoreGroup
      maxConcurrency: 10
      recoveryInterval: 10000
      SuitabilityScore:
      concurrency: 5
      destination: suitabilityScore
      content-type: application/json
      group: suitabilityScore
      maxConcurrency: 10
      recoveryInterval: 10000
      CompletenessScore:
      concurrency: 5
      destination: completenessScore
      content-type: application/json
      group: completenessScore
      maxConcurrency: 10
      recoveryInterval: 10000

      rabbitmq:
      host: ${rabbitmq.host:localhost}
      username: guest
      password: guest
      port: 5672



      Custom channel for queues




      public interface CustomChannels {

      @Output("QuickScore")
      MessageChannel publishMessageToQuickScore();

      @Input("QuickScore")
      SubscribableChannel receivedAtQuickScore();

      @Output("CompletenessScore")
      MessageChannel publishMessageToCompletenessScore();

      @Input("CompletenessScore")
      SubscribableChannel receivedAtCompletenessScore();

      @Output("SuitabilityScore")
      MessageChannel publishMessageToSuitabilityScore();

      @Input("SuitabilityScore")
      SubscribableChannel receivedAtSuitabilityScore();
      }



      producers for queues :




      @Autowired
      private CustomChannels customChannels;

      public void sendToQuickScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToQuickScore().send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to Quick score" + updatedFieldsEntity.toString());
      }

      public void sendToCompletenessScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToCompletenessScore()
      .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to completeness score" + updatedFieldsEntity.toString());
      }

      public void sendToSuitabilityScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToSuitabilityScore()
      .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to suitability score" + updatedFieldsEntity.toString());
      }
      }


      And this is how I am filtering and publishing in different queues :



       @Autowired
      private EventProducer producer;

      public UpdatedFieldsEntity CheckUpdatedKey(UpdatedFieldsEntity updatedFieldsEntity)
      throws RezoomexException {
      logger.info("nn Checking UpdateKeys " + updatedFieldsEntity.toString());
      if (updatedFieldsEntity == null) {
      RezoomexException exception = new RezoomexException("update message is null");
      throw exception;
      }
      for (UpdatedFields updatedFields : updatedFieldsEntity.getUpdatedFields()) {
      UpdateKey element = updatedFields.getUpdateKey();
      if (element.toString().equals(TECHNOLOGIES_UNDER_SKILLSET) || element.toString()
      .equals(TOTAL_EXPERIENCE_VALUE)
      || element.toString().equals(TECHNOLOGIES) || element.toString()
      .equals(TOTAL_EXPERIENCE_SUFFIX)) {
      IsThreeScores = true;
      }

      }
      if (IsThreeScores == true) {
      logger.info("nnn publishing message to all Q");
      producer.sendToQuickScore(updatedFieldsEntity);
      producer.sendToSuitabilityScore(updatedFieldsEntity);
      producer.sendToCompletenessScore(updatedFieldsEntity);
      IsThreeScores = false;
      } else {
      logger.info("nnn publishing message to 2 Q");
      producer.sendToSuitabilityScore(updatedFieldsEntity);
      producer.sendToCompletenessScore(updatedFieldsEntity);
      }
      return updatedFieldsEntity;
      }
      }


      The very first time all queues consumes the message , but at second time any of the three queues throws exception as :



          org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception

      Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
      at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:154) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      ... 43 common frames omitted









      share|improve this question














      What I am trying to do is, When I receive a message at consumer, I filter that message based on there content the filter will send messages to 3 different queues with the help of three different producers.




      this is the configuration for three queues :




        cloud:
      stream:
      bindings:
      QuickScore:
      concurrency: 5
      destination: quickScore
      content-type: application/json
      group: quickScoreGroup
      maxConcurrency: 10
      recoveryInterval: 10000
      SuitabilityScore:
      concurrency: 5
      destination: suitabilityScore
      content-type: application/json
      group: suitabilityScore
      maxConcurrency: 10
      recoveryInterval: 10000
      CompletenessScore:
      concurrency: 5
      destination: completenessScore
      content-type: application/json
      group: completenessScore
      maxConcurrency: 10
      recoveryInterval: 10000

      rabbitmq:
      host: ${rabbitmq.host:localhost}
      username: guest
      password: guest
      port: 5672



      Custom channel for queues




      public interface CustomChannels {

      @Output("QuickScore")
      MessageChannel publishMessageToQuickScore();

      @Input("QuickScore")
      SubscribableChannel receivedAtQuickScore();

      @Output("CompletenessScore")
      MessageChannel publishMessageToCompletenessScore();

      @Input("CompletenessScore")
      SubscribableChannel receivedAtCompletenessScore();

      @Output("SuitabilityScore")
      MessageChannel publishMessageToSuitabilityScore();

      @Input("SuitabilityScore")
      SubscribableChannel receivedAtSuitabilityScore();
      }



      producers for queues :




      @Autowired
      private CustomChannels customChannels;

      public void sendToQuickScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToQuickScore().send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to Quick score" + updatedFieldsEntity.toString());
      }

      public void sendToCompletenessScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToCompletenessScore()
      .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to completeness score" + updatedFieldsEntity.toString());
      }

      public void sendToSuitabilityScore(UpdatedFieldsEntity updatedFieldsEntity) {
      customChannels
      .publishMessageToSuitabilityScore()
      .send(MessageBuilder.withPayload(updatedFieldsEntity).build());
      log.info("sending to suitability score" + updatedFieldsEntity.toString());
      }
      }


      And this is how I am filtering and publishing in different queues :



       @Autowired
      private EventProducer producer;

      public UpdatedFieldsEntity CheckUpdatedKey(UpdatedFieldsEntity updatedFieldsEntity)
      throws RezoomexException {
      logger.info("nn Checking UpdateKeys " + updatedFieldsEntity.toString());
      if (updatedFieldsEntity == null) {
      RezoomexException exception = new RezoomexException("update message is null");
      throw exception;
      }
      for (UpdatedFields updatedFields : updatedFieldsEntity.getUpdatedFields()) {
      UpdateKey element = updatedFields.getUpdateKey();
      if (element.toString().equals(TECHNOLOGIES_UNDER_SKILLSET) || element.toString()
      .equals(TOTAL_EXPERIENCE_VALUE)
      || element.toString().equals(TECHNOLOGIES) || element.toString()
      .equals(TOTAL_EXPERIENCE_SUFFIX)) {
      IsThreeScores = true;
      }

      }
      if (IsThreeScores == true) {
      logger.info("nnn publishing message to all Q");
      producer.sendToQuickScore(updatedFieldsEntity);
      producer.sendToSuitabilityScore(updatedFieldsEntity);
      producer.sendToCompletenessScore(updatedFieldsEntity);
      IsThreeScores = false;
      } else {
      logger.info("nnn publishing message to 2 Q");
      producer.sendToSuitabilityScore(updatedFieldsEntity);
      producer.sendToCompletenessScore(updatedFieldsEntity);
      }
      return updatedFieldsEntity;
      }
      }


      The very first time all queues consumes the message , but at second time any of the three queues throws exception as :



          org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception

      Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
      at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:154) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:89) ~[spring-integration-core-4.3.14.RELEASE.jar!/:4.3.14.RELEASE]
      ... 43 common frames omitted






      spring-boot rabbitmq






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 23 '18 at 10:59









      milindjoshimilindjoshi

      155




      155
























          1 Answer
          1






          active

          oldest

          votes


















          0














          The problem is because you are using same channel for Input and Output (i.e consuming message and posting message in queue from same channel).
          Have different Channel for Consuming for eg:-



            @Output("QuickScore")
          MessageChannel publishMessageToQuickScore();

          @Input("Score")
          SubscribableChannel receivedAtQuickScore();


          In your code change Channel name for @input or @output.






          share|improve this answer
























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445402%2fi-setup-three-rabbitmq-queues-with-spring-cloud-one-of-the-queues-randomly-fail%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            The problem is because you are using same channel for Input and Output (i.e consuming message and posting message in queue from same channel).
            Have different Channel for Consuming for eg:-



              @Output("QuickScore")
            MessageChannel publishMessageToQuickScore();

            @Input("Score")
            SubscribableChannel receivedAtQuickScore();


            In your code change Channel name for @input or @output.






            share|improve this answer




























              0














              The problem is because you are using same channel for Input and Output (i.e consuming message and posting message in queue from same channel).
              Have different Channel for Consuming for eg:-



                @Output("QuickScore")
              MessageChannel publishMessageToQuickScore();

              @Input("Score")
              SubscribableChannel receivedAtQuickScore();


              In your code change Channel name for @input or @output.






              share|improve this answer


























                0












                0








                0







                The problem is because you are using same channel for Input and Output (i.e consuming message and posting message in queue from same channel).
                Have different Channel for Consuming for eg:-



                  @Output("QuickScore")
                MessageChannel publishMessageToQuickScore();

                @Input("Score")
                SubscribableChannel receivedAtQuickScore();


                In your code change Channel name for @input or @output.






                share|improve this answer













                The problem is because you are using same channel for Input and Output (i.e consuming message and posting message in queue from same channel).
                Have different Channel for Consuming for eg:-



                  @Output("QuickScore")
                MessageChannel publishMessageToQuickScore();

                @Input("Score")
                SubscribableChannel receivedAtQuickScore();


                In your code change Channel name for @input or @output.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 30 '18 at 11:48









                Adib RajiwateAdib Rajiwate

                13512




                13512
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53445402%2fi-setup-three-rabbitmq-queues-with-spring-cloud-one-of-the-queues-randomly-fail%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    這個網誌中的熱門文章

                    Hercules Kyvelos

                    Tangent Lines Diagram Along Smooth Curve

                    Yusuf al-Mu'taman ibn Hud