Monday, December 21, 2015

How to find user who ran DROP or DELETE statements on your SQL Server Objects

Problem
Someone has dropped a table from your database and you want to track who did it.  Or someone has deleted some data from a table, but no one will say who did.  In this tip, we will look at how you can use the transaction log to track down some of this information.
Solution
Here we will use the same undocumented function "fn_dblog" to find any unauthorized or unapproved deletes or table drops. This tip will help you track or find any unethical or an unwanted user who has dropped a table or deleted data from a table. I strongly suggest testing any undocumented functions in a lab environment first.
One way to find such users is with the help of the default trace, because the default trace captures and tracks database activity performed on your instance, but if you have a busy system the trace files may roll over far too fast and you may not be able to catch some of the changes in your database.  But these changes are also tracked in the transaction log file of the database and we will use this to find the users in question.

Finding a user who ran a DELETE statement

Step 1
Before moving ahead, we will create a database and a table on which I will delete some data. Run the below SQL code to create a database and table.
--Create DB.
USE [master];
GO
CREATE DATABASE ReadingDBLog;
GO
-- Create tables.
USE ReadingDBLog;
GO
CREATE TABLE [Location] (
    [Sr.No] INT IDENTITY,
    [Date] DATETIME DEFAULT GETDATE (),
    [City] CHAR (25) DEFAULT 'Bangalore');
Step 2
We have created a database named "ReadingDBLog" and a table 'Location' with three columns. Now we will insert a 100 rows into the table.
USE ReadingDBLog
GO
INSERT INTO Location DEFAULT VALUES ;
GO 100
Step 3
Now go ahead and delete some rows to check who has deleted your data.
USE ReadingDBLog
GO
DELETE Location WHERE [Sr.No]=10
GO
SELECT * FROM Location WHERE [Sr.No]=10
GO
Delete a row from the table'location'
You can see in the above screenshot that a row has been deleted from the table "Location". I also ran a SELECT statement to verify the data has been deleted.
Step 4
Now we have to search the transaction log file to find the info about the deleted rows. Run the below command to get info about all deleted transactions.
USE ReadingDBLog
GO
SELECT 
    [Transaction ID],
    Operation,
    Context,
    AllocUnitName
    
FROM 
    fn_dblog(NULL, NULL) 
WHERE 
    Operation = 'LOP_DELETE_ROWS'


Find all the deleted rows info from t-log file
All transactions which have executed a DELETE statement will display by running the above command and we can see this in the above screenshot. As we are searching for deleted data in table Location, we can see this in the last row. We can find the table name in the "AllocUnitName" column. The last row says a DELETE statement has been performed on a HEAP table 'dbo.Location' under transaction ID 0000:000004ce. Now capture the transaction ID from here for our next command.
Step 5
We found the transaction ID from the above command which we will use in the below command to get the transaction SID of the user who has deleted the data.
USE ReadingDBLog
GO
SELECT
    Operation,
    [Transaction ID],
    [Begin Time],
    [Transaction Name],
    [Transaction SID]
FROM
    fn_dblog(NULL, NULL)
WHERE
    [Transaction ID] = '0000:000004ce'
AND
    [Operation] = 'LOP_BEGIN_XACT'


Find the transaction SID of the user
Here, we can see the [Begin Time] of this transaction which will also help filter out the possibilities in finding the exact info like when the data was deleted and then you can filter on the base of begin time when that command was executed.
We can read the above output as "A DELETE statement began at 2013/10/14 12:55:17:630 under transaction ID 0000:000004ce by user transaction SID 0x0105000000000005150000009F11BA296C79F97398D0CF19E8030000.
Now our next step is to convert the transaction SID hexadecimal value into text to find the real name of the user.
Step 6
Now we will figure out who ran the DELETE command. We will copy the hexadecimal value from the transaction SID column for the DELETE transaction and then pass that value into the SUSER_SNAME () function.
USE MASTER
GO   
SELECT SUSER_SNAME(0x0105000000000005150000009F11BA296C79F97398D0CF19E8030000)


Find the login name with the help of transaction SID
Now we have found the user that did the delete.

Finding a user who ran a DROP statement

Step 1
Here I am going to drop table Location.
USE ReadingDBLog
GO
DROP TABLE Location


Drop a table
Step 2
Similarly if you drop any object or you perform anything operation in your database it will get logged in the transaction log file which will be visible by using this function fn_dblog.
Run the below script to display all logs which have been logged under DROPOBJ statement.
USE ReadingDBLog
GO
SELECT 
Operation,
[Transaction Id],
[Transaction SID],
[Transaction Name],
 [Begin Time],
   [SPID],
   Description
FROM fn_dblog (NULL, NULL)
WHERE [Transaction Name] = 'DROPOBJ'
GO


Finding a user trasaction SID who ran DROP statement for table location
Here we can find the transaction SID and all required info which we need to find the user.
Step 3
Now we can pass the transaction SID into system function SUSER_SNAME () to get the exact user name.
SELECT SUSER_SNAME(0x0105000000000005150000009F11BA296C79F97398D0CF19E8030000) 


Finding a user who ran DROP statement for table location

SQL Server DDL Triggers to Track All Database Changes

Problem
In a perfect world, only the DBA would have sa privileges, F5 would only ever be hit on purpose, every change would go through rigorous source control procedures, and we would have full backups of all databases every minute. Of course, in reality, we deal with much different circumstances, and we can find ourselves (or overhear someone else) saying, "Oops... how do I fix that?" One of the more common scenarios I've seen involves someone editing a stored procedure multiple times between backups or within some kind of cycle, and then wishing they had version (current - 1) available. It's not in the backup yet, so can't be restored; and the user, of course, has closed his or her window without saving.
Solution
There are a lot of solutions to this issue, of course. They include tightening down server access, adopting a reliable source control system, and implementing a rigorous and well-documented deployment process. These things do not happen overnight, so in the meantime, DDL Triggers can provide a short-term fix that is both easy to implement and simple to manage. The approach is to take a snapshot of the current objects in the database, and then log all DDL changes from that point forward. With a well-managed log, you could easily see the state of an object at any point in time (assuming, of course, the objects are not encrypted).
 
So where do we start? First, I like to keep housekeeping items (monitoring, administration etc.) in their own database. This allows me to query things centrally and also to control growth separately. For this task, let's use a database called AuditDB:
CREATE DATABASE AuditDB;
GO
To keep things relatively simple, let's assume we are only interested in actions taken on stored procedures - create, alter, drop. We have a set of stored procedures already, and they are in a given state. We will need to capture that state, in addition to any changes that are made to them from that point forward. This way, we will always be able to get back to any state, including the original state.
In addition to the data specific to the actions taken on stored procedures, we can also think of several other pieces of information we would want to store about each event. For example:
  • database name
  • schema / object name
  • login information
  • host name / IP address (useful with SQL auth)
So here is the definition for a table to capture these events and the surrounding information about them:
USE AuditDB;
GO


CREATE TABLE dbo.DDLEvents
(
    EventDate    DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    EventType    NVARCHAR(64),
    EventDDL     NVARCHAR(MAX),
    EventXML     XML,
    DatabaseName NVARCHAR(255),
    SchemaName   NVARCHAR(255),
    ObjectName   NVARCHAR(255),
    HostName     VARCHAR(64),
    IPAddress    VARCHAR(32),
    ProgramName  NVARCHAR(255),
    LoginName    NVARCHAR(255)
);
Yes, we could keep the table skinnier and use [object_id] instead of schema/object name, also protecting us from resolution problems due to renames. However, often stored procedures are dropped and re-created, in which case the system will generate a new [object_id]. I also prefer to use the database name to make ad hoc queries (and script automation) against specific databases easier. You can choose which metadata to rely on; personally, I'll trade the space for readability and scriptability.
Now that the table exists, we can easily grab a snapshot of our existing stored procedure definitions, leaving out some of the irrelevant auditing data, as follows (replacing 'my name' with whatever you want to display for the initial rows):
USE YourDatabase;
GO


INSERT AuditDB.dbo.DDLEvents
(
    EventType,
    EventDDL,
    DatabaseName,
    SchemaName,
    ObjectName,
    LoginName
)
SELECT
    'CREATE_PROCEDURE',
    OBJECT_DEFINITION([object_id]),
    DB_NAME(),
    OBJECT_SCHEMA_NAME([object_id]),
    OBJECT_NAME([object_id]),
    'my name'
FROM
    sys.procedures;
Now we're ready to start capturing actual changes to these procedures as they happen. You can create a DDL Trigger with the following code, that will record pertinent data to the above table when changes are made to stored procedures:
USE YourDatabase;
GO


CREATE TRIGGER DDLTrigger_Sample
    ON DATABASE
    FOR CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE
        @EventData XML = EVENTDATA();
 
    DECLARE 
        @ip VARCHAR(32) =
        (
            SELECT client_net_address
                FROM sys.dm_exec_connections
                WHERE session_id = @@SPID
        );
 
    INSERT AuditDB.dbo.DDLEvents
    (
        EventType,
        EventDDL,
        EventXML,
        DatabaseName,
        SchemaName,
        ObjectName,
        HostName,
        IPAddress,
        ProgramName,
        LoginName
    )
    SELECT
        @EventData.value('(/EVENT_INSTANCE/EventType)[1]',   'NVARCHAR(100)'), 
        @EventData.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'NVARCHAR(MAX)'),
        @EventData,
        DB_NAME(),
        @EventData.value('(/EVENT_INSTANCE/SchemaName)[1]',  'NVARCHAR(255)'), 
        @EventData.value('(/EVENT_INSTANCE/ObjectName)[1]',  'NVARCHAR(255)'),
        HOST_NAME(),
        @ip,
        PROGRAM_NAME(),
        SUSER_SNAME();
END
GO
Note that when you create a DDL Trigger, just like a DML Trigger, it is enabled and will start working immediately. To disable it, you can run the following code:
USE YourDatabase;
GO


DISABLE TRIGGER [DDLTrigger_Sample] ON DATABASE;
And then to re-enable:
USE YourDatabase;
GO


ENABLE TRIGGER [DDLTrigger_Sample] ON DATABASE;
So now you can test the auditing capabilities by altering an existing procedure. Right-click a procedure in Object Explorer and choose Modify. Add the following line somewhere in the body:
-- testing audit
Then you can run a query against the DDLEvents table:
SELECT *
    FROM AuditDB.dbo.DDLEvents
    WHERE EventType = 'ALTER_PROCEDURE';
Assuming your system is relatively quiet, all you should see is the change above. Now to go one step further, you can examine the differences between the initial object and its most recent state using a query like this:
;WITH [Events] AS
(
    SELECT
        EventDate,
        DatabaseName,
        SchemaName,
        ObjectName,
        EventDDL,
        rnLatest = ROW_NUMBER() OVER 
        (
            PARTITION BY DatabaseName, SchemaName, ObjectName
            ORDER BY     EventDate DESC
        ),
        rnEarliest = ROW_NUMBER() OVER
        (
            PARTITION BY DatabaseName, SchemaName, ObjectName
            ORDER BY     EventDate
        )        
    FROM
        AuditDB.dbo.DDLEvents
)
SELECT
    Original.DatabaseName,
    Original.SchemaName,
    Original.ObjectName,
    OriginalCode = Original.EventDDL,
    NewestCode   = COALESCE(Newest.EventDDL, ''),
    LastModified = COALESCE(Newest.EventDate, Original.EventDate)
FROM
    [Events] AS Original
LEFT OUTER JOIN
    [Events] AS Newest
    ON  Original.DatabaseName = Newest.DatabaseName
    AND Original.SchemaName   = Newest.SchemaName
    AND Original.ObjectName   = Newest.ObjectName
    AND Newest.rnEarliest = Original.rnLatest
    AND Newest.rnLatest = Original.rnEarliest
    AND Newest.rnEarliest > 1
WHERE
    Original.rnEarliest = 1;
If you are tracking down a specific object or an object in a specific schema, you could put additional WHERE clauses against Original.ObjectName or Original.SchemaName. From here, you can take the values for "OriginalCode" and "NewestCode" and put them through your favorite diff tool to see what changes there have been. And you can also change the query slightly to retrieve the latest version of any procedure, and the version that preceded it - I'll leave that as an exercise for the reader.
What the above does not capture are other peripheral changes that can happen to a stored procedure. For example, what about moving a procedure to a different schema? You can change the DDL Trigger above in the following way to capture the ALTER_SCHEMA event:
USE YourDatabase;
GO


ALTER TRIGGER DDLTrigger_Sample
    ON DATABASE
    FOR CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE,
        ALTER_SCHEMA
AS
BEGIN
    -- ...
And how about rename? Unfortunately in SQL Server 2005, DDL Triggers were unable to observe calls to sp_rename (or manual renames through Management Studio). In SQL Server 2008 and above, however, a rename can be captured with the aptly-named RENAME event:
USE YourDatabase;
GO


ALTER TRIGGER DDLTrigger_Sample
    ON DATABASE
    FOR CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE,
        ALTER_SCHEMA, RENAME
AS
BEGIN
    -- ...
(In a future tip, I'll demonstrate how to restrict these additional auditing rows to specific objects or object types, so that you're not capturing all kinds of irrelevant information about changes to objects other than stored procedures.)
Some other considerations:
  • You may want to put in a cleanup routine that gets rid of "noise" more than <n> days old (but still keeping the set of objects that are important to you).
  • To validate that your auditing process is capturing all changes, you can check modify_date in sys.procedures. Of course this only works for procedures that haven't been dropped - only if they have been created, modified, renamed, or transfered to a different schema.
  • Security might be an issue, depending on what you want to accomplish. Allow me to elaborate: DDL Triggers will not be transparent to users - first of all, they can see them in the Object Explorer tree, so it won't be a big secret that they are there and operational. They also appear in execution plans; if users have this option enabled when they create or modify objects in Management Studio, they will see the query plan for statements such as INSERT AuditDB.dbo.DDLEvents.
    If you want to hide the definition of the DDL Trigger, you can encrypt it as follows:
    USE YourDatabase;
    GO
    
    
    ALTER TRIGGER DDLTrigger_Sample
        ON DATABASE
        WITH ENCRYPTION
        FOR -- ...
    
    This way, when users want to see what the trigger is doing, they will right-click to generate a script, but the following is what will happen:
    TITLE: Microsoft SQL Server Management Studio
    ------------------------------
    Script failed for DatabaseDdlTrigger 'DDLTrigger_Sample'.
    Property TextHeader is not available for DatabaseDdlTrigger
    '[DDLTrigger_Sample]'. This property may not exist for this
    object, or may not be retrievable due to insufficient access
    rights.  The text is encrypted.
    ...
    
    But users with sufficient privileges can still disable the trigger, as described above. And you can't even capture this event, much less prevent it (which DDL Triggers are sometimes used for). For more information, see these Connect items:
    So, assuming SQL Server 2008 or above, you could use an audit specification to capture DDL events as a backup (or instead). But, given all of this, if you have to go to these lengths to prevent people from circumventing your auditing capabilites, then maybe your problems are larger and not all that technical. I suspect that in most reasonable environments, you'll sleep fine at night simply locking down the audit table.

I hope this provides a decent starting point to protect your environment(s) with DDL Triggers. However, given the manual aspect of this approach as well as its limitations, it will likely be best to consider this a short-term plan, and look into more robust source control and recovery techniques in the longer term.


Source : www.mssqltips.com

Tuesday, June 2, 2015

Android - JSON Parser

JSON stands for JavaScript Object Notation.It is an independent data exchange format and is the best alternative for XML. This chapter explains how to parse the JSON file and extract necessary information from it.
Android provides four differnet classes to manipulate JSON data. These classes areJSONArray,JSONObject,JSONStringer and JSONTokenizer.
The first step is to identify the fields in the JSON data in which you are interested in. For example. In the JSON given below we interested in getting temperature only.
{
"sys":
   {
      "country":"GB",
      "sunrise":1381107633,
      "sunset":1381149604
   },
"weather":[
   {
      "id":711,
      "main":"Smoke",
      "description":"smoke",
      "icon":"50n"
   }
],
"main":
   {
      "temp":304.15,
      "pressure":1009,
   }
}

JSON - Elements

An JSON file consist of many components. Here is the table defining the compoents of an JSON file and their description −
Sr.NoComponent & description
1Array([)
In a JSON file , square bracket ([) represents a JSON array
2Objects({)
In a JSON file, curly bracket ({) represents a JSON object
3Key
A JSON object contains a key that is just a string. Pairs of key/value make up a JSON object
4Value
Each key has a value that could be string , integer or double e.t.c

JSON - Parsing

For parsing a JSON object, we will create an object of class JSONObject and specify a string containing JSON data to it. Its syntax is −
String in;
JSONObject reader = new JSONObject(in);
The last step is to parse the JSON. An JSON file consist of different object with different key/value pair e.t.c. So JSONObject has a seperate function for parsing each of the component of JSON file. Its syntax is given below −
JSONObject sys  = reader.getJSONObject("sys");
country = sys.getString("country");
   
JSONObject main  = reader.getJSONObject("main");
temperature = main.getString("temp");
The method getJSONObject returns the JSON object. The method getString returns the string value of the specified key.
Apart from the these methods, there are other methods provided by this class for better parsing JSON files. These methods are listed below −
Sr.NoMethod & description
1get(String name)
This method just Returns the value but in the form of Object type
2getBoolean(String name)
This method returns the boolean value specified by the key
3getDouble(String name)
This method returns the double value specified by the key
4getInt(String name)
This method returns the integer value specified by the key
5getLong(String name)
This method returns the long value specified by the key
6length()
This method returns the number of name/value mappings in this object..
7names()
This method returns an array containing the string names in this object.

Example

Here is an example demonstrating the use of JSONObject class. It creates a basic Weather application that allows you to parse JSON from google weather api and show the result.
To experiment with this example, you can run this on an actual device or in an emulator.
StepsDescription
1You will use Android studio to create an Android application. While creating this project, make sure you Target SDK and Compile With at the latest version of Android SDK to use higher levels of APIs.
2Modify src/MainActivity.java file to add necessary code.
3Modify the res/layout/activity_main to add respective XML components
4Modify the res/values/string.xml to add necessary string components
5Create a new java file under src/HandleJSON.java to fetch and parse XML data
6Modify AndroidManifest.xml to add necessary internet permission
7Run the application and choose a running android device and install the application on it and verify the results
Following is the content of the modifed main activity file src/MainActivity.java.
package com.example.arunkumar.weatherapplication;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;

import android.graphics.Typeface;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;

import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
com.example.arunkumar.weatherapplication

public class MainActivity extends ActionBarActivity {
   EditText ed1,ed2,ed3,ed4,ed5;
   private String url1 = "http://api.openweathermap.org/data/2.5/weather?q=";
   private String url2 = "&mode=xml";
   private HandleXML obj;
   Button b1;
   
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      b1=(Button)findViewById(R.id.button);
      
      ed1=(EditText)findViewById(R.id.editText);
      ed2=(EditText)findViewById(R.id.editText2);
      ed3=(EditText)findViewById(R.id.editText3);
      ed4=(EditText)findViewById(R.id.editText4);
      ed5=(EditText)findViewById(R.id.editText5);
      
      b1.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            String url = ed1.getText().toString();
            String finalUrl = url1 + url + url2;
            
            ed2.setText(finalUrl);
            obj = new HandleXML(finalUrl);
            obj.fetchXML();
            
            while(obj.parsingComplete);
            ed2.setText(obj.getCountry());
            ed3.setText(obj.getTemperature());
            ed4.setText(obj.getHumidity());
            ed5.setText(obj.getPressure());
         }
      });
   }
   
   @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       // Inflate the menu; this adds items to the action bar if it is present.
       getMenuInflater().inflate(R.menu.menu_main, menu);
       return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       // Handle action bar item clicks here. The action bar will
       // automatically handle clicks on the Home/Up button, so long
       // as you specify a parent activity in AndroidManifest.xml.
       
       int id = item.getItemId();
       
       //noinspection SimplifiableIfStatement
       if (id == R.id.action_settings) {
          return true;
       }
       return super.onOptionsItemSelected(item);
    }
}
Following is the content of src/HandleXML.java.
package com.example.arunkumar.weatherapplication;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by arunkumar on 24/05/2015.
 */
public class HandleXML {
   private String country = "county";
   private String temperature = "temperature";
   private String humidity = "humidity";
   private String pressure = "pressure";
   private String urlString = null;
   private XmlPullParserFactory xmlFactoryObject;
   
   public volatile boolean parsingComplete = true;
   public HandleXML(String url){
      this.urlString = url;
   }
   
   public String getCountry(){
      return country;
   }
   
   public String getTemperature(){
      return temperature;
   }
   
   public String getHumidity(){
      return humidity;
   }
   
   public String getPressure(){
      return pressure;
   }
   
   public void parseXMLAndStoreIt(XmlPullParser myParser) {
      int event;
      String text=null;
      
      try {
         event = myParser.getEventType();
         
         while (event != XmlPullParser.END_DOCUMENT) {
            String name=myParser.getName();
            
            switch (event){
               case XmlPullParser.START_TAG:
               break;
               
               case XmlPullParser.TEXT:
               text = myParser.getText();
               break;
               
               case XmlPullParser.END_TAG:
               if(name.equals("country")){
                  country = text;
               }
               
               else if(name.equals("humidity")){
                  humidity = myParser.getAttributeValue(null,"value");
               }
               
               else if(name.equals("pressure")){
                  pressure = myParser.getAttributeValue(null,"value");
               }
               
               else if(name.equals("temperature")){
                  temperature = myParser.getAttributeValue(null,"value");
               }
               
               else{
               }
               
               break;
            }
            event = myParser.next();
         }
         
         parsingComplete = false;
      }
      
      catch (Exception e) {
         e.printStackTrace();
      }
   }
   
   public void fetchXML(){
      Thread thread = new Thread(new Runnable(){
         @Override
         public void run() {
            try {
               URL url = new URL(urlString);
               HttpURLConnection conn = (HttpURLConnection)url.openConnection();
               
               conn.setReadTimeout(10000 /* milliseconds */);
               conn.setConnectTimeout(15000 /* milliseconds */);
               conn.setRequestMethod("GET");
               conn.setDoInput(true);
               conn.connect();
               
               InputStream stream = conn.getInputStream();
               xmlFactoryObject = XmlPullParserFactory.newInstance();
               XmlPullParser myparser = xmlFactoryObject.newPullParser();
               
               myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
               myparser.setInput(stream, null);
               
               parseXMLAndStoreIt(myparser);
               stream.close();
            }
            catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
      thread.start();
   }
}
Following is the modified content of the xml res/layout/activity_main.xml.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
   android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
   
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="XML Fetch"
      android:id="@+id/textView"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:textSize="30dp" />
      
   <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Tutorials Point"
      android:id="@+id/textView2"
      android:layout_below="@+id/textView"
      android:layout_centerHorizontal="true"
      android:textSize="35dp"
      android:textColor="#ff16ff01" />
      
   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText"
      android:hint="Location"
      android:layout_below="@+id/textView2"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_marginTop="61dp"
      android:layout_alignParentRight="true"
      android:layout_alignParentEnd="true" />
      
   <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Weather "
      android:id="@+id/button"
      android:layout_below="@+id/editText"
      android:layout_centerHorizontal="true" />
      
   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText2"
      android:layout_below="@+id/button"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_alignRight="@+id/editText"
      android:layout_alignEnd="@+id/editText"
      android:text="Currency" />
      
   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText3"
      android:layout_below="@+id/editText2"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_alignParentRight="true"
      android:layout_alignParentEnd="true"
      android:text="Temp" />
      
   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText4"
      android:layout_below="@+id/editText3"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_alignRight="@+id/editText3"
      android:layout_alignEnd="@+id/editText3"
      android:text="Humidity" />
      
   <EditText
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/editText5"
      android:layout_below="@+id/editText4"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_alignParentRight="true"
      android:layout_alignParentEnd="true"
      android:text="Pressure" />
      
</RelativeLayout>
Following is the content of AndroidManifest.xml file.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.arunkumar.weatherapplication" >
   <uses-permission android:name="android.permission.INTERNET"/>
   <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme" >
      
      <activity
         android:name=".MainActivity"
         android:label="@string/app_name" >
         
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
      
      </activity>
         
   </application>
</manifest>
Let's try to run our application we just modified. I assume you had created your AVD while doing environment setup. To run the app from Android studio, open one of your project's activity files and click Run .Eclipse Run Icon icon from the toolbar. Android studio installs the app on your AVD and starts it and if everything is fine with your setup and application.
Now when you press the weather button, the application will contact the Google Weather API and will request for your necessary JSON location file and will parse it. In case of oddanchatram the file would be returned −
Note that this temperature is in kelvin, so if you want to convert it into more understandable format , you have to convert it into Celcius.