About Me

My photo
FullStack Software Engineer,Visa Inc.Singapore

Wednesday, November 8, 2017

Handling POST request using akka-http in a akka-actor system

Akka-htp is a well known module for providing full server side as well as client side http stack currently supporting Scala and Java language bindings. Among other Java Rest frameworks/libraries such as Spring-boot, Play Framework, JAX-RS, Jersy or Scalatra, akka-http is more preferable in applications where high throughput and concurrency is expected.

Akka-http is not a full MVC framework like Play or not require a container to run like scalatra. As it is based on akka-actor and akka-stream modules inherently reactive and works well with message driven systems. As it supports for different levels(low level and high levl) of APIs makes it easy to adopt and ease of deployment.

Here is a simple example of using Akka-http high level API in Java in a akka-actor system.

First we need following dependencies to be included in our project.




Here we initialize the http server and bind with the akka system. 

We can define our router class by extending 'AllDirectives' class as follows. We use this to get a Route object while initializing the 'routeFlow' as above.

import akka.http.javadsl.model.ContentTypes;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.server.AllDirectives;
import akka.http.javadsl.server.Route;

import static akka.http.javadsl.server.PathMatchers.integerSegment;
import static akka.http.javadsl.server.PathMatchers.segment;

public class Router extends AllDirectives {

    //host:port/api/{userId}/{resourceId}
    public Route createRoute() {
        return route(
                pathPrefix(segment("api"),
                        () -> pathPrefix(integerSegment(),
                                userId -> pathPrefix(segment(),
                                        resourceId -> pathEndOrSingleSlash(
                                            () -> processRequest(userId, resourceId))
                                )
                        )
               )
        );
    }

}

In the processRequest method we provide the POST request handler which returns a 'akka.http.javadsl.server.Route' instance.
    private Route processRequest(args...) {
        return post(() -> entity(handler...)
        );
    }

Based on the request body (Content-Type) we can use a specific Unmarshaller to access request body data. As an example in order to parse the JSON request body we can use a Unmarshaller provided by 'akka.http.javadsl.unmarshalling.Unmarshaller' , 'akka-http-jackson-experimental_2.11' package, Gson etc.

Using akka.http.javadsl.marshallers.jackson.Jackson;
import akka.http.javadsl.marshallers.jackson.Jackson;

public Route processRequestUsingJackson(int userId,String resourceId) {

        return post(() -> entity(Jackson.unmarshaller(Request.class),
                                    content ->
                                        completeWithFuture(
                                            CompletableFuture.completedFuture(
                                                HttpResponse.create()
                                                .withEntity(ContentTypes.APPLICATION_JSON, "{\"msg\":\"Success\"}")
                                            )
                                        )
                                )
        );
    }

Here we use default akka Unmarshaller package to parse entity to string and then Gson to get the Java object.

import akka.http.javadsl.unmarshalling.Unmarshaller;
import com.google.gson.Gson;

private Route processRequestUsingGson(int userId,String resourceId) {

        return post(() -> entity(Unmarshaller.entityToString(), content -> {

                    final Gson gson = new Gson();
                    final Request requestBody = gson.fromJson(content, Request.class);

                    return completeWithFuture(
                                CompletableFuture.completedFuture(
                                        HttpResponse.create()
                                        .withEntity(ContentTypes.APPLICATION_JSON, "{\"msg\":\"Success\"}")
                                )
                    );
                }
            )
        );
    }

Monday, October 30, 2017

Uploading maven artifacts to a ftp location using SFTP protocol.

Apache Maven Wagon is a set of plugins developed to provides a transport abstraction for handling maven artifacts and repositories. Shown below is the way to use 'wagon-ssh' plugin to upload maven artifacts to a ftp location using the SFTP protocol.

This is quite straight forward and requires few elements to be configured in the pom.xml as follows.

1. Configure repository location of the wagon-git plugin.


        
            synergian-repo
            https://raw.github.com/synergian/wagon-git/releases
        

2. Include the 'wagon-ssh' plugin extension configuration inside the 'build' element.


        
            
                org.apache.maven.wagon
                wagon-ssh
                2.8
            
        

3. Finally we need to include our ftp location using the 'distributionmanagement' element. During the build process artifacts will be uploaded in to following location.


        
            mvn-ftp-server
            sftp://ftp.aravinda-sites.com/my-ftp-repo
        

In order to use SFTP protocol maven settings.xml need to be updated with the ftp server access keys. Here the 'id' defined in the repository should match with the server id.


    
      mvn-ftp-server
      /Users/aravinda/.ssh/id_rsa
      passPhrase
  

Now you can execute,
'
mvn deploy

command to upload the artifacts.

Thursday, August 17, 2017

Changing max pass through request body size in Nginx for AWS Elastic Beanstalk

Most of the NodeJS applications in Elastic Beanstalk uses a Nginx as reverse proxy which routes requests from port 80 to 8080. Reason being the out of the box NginX support for NodeJS applications in beanstalk.

Recently i was working in a nodejs application which uploads images and video files to AWS S3 and our deployment environment is Elastic Beanstalk.

With the default Nginx configuration i came across following error when i try to upload large files.

-------------------------------------
/var/log/nginx/error.log
-------------------------------------
2017/08/17 08:12:16 [error] 20884#0: 
*526 client intended to send too large body: 41324010 bytes,
client: 10.0.0.10, 
server: , request: "POST /filelink/upload HTTP/1.1", 
host: "fileuploader***.elasticbeanstalk.com"
-------------------------------------

As clearly mentioned in the log Nginx doesn't allow requests with large body to pass through it. Default max value is ~2MB. 

Elastic beanstalk allows this kind of configurations to be manipulated via, .ebextensions. What we need to do is to create a folder as .ebextensions in your root directory of the node project and add a SOME_NAME.config file to it with the following Nginx configuration. Here we are changing the property, client_max_body_size to 50M which increases the pass through file size.

files:
  /etc/nginx/conf.d/proxy.conf:
    content:  |
      client_max_body_size 50M;

Here is a sample nginx configuration from official documentation.


Let me know your thoughts.

Sunday, August 31, 2014

Dive into Oracle : Data Grouping and Merging

In this post we are going to discuss about commonly used Oracle database queries for manipulate data mainly grouping and merging. If the database structure is normalized and when it comes to visualization of data, it is required to group data based on their common characteristics. Similarly in most of the database systems including Oracle, Merging is the functionality provided in order to migrate data between two databases, schema or tables.

Let's create a simple database structure as follows. We can use a tool like SQL Fiddle to run queries and see how it works. Make sure you have selected Oracle 11g R2 as DB type before running any queries.

CREATE TABLE SEMISTER_GPA(
    STUDENT_ID VARCHAR2(8),
    SEMISTER_ID VARCHAR2(4),
    GPA NUMBER(5,4),
    PRIMARY KEY (STUDENT_ID,SEMISTER_ID)
);
Adding some values to above tables.
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000001','L1S1',3.5245);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000002','L1S1',3.6100);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000003','L1S1',3.0589);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000001','L1S2',3.7241);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000002','L1S3',3.8180);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000003','L1S2',3.2589);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000002','L1S4',3.8675);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000002','L2S1',3.2369);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000003','L1S4',3.6523);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000001','L1S4',3.2675);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000003','L2S1',3.4389);
INSERT INTO SEMISTER_GPA(STUDENT_ID,SEMISTER_ID,GPA) VALUES ('ST000003','L2S2',3.0523);
See in SQL Fiddle.

01. Simple grouping: Get the no. of semesters each student has completed.
SELECT STUDENT_ID,COUNT(*) FROM SEMISTER_GPA GROUP BY STUDENT_ID;





02. DENSE_RANK() and PARTITION BY

'PARTITION BY' is used partition a table into different segments which makes easier to manipulate each segment individually. Here 'SEMISTER_GPA' table can be partition by STUDENT_ID. In order to get the row which has the highest 'GPA' for each student, each segment is ordered by 'GPA' in descending order. Then the row which has the DENSE_RANK()=1 gives the expected result.
    SELECT DT.STUDENT_ID,
           DT.SEMISTER_ID,
           DT.GPA
    FROM   (SELECT STUDENT_ID,
                   SEMISTER_ID,
                   GPA,
                   DENSE_RANK()
                     OVER (
                       PARTITION BY STUDENT_ID
                       ORDER BY GPA DESC) RNK
            FROM   SEMISTER_GPA) DT
    WHERE  ( DT.RNK = 1 )


03. LISTAGG () function

This function gives a single row, concatenated using specified column within each group ordered. To get the list of semesters each student has completed, we can group table using STUDENT_ID order each group by GPA and concatenate column values using above function.

    SELECT STUDENT_ID,
           LISTAGG(SEMISTER_ID, ',')
             WITHIN GROUP (ORDER BY SEMISTER_ID) AS SEMISTER_LIST
    FROM   SEMISTER_GPA
    GROUP  BY STUDENT_ID


Below mentioned is another sample data set. Timezone data is stored in two tables  TIME_ZONE and TIMEZONE_DESCRIPTIONS. In order to migrate data into a single denormalized table 'MERGE INTO .. USING.. ' statement can be used. Merging can handle insert or update unconditionally without knowing it's presence in target table. This is a more flexible way of moving large amounts of data extracted from one or more tables. See in SQL Fiddle.

CREATE TABLE TIME_ZONE
  (
     TIMEZONE_ID     NUMBER(3) NOT NULL,
     TIMEZONE_OFFSET VARCHAR2(10),
     MODIFIED_DATE   DATE DEFAULT SYSDATE NOT NULL,
     PRIMARY KEY (TIMEZONE_ID)
  );

CREATE TABLE TIMEZONE_DESCRIPTIONS
  (
     TIMEZONE_ID   NUMBER(3) NOT NULL,
     LANGUAGE_ID   VARCHAR2(2) DEFAULT 'EN' NOT NULL,
     DESCRIPTION   NVARCHAR2(100),
     MODIFIED_DATE DATE DEFAULT SYSDATE NOT NULL,
     PRIMARY KEY (TIMEZONE_ID, LANGUAGE_ID)
  );

Insert into TIME_ZONE (TIMEZONE_ID,TIMEZONE_OFFSET,MODIFIED_DATE) values (1,'+0300',SYSDATE);
Insert into TIME_ZONE (TIMEZONE_ID,TIMEZONE_OFFSET,MODIFIED_DATE) values (2,'+0200',SYSDATE);
Insert into TIME_ZONE (TIMEZONE_ID,TIMEZONE_OFFSET,MODIFIED_DATE) values (3,'+0400',SYSDATE);
Insert into TIME_ZONE (TIMEZONE_ID,TIMEZONE_OFFSET,MODIFIED_DATE) values (5,'-0400',SYSDATE);
Insert into TIME_ZONE (TIMEZONE_ID,TIMEZONE_OFFSET,MODIFIED_DATE) values (6,'+0400',SYSDATE);

Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (1,'EN','Saudi Arabia',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (2,'EN','Egypt',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (3,'EN','UAE',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (5,'EN','USA',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (6,'EN','Oman',SYSDATE);

Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (1,'FR','Arabie Saoudite',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (2,'FR','Egypte',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (3,'FR','Émirats arabes unis',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (5,'FR','USA',SYSDATE);
Insert into TIMEZONE_DESCRIPTIONS (TIMEZONE_ID,LANGUAGE_ID,DESCRIPTION,MODIFIED_DATE) values (6,'FR','Oman',SYSDATE);

Denormalized table structure.

CREATE TABLE TIME_ZONE_MASTER (
    TIMEZONE_ID NUMBER(3) NOT NULL,
    TIMEZONE_OFFSET VARCHAR2(10),
    DESCRIPTION NVARCHAR2(100),
    MODIFIED_DATE DATE DEFAULT SYSDATE  NOT NULL,
    PRIMARY KEY (TIMEZONE_ID)
);

Select data set from TIMEZONE_DESCRIPTIONS table to join with TIME_ZONE table. In the target table, language wise descriptions will be stored in the same row according to a predefined format.

    SELECT X.TIMEZONE_ID,
           MAX(X.MODIFIED_DATE) AS MODIFIED_DATE,
           'EN:'
           || MAX(DECODE(X.LANGUAGE_ID, 'EN', X.DESCRIPTION))
           || ',FR:'
           || MAX(DECODE(X.LANGUAGE_ID, 'FR', X.DESCRIPTION)) TIME_ZONE_DESC
    FROM   (SELECT TZD.TIMEZONE_ID,
                   TZD.LANGUAGE_ID,
                   TZD.DESCRIPTION,
                   TZD.MODIFIED_DATE
            FROM   TIMEZONE_DESCRIPTIONS TZD) X
    GROUP  BY X.TIMEZONE_ID;

To get the full select statement, join with TIME_ZONE table using TIMEZONE_ID.

SELECT tz.TIMEZONE_ID,
       tz.TIMEZONE_OFFSET,
       v.TIME_ZONE_DESC,
       GREATEST(v.MODIFIED_DATE, tz.MODIFIED_DATE) AS MODIFIED_DATE
FROM   TIME_ZONE tz
       LEFT OUTER JOIN (SELECT x.TIMEZONE_ID,
                               MAX(x.MODIFIED_DATE) AS MODIFIED_DATE,
                               'EN:'
                               || MAX(DECODE(x.LANGUAGE_ID, 'EN', x.DESCRIPTION))
                               || ',FR:'
                               || MAX(DECODE(x.LANGUAGE_ID, 'FR', x.DESCRIPTION)) TIME_ZONE_DESC
                        FROM   (SELECT tzd.TIMEZONE_ID,
                                       tzd.LANGUAGE_ID,
                                       tzd.DESCRIPTION,
                                       tzd.MODIFIED_DATE
                                FROM   TIMEZONE_DESCRIPTIONS tzd) x
                        GROUP  BY x.TIMEZONE_ID) v
                    ON ( tz.TIMEZONE_ID = v.TIMEZONE_ID );

Merge statement syntax,

MERGE INTO TARET_TABLE USING
      (SELECT
    )ON (JOIN)
WHEN MATCHED THEN UPDATE
  SET
WHEN NOT MATCHED THEN
  INSERT
    ()
    VALUES
    ();

Finally, we can create the full merge statement to update TIME_ZONE_MASTER as follows.

MERGE INTO TIME_ZONE_MASTER t
USING (SELECT tz.TIMEZONE_ID,
              tz.TIMEZONE_OFFSET,
              v.TIME_ZONE_DESC,
              GREATEST(v.MODIFIED_DATE, tz.MODIFIED_DATE) AS MODIFIED_DATE
       FROM   TIME_ZONE tz
              LEFT OUTER JOIN (SELECT x.TIMEZONE_ID,
                                      MAX(x.MODIFIED_DATE)
                                      AS
                                                           MODIFIED_DATE,
                                      'EN:'
                                      || MAX(DECODE(x.LANGUAGE_ID, 'EN',
                                             x.DESCRIPTION))
                                      || ',FR:'
                                      || MAX(DECODE(x.LANGUAGE_ID, 'FR',
                                             x.DESCRIPTION))
                                                           TIME_ZONE_DESC
                               FROM   (SELECT tzd.TIMEZONE_ID,
                                              tzd.LANGUAGE_ID,
                                              tzd.DESCRIPTION,
                                              tzd.MODIFIED_DATE
                                       FROM   TIMEZONE_DESCRIPTIONS tzd) x
                               GROUP  BY x.TIMEZONE_ID) v
                           ON ( tz.TIMEZONE_ID = v.TIMEZONE_ID )) TD
ON (t.TIMEZONE_ID = TD.TIMEZONE_ID)
WHEN MATCHED THEN
  UPDATE SET t.DESCRIPTION = TD.TIME_ZONE_DESC,
             t.TIMEZONE_OFFSET = TD.TIMEZONE_OFFSET,
             t.MODIFIED_DATE = TD.MODIFIED_DATE
WHEN NOT MATCHED THEN
  INSERT ( TIMEZONE_ID,
           TIMEZONE_OFFSET,
           DESCRIPTION,
           MODIFIED_DATE )
  VALUES ( TD.TIMEZONE_ID,
           TD.TIMEZONE_OFFSET,
           TD.TIME_ZONE_DESC,
           TD.MODIFIED_DATE );

Final outcome would be like this.




Thoughts are welcome...

Tuesday, February 4, 2014

Http Session creation and Destroy events...

HttpSession is one of the commonly used way of identifying users across multiple requests between clients and servers. In order to provide various services such as authentication, authorization etc. for users and to store user information, logging and audit purposes, it is required to keep track of newly created sessions, active sessions and session destroy events. HttpSessionListener interface in servlet API provides methods to receive session events for its implementation classes published by the servlet container.

Lets look at a sample class 'WebSessionListener' which implements "HttpSessionListener" interface.

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class WebSessionListener implements HttpSessionListener {
    
    //Notification that a session was created.
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionCreatedEvent) {
    } 
    
    //Notification that a session is about to be invalidated.
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionDestroyedEvent) {
    }

}
To receive notification events, the implementation class must be configured, commonly referred as registered  in the deployment descriptor (web.xml)  of the web application as follows.


        
            com.araTechBlog.sample.listeners.WebSessionListener
        

Any change in active sessions, i.e. Session creation, Session Timeout etc. can be monitored and necessary actions can be performed depending on the requirements.  HttpSession Object can be accessed via session event object which represents event notifications for changes to sessions within a web application.

HttpSession httpSession = httpSessionEvent.getSession();

Both Session invalidation and session timeout(expiry) are notified via same sessionDestroyed event and can't be distinguished using this method.

If you use Spring Security, application context can be accessed using 'context.getBean()' method as follows inside the listner.

 WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
 CustomUserBean user= (CustomUserBean) context.getBean("customUser");

In a Spring environment. best practice is to use 'ApplicationListener' interface provided by the spring framework to receive session events.

In order to use ApplicationListner as a session event notifier,

You need to register 'HttpSessionEventPublisher' in the web.xml, which is the event publisher of the spring framework. If you look at the implementation of 'HttpSessionEventPublisher', you will see that it also implements the 'HttpSessionListener' and publish the session events to the Spring Root WebApplicationContext receieved from the servlet container.

  
       org.springframework.security.web.session.HttpSessionEventPublisher
  


Define you bean in the security.xml


Implement 'ApplicationListener' in your implementation.

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.web.session.HttpSessionCreatedEvent;
import org.springframework.security.web.session.HttpSessionDestroyedEvent;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger

public class WebSessionListener implements ApplicationListener<ApplicationEvent> {
    
    private static final Logger LOG = Logger.getLogger(WebSessionListener.class);

    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
       
        if(applicationEvent instanceof HttpSessionCreatedEvent){ //If event is a session created event

           HttpSession httpSession = httpSessionDestroyedEvent.getSession(); //get session object
           String sessionId = httpSession.getId(); //get session id
           ....
           persistSessionData(sessionId); //save session data to DB
           LOG.debug(" Session is invalidated |SESSION_ID :" + sessionId ); //log data
        
        }else if(applicationEvent instanceof HttpSessionDestroyedEvent){ //If event is a session destroy event
           ...
        }else{
           ...
        }
    }
}


Thoughts are welcome...

Thursday, July 4, 2013

Apache Derby Querying...

Intro...

Apache derby one of the popular relational databases purely written in Java. Derby supports running in both Embedded as well as client/server models. In the embedded mode derby runs within the JVM and provides only single connection for applications, while supporting multi-threded, multi-connection and multi-user modes. In server mode derby allows multiple connections depending on the threading and mode configurations. While providing fully transactional, secure and standard (SQL, JDBC API, and Java EE) database system, still developer community is able to maintain small foot print less than 3MB for base engine and database.  Features like stored procedures, triggers, views, referential integrity constraints, multi-user capable and cost-based query optimization also supported by Apache Derby.

1. Table creation

CREATE TABLE STUDENT (
  REG_ID      SMALLINT NOT NULL PRIMARY KEY
              GENERATED ALWAYS AS IDENTITY,
  FIRST_NAME  VARCHAR(20) NOT NULL,
  LAST_NAME   VARCHAR(20) NOT NULL,
  GENDER      CHAR(1) NOT NULL 
              CONSTRAINT GENDER_CONSTRAINT 
              CHECK (Gender IN ('M', 'F')) 
);

2. Insert Values into table

INSERT INTO STUDENT (FIRST_NAME, LAST_NAME, GENDER) 
              VALUES ('ARAVINDA', 'MADUSANKA', 'M');
Since REG_ID column is set as auto generated, we only have to set other column values as  mentioned above. 
Note that GENDER column can only have to values 'M' and 'F' according to the constrain added in the table
creation script. 

3. Simple select Operation

SELECT * FROM STUDENT WHERE FIRST_NAME='ARAVINDA' AND GENDER='M';
Note that column names are not case sensitive. Both 'first_name' and 'FIRST_NAME' are valid column names 
for querying.

4. Update a row.

UPDATE STUDENT SET LAST_NAME = 'NIMAL', LAST_NAME = 'SUJEEWA' WHERE REG_ID = 202;

5. Delete a row.

DELETE FROM STUDENT WHERE REG_ID = 202;

6. Delete multiple rows.

DELETE FROM STUDENT WHERE REG_ID IN (2,5,202);

7. Like operation to search for similar content.

SELECT * FROM STUDENT WHERE LAST_NAME LIKE '%aCbBbnN%'
This will search for LAST_NAME 's which contains 'aCbBbnN' string. That is 'xxxaCbBbnN', 'xxaCbBbnNxx' and
 'aCbBbnNxxx' will satisfy above condition.
 

8. Search for multiple values

SELECT * FROM STUDENT WHERE FIRST_NAME IN ('MIKE','TOM');
This will search for first names 'MIKE' and 'TOM'
 

9. Sorting the results

>> Ascending Order 
SELECT * FROM STUDENT ORDER BY FIRST_NAME;

>> Descending Order
SELECT * FROM STUDENT ORDER BY FIRST_NAME DESC;

>> Sort by FIRST_NAME and if two values are equal LAST_NAME Descending Order will use as the next ordering
SELECT * FROM STUDENT ORDER BY FIRST_NAME,LAST_NAME DESC;

10. Limit the result set (no of rows)

SELECT * FROM STUDENT FETCH FIRST 10 ROWS ONLY;

11. Setting starting index for select operation

SELECT * FROM STUDENT OFFSET 2 ROWS;

12. Handling pagination

You can combine above two operations to implement pagination.
SELECT * FROM STUDENT OFFSET N ROWS FETCH FIRST 10 ROWS ONLY;
Changing n value as 0,1,2.. will give you the paginated results with 10 rows in a page.

Thoughts are welcome....

Tuesday, October 9, 2012

For Better web experience - Full Screen API

Some web applications may require to hide the title bar and the address bar of the browser and show it as a desktop application in full screen view, so that users get the best experience in viewing. Conventional way of doing this is to open a new window using the "window.open" method as follows.

<script type="text/javascript">
 
   var newWindow;
   var url = "www.google.com";
   window.onload = function (url) {
   newWindow = window.open(url, 'name', 'fullscreen=yes,location=0,titlebar=0,top = 0, left = 0,   
                                width = '+screen.availWidth + ', height = ' +screen.availHeight + '');
           if (window.focus) {newWindow.focus()}
        }
 
</script>


Using this method you can customize the new window popup by setting the properties associated with the third parameter. Get More details here


However, due to security reasons modern browsers don't allow to hide title bar and address bar anymore.Therefore alternative is to use a java script library such as Full screen API which employes HTML5 capabilities of browsers without loosing the inbuilt security mechanisms.

Full screen API provides an easy way of presenting web content to users. So far this works for browsers Chrome 15+, Firefox 10+, Opera 5.1+ and still under development stage.

Pretty simple java script code as shown below can be used for enabling full screen in a full web page or in a single element such as in a image.


<button id="flScrBtn" onclick="requestFullScreen(document.documentElement);">Full Screen whole page</button>

<script type="text/javascript">

    function requestFullScreen(el) {
                rfs = el.requestFullScreen || el.webkitRequestFullScreen
                        || el.mozRequestFullScreen || el.msRequestFullScreen;
        if (typeof rfs != "undefined" && rfs) {
            rfs.call(el);
        } else if (typeof window.ActiveXObject != "undefined") {
            var wscript = new ActiveXObject("WScript.Shell");
            if (wscript != null) {
                wscript.SendKeys("{F11}");
            }
        }
    }

</script>
 









To fullscreenify a element, you need to pass the element to  "
requestFullScreen()" method.
 
To work this code properly it needs to associate with a event handler such as mouse click. This is to prevent using the full screen API  for malicious purposes.

References
1. https://developer.mozilla.org/en-US/docs/DOM/Using_full-screen_mode
2. https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html

3. https://stackoverflow.com/questions/1125084/how-to-make-in-javascript-full-screen-windows-stretching-all-over-the-screen

Handling POST request using akka-http in a akka-actor system

Akka-htp is a well known module for providing full server side as well as client side http stack currently supporting Scala and Java langua...