Quantcast
Viewing all articles
Browse latest Browse all 3285

Dirigible - Extensions vs Configurations

If somebody asks you just right now "What do you require most from your business software in general?", what will pop up in your mind first?

To be ...reliable, secure, feature rich? ... Cheaper? – Noo!...

 

What about  being configurable, flexible, or extendable?

 

Well, it is clear that for business applications, in comparison to other types of

software bundles like HTTP Servers, Databases, Office Packages, etc., it is vital to be adaptable to the particular business processes within a given company.

 

How much effort do businesses usually spend for customizations? What is the cost of that? What is the timeframe?

 

Sounds familiar? Then we are on the right track.

 

How does the product owner usually imagine the adaptable software?

As a single generic screen, fully "responsive" and depending on the user's type, role, use-case, and any other parameter one can imagine. On the other side it results in thousands of configuration entries.

 

This works! We proudly have enough examples based on this approach.

The product owner is on the safe side - "reusing"! He/she doesn't make any "double efforts"!

Unfortunately, there are several issues with this approach:

- Relatively big effort to develop such a highly configurable screen

- Relatively big effort to configure it - per user, role, etc.

- Relatively big effort to change it once being shipped

- Relatively big effort to support it

- Relatively low performance

- ...  And the saddest part is that, usually, it becomes equally complex and difficult for everyone.

 

(Disclaimer: Everything mentioned above is intentionally exaggerated.)

 

What to do then?

The other option is to build tailored screens and underlying services for a given role.

Can we build multiple end-to-end vertical stacks easily and fast with Dirigible on SAP HANA Cloud Platform?

You already know that, so we can finish the article now.

 

Unfortunately, this is not so simple either.

What if we want to reuse the services provided by the vendor of the packaged software,

and want to add just a few fields, but in the way to survive the next update/upgrade of the basis?

You would like to have something like a BAdI or Eclipse plugin mechanisms, right?

Let’s see whether the extensibility feature we have recently added to Dirigible can supply such a need...

 

To explore the capabilities of extensions in Dirigible, we will create two projects – “products” and “products_discounter”. The first project will be the one with the extension point and the second will be with the extension. The “products” project will display information about products

Image may be NSFW.
Clik here to view.
_1.png

and the “products_discounter” will show the discounted items.

Image may be NSFW.
Clik here to view.
_2.png

The final result will be:

 

Image may be NSFW.
Clik here to view.
_3.png

 

In the “products” project we will create

  • Database table for products
  • Delimiter Separated Values (DSV) file that will provide sample data for the table
  • Discounts extension point
  • Menu extension point
  • RESTfull scripting service
  • Menu scripting service
  • UI

 

In the “products_discounter” project we will create

  • Database table for discounted products
  • Delimiter Separated Values (DSV) file with sample data
  • Discounts extension
  • Menu extension
  • Discounts extension implementation
  • Menu extension implementation
  • UI

 

We have plenty of work, so let’s get started.


  • First, create a new blank project "products".

Image may be NSFW.
Clik here to view.
_4.png

 

Image may be NSFW.
Clik here to view.
_5.png

 

  • Then, add a  new database table "products.table"

Image may be NSFW.
Clik here to view.
_6.png

 

Image may be NSFW.
Clik here to view.
_7.png

 

Image may be NSFW.
Clik here to view.
_8.png

 

  • The easiest way to supply data for the newly created table is to go to the “DataStructures” folder and create a new file - "products.dsv". Enter the following records:
1|Dumbbell|100|http://www.aloyd.com/home/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/r/u/rubber-hex-dumbbell.jpg
2|Leg extension|155|http://www.pacillo.com/products/kf_leg_extension_b.jpg
3|Squad rack|153|http://images.monstermarketplace.com/gym-flooring-and-fitness-equipment/valor-bd-19-sawtooth-squat-rack-bench-press-combo-600x600.jpg
4|Shoulder press|300|http://gymstogo.com/commercial-gym-equipment/plate-loaded/precor-fitness/shoulder-press--550-discovery-line.jpg


Image may be NSFW.
Clik here to view.
_9.png


  • Now we want to get a discount for some “products”. This will be done through extension point. Create a new extension point in the “ExtensionDefinitions “ folder and give it a name of "discounted_products.extensionpoint".

Image may be NSFW.
Clik here to view.
_10.png

 

It should look like this:

Image may be NSFW.
Clik here to view.
_11.png

 

  • We want our final version to have a menu for navigation through different tabs. Also we want the UI for the discounted products to be provided by other project. For that purpose, we will add a new "Extension Point" - "products_menu.extensionpoint". It will look like this:

Image may be NSFW.
Clik here to view.
_12.png

 

  • “Activate” and “Publish” the project.

Image may be NSFW.
Clik here to view.
_14.png

 

Image may be NSFW.
Clik here to view.
_13.png

 

  • Let's expose our table through “ScriptingService”. Choose “Entity Service on Table” and from the list find our "products" table. Give it the name  “products.js”.

Image may be NSFW.
Clik here to view.
_15.png

 

  • Expand “ScriptingServices” folder and open "products.jslib".
  • Navigate to the "exports.readProductsList" function and add the following lines.
var extensions = extensionManager.getExtensions("/products/discounted_products");
for (var i=0;i<extensions.length;i++) {    var extension = require(extensions[i]);    result = extension.getDiscounts();
}

It should look like this:

Image may be NSFW.
Clik here to view.
_16.png


  • The menu for “products” project will be provided through “ScriptingService”. Create a new file into "ScriptingService" folder and name it "menu.js".
  • Copy and paste inside the following lines:
var menu = [    {        "name": "Products",        "link": "../../web/products/products.html",        "subMenu": []    }
];
var extensions = extensionManager.getExtensions("/products/products_menu");
for (var i=0;i<extensions.length;i++) {    var extension = require(extensions[i]);    menu = extension.getMenuItems(menu);
}

response.setContentType("text/json");
  response.getWriter().println(JSON.stringify(menu));

Image may be NSFW.
Clik here to view.
_17.png

 

  • Now we will create the UI for our products - "products.html" in “WebContent” folder. Use the following code:
<!DOCTYPE html><html lang="en" ng-app><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content=""><meta name="author" content=""><title>Home</title><link rel="stylesheet"
 href="../../components/bootstrap/dist/css/bootstrap.min.css"></head><body>    <div id="wrap">          <div class="container">              <div ng-controller="ListController">                    <div class="col-lg-3 col-md-6 hero-feature ng-scope" ng-repeat="entry in data">                        <a class="thumbnail btn btn-default" href="#/content" target="_self">                              <img src="{{entry.image}}">                              <div class="caption">                                  <h3 class="ng-binding">{{entry.name}}</h3>                                  <p>$ {{entry.price}}</p>                              </div>                        </a>                    </div>              </div>          </div>    </div>    <script src="../../components/angular/angular.min.js"></script>    <script src="../../components/angular-resource/angular-resource.min.js"></script>    <script type="text/javascript">          function ListController($scope, $http) {              var url = '/dirigible/js/products/products.js';              $http.get(url)                    .success(function(data) {                        $scope.data = data;                    });          }    </script></body></html>

Image may be NSFW.
Clik here to view.
_18.png

 

  • To make our project complete, we need to add a menu for navigation between different tabs. Create a new "User Interface" - "Index Page with Main Menu, Header, and Footer".

Image may be NSFW.
Clik here to view.
_19.png

 

  • Leave the default file name ("index.html"), and for the title enter "Products".

Image may be NSFW.
Clik here to view.
_20.png

 

So far, so good. To complete the UI part in the “products” project we need to make one last change.

 

  • Open "footer.html" and replace
$.getJSON("main.menu", function(data) {

with

$.getJSON("../../js/products/menu.js", function(data) {

Image may be NSFW.
Clik here to view.
_21.png

 

  • Apply the same change in “index.html”, as well.
  • “Activate” and “Publish” the project.

 

Now we are ready with the main project.

 

Let’s add an extension project that will provide the discounted products.


  • Create a new "Blank project" and name it "products_discounter".
  • In this project, we need a table with the discounted products. Create a new "Database table". It looks like this:

Image may be NSFW.
Clik here to view.
_22.png

 

  • Name it "discounted_products.table".
  • Create a file “discounted_products.dsv" into the "DataStructures" folder and enter some data.
1|0.25
2|0.40

Image may be NSFW.
Clik here to view.
_23.png

 

  • Create "products_discounter.extension" extension. The value for "extension-point" should be "/products/discounted_products" – the extension point from “products” project.


Image may be NSFW.
Clik here to view.
_24.png

 

  • For the menu, we need to create a new "Extension" - "products_menu_provider.extension".
  • For the target "extension-point", set "/products/products_menu".

Image may be NSFW.
Clik here to view.
_25.png

 

  • Go to "ScriptingServices" folder and create a new file named "products_discounter.jslib". Here will be the implementation for the “products_discounter” extension. Place inside the following code:
function createEntity(resultSet, data) {    var result = {};    result.id = resultSet.getInt("ID");    result.name = resultSet.getString("NAME");    result.image = resultSet.getString("IMAGE");    result.price = resultSet.getString("PRICE");    var discount = resultSet.getString("DISCOUNT");    if(discount !== null && discount > 0 ){        result.discount_price = result.price - (result.price * discount);    }    return result;
}

exports.getDiscounts = function() {
    var discounts = [];    var connection = datasource.getConnection();    try {        var sql = "select p.id, p.name, p.image, p.price, d.discount from products p left join discounted_products d on p.id = d.product_id order by d.discount";         var statement = connection.prepareStatement(sql);        var resultSet = statement.executeQuery();        var value;        while (resultSet.next()) {                discounts.push(createEntity(resultSet));        }     } catch(e){            } finally {        connection.close();        return discounts;    }
};

Image may be NSFW.
Clik here to view.
_26.png

 

  • To finish with the extensions, we need to provide logic for the “products_menu_provider” extension. Create a new file in "ScriptingService" folder with name "products_menu_provider.jslib".
  • Place inside the following code:
exports.getMenuItems = function(menu) {    for(var i = 0 ; i < menu.length; i ++ ){        if(menu[i].name == "Products"){            menu[i].link = "../../web/products_discounter/discounted.html";        }    }    return menu;
};

Image may be NSFW.
Clik here to view.
_27.png

 

Last but not least, let's add some UI.

 

  • In the "WebContent" folder, create a file named "discounted.html".
  • Copy and paste the following code:
<!DOCTYPE html><html lang="en" ng-app><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content=""><meta name="author" content=""><title>Home</title><link rel="stylesheet" href="../../components/bootstrap/dist/css/bootstrap.min.css"><style>  h1,h2,h3,h4,h5,h6,p {    white-space: normal;  }  .discounted{    border-style: solid;    border-color: red;    border-radius: 10px;  }  .discounted:hover  {    background-color: red;  }  .discounted:hover h3 {    color:white;  }  .discounted:hover span {    color:white;  }  .old-price {    text-decoration:line-through;    font-size: 50%  }  .new-price {    color: red;    font-weight: bold;  }</style></head><body>  <div id="wrap">  <div class="container">        <div ng-controller="ListController">          <div class="col-lg-3 col-md-3 col-sm-4 col-xs-6 hero-feature ng-scope" ng-repeat="entry in data">    <a class="thumbnail btn btn-default" ng-class="{discounted: entry.discount_price}" href="#/content" target="_self">              <img src="{{entry.image}}">    <div class="caption">  <h3 class="ng-binding">{{entry.name}}</h3>  <h3 ng-hide="entry.discount_price" >$ {{entry.price}}</h3>                <div ng-show="entry.discount_price">        <h3><span class="old-price">$ {{entry.price}}</span> <span class="new-price">$ {{entry.discount_price}}</span></h3>                </div>  </div>      </a>      </div>        </div>  </div>  </div>  <script src="../../components/angular/angular.min.js"></script>  <script src="../../components/angular-resource/angular-resource.min.js"></script>  <script type="text/javascript">  function ListController($scope, $http) {    var url = '/dirigible/js/products/products.js';  $http.get(url)  .success(function(data) {      $scope.data = data;  });  }  </script></body></html>

Because the page with discounted products is in another project wherethere is neither "header.html" nor "footer.html", a menu is lacking, too. The first approach is just to copy and paste them, but this is not a good solution. We don't want double maintenance of our code, we just want to reuse the "header" and "footer" files. For that purpose, we’ll make little magic in the “products_discounter” project.

 

  • In the "WebContent" folder, create "header.ref" and "footer.ref" files. Yes we will just reference the original "header" and "footer".
  • In the "header.ref" file, enter:
/products/header.html


  • In the "footer.ref" file, enter:
/products/footer.html


  • “Activate” and “Publish” the project.
  • Now click on "discounted.html" and see the result in the "Web Viewer" tab.

 

Finally we are done. We have reached our goal! Image may be NSFW.
Clik here to view.

Image may be NSFW.
Clik here to view.
_28.png

 

 

 

Do you think this approach can be helpful for your extensibility story ... or you still prefer the "configurations" way?


Viewing all articles
Browse latest Browse all 3285

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>