Defining the Input Command Hierarchy, Reading the Configuration, and Adding the Message

To define the hierarchy of user commands specific to your application, you write DDL code and save it in a file with the suffix cmd.dd in the src/lib/ddl/input directory in your development sandbox.

For example, the Hello World DDL to define the command show sync message is defined in the file helloworld.cmd.dd as follows:

#define DNAME_HELLOWORLD "helloworld"

#define HELLOWORLD_ACTION \
  action execute DNAME_HELLOWORLD;

command juniper-command {

     /*
     * show sync functionality
     */
    command show {
        command sync {
            require view;
            help "Show SDK Your Net Corp. application information";
            
            command helloworld {
                require view;
                help "Show helloworld information";
    
                command message {
                    help "Show the message";
                    HELLOWORLDD_ACTION;
                }
            }
        }
    }
}

In the previous code, the action execute DNAME_HELLOWORLD statement invokes the daemon when the user presses Return within the operational mode of the CLI.

When your makefile runs the DDL compiler, the output goes to the obj-i386/lib/ddl/feature directory. Variables the compiler generates from the configuration have the preface DDLNAME_, and your function code must reference them with this prefix.

The constants for sequence and package name, which you specify as parameters to the junos_daemon_init() function, are also generated by the DDL compiler in obj-i386/lib/ddl/feature/application-name_sequence.h. For example, if your application name is sync, the sequence.h file contains:

#define SEQUENCE_NUMBER 0xd4396e96
#define PACKAGE_NAME   "syncps"

For more information about how to write DDL, see the DDL Guide included in this documentation set.

Reading the Configuration

To read the configuration you coded in DDL, the application uses the DDL Access (DAX) APIs to perform the following operations:

  1. Define a data object pointer (using a predefined DAX data type) to access the values:

    ddl_handle_t *dop = NULL;

  2. Define variables to retrieve and store the data as required by the DAX API function call syntax. For example, the hw_data_config_name array is defined to correspond to the path parameter in the function dax_get_object_by_path(), which is defined as follows:

    ddl_boolean_t dax_get_object_by_path (
       ddl_handle_t *root, 
       const char *path[], 
       ddl_handle_t **r_dop,
       ddl_boolean_t changed)
    

    The path consists of the tokens that compose the show command, which are stored as branches in the DDL hierarchy:

    sync
      helloworld
          message
    

    The DDL compiler translates the tokens as:

    DDLNAME_SYNC
        DDLNAME_SYNC_HELLOWORLD,
           DDLNAME_SYNC_HELLOWORLD_MESSAGE
    

    And the code defines the path array as:

        const char  *hw_data_config_name[] = 
                                         {DDLNAME_SYNC,
                                          DDLNAME_SYNC_HELLOWORLD,
                                          DDLNAME_SYNC_HELLOWORLD_MESSAGE,
                                          NULL};
    

  3. Call DAX accessor functions to retrieve the data. dax_get_object_by_path() finds a string (in this application, the message the user entered), and dax_get_stringr_by_aid() retrieves the string into an array.

    The add_message() function then adds the message to the database.

    /* variable definitions: */
     ddl_handle_t *dop = NULL; /* DDL Object Pointer */
         const char    *hw_data_config_name[] = 
                                           {DDLNAME_SYNC,
                                            DDLNAME_SYNC_HELLOWORLD,
                                            DDLNAME_SYNC_HELLOWORLD_MESSAGE,
                                            NULL};
     char         hw_msg[MESSAGE_STR_SIZE];
     int          status = SUCCESS;
    
    
    /* function calls: */
    if (dax_get_object_by_path(NULL, hw_data_config_name, &dop, FALSE)) {
     
             if (dax_is_changed(dop)) {
                 /* if message has changed */
     
                 /* clear stored config data, & repopulate with new config data */
                 clear_messages();
         
                 if (dax_get_stringr_by_aid(dop, HELLOWORLD_MESSAGE_CONTENTS, 
                         hw_msg, sizeof(hw_msg))) {
         
                     add_message(hw_msg); /* add this data (a message) */
         
                 } else {
                     status = EFAIL;
                 }
             }
         }
    
    ...
    

  4. When the daemon finds the message, it calls add_message() to store the message in the patricia tree (see Creating the Tree and Adding Messages).

Coding, Fetching, and Displaying the Output


2007-2009 Juniper Networks, Inc. All rights reserved. The information contained herein is confidential information of Juniper Networks, Inc., and may not be used, disclosed, distributed, modified, or copied without the prior written consent of Juniper Networks, Inc. in an express license. This information is subject to change by Juniper Networks, Inc. Juniper Networks, the Juniper Networks logo, and JUNOS are registered trademarks of Juniper Networks, Inc. in the United States and other countries. All other trademarks, service marks, registered trademarks, or registered service marks are the property of their respective owners.
Generated on Sun May 30 20:26:47 2010 for Juniper Networks Partner Solution Development Platform JUNOS SDK 10.2R1 by Doxygen 1.4.5