diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py
new file mode 100644
index 0000000..a6b831e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py
@@ -0,0 +1,759 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Foreign Data Wrapper Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from functools import wraps
+
+
+class ForeignDataWrapperModule(CollectionNodeModule):
+    """
+    class ForeignDataWrapperModule(CollectionNodeModule)
+
+        A module class for foreign data wrapper node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Foreign data wrapper module and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * script_load()
+      - Load the module script for foreign data wrapper, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'foreign_data_wrapper'
+    COLLECTION_LABEL = gettext("Foreign Data Wrappers")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the Foreign data wrapper module and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+
+        self.min_ver = None
+        self.max_ver = None
+
+        super(ForeignDataWrapperModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did):
+        """
+        Method is used to generate the browser collection node
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database Id
+        """
+        yield self.generate_browser_collection_node(did)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for foreign data wrapper, when any of the database node is initialized.
+
+        Returns: node type of the server module.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = ForeignDataWrapperModule(__name__)
+
+
+class ForeignDataWrapperView(PGChildNodeView):
+    """
+    class ForeignDataWrapperView(PGChildNodeView)
+
+        A view class for foreign data wrapper node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like updating foreign data wrapper
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the ForeignDataWrapperView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list(gid, sid, did)
+      - This function is used to list all the foreign data wrapper nodes within that collection.
+
+    * nodes(gid, sid, did)
+      - This function will used to create all the child node within that collection.
+        Here it will create all the foreign data wrapper node.
+
+    * properties(gid, sid, did, fid)
+      - This function will show the properties of the selected foreign data wrapper node
+
+    * tokenizeOptions(option_value)
+      - This function will tokenize the string stored in database
+
+    * create(gid, sid, did)
+      - This function will create the new foreign data wrapper node
+
+    * delete(gid, sid, did, fid)
+      - This function will delete the selected foreign data wrapper node
+
+    * update(gid, sid, did, fid)
+      - This function will update the data for the selected foreign data wrapper node
+
+    * msql(gid, sid, did, fid)
+      - This function is used to return modified SQL for the selected foreign data wrapper node
+
+    * get_sql(data, fid)
+      - This function will generate sql from model data
+
+    * get_validators(gid, sid, did)
+      - This function returns the validators for the selected foreign data wrapper node
+
+    * get_handlers(gid, sid, did)
+      - This function returns the handlers for the selected foreign data wrapper node
+
+    * sql(gid, sid, did, fid):
+      - This function will generate sql to show it in sql pane for the selected foreign data wrapper node.
+
+    * dependents(gid, sid, did, fid):
+      - This function get the dependents and return ajax response for the foreign data wrapper node.
+
+    * dependencies(self, gid, sid, did, fid):
+      - This function get the dependencies and return ajax response for the foreign data wrapper node.
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'fid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}],
+        'get_handlers': [{}, {'get': 'get_handlers'}],
+        'get_validators': [{}, {'get': 'get_validators'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "foreign_data_wrappers/js/foreign_data_wrappers.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90300:
+                self.template_path = 'foreign_data_wrappers/sql/9.3_plus'
+            else:
+                self.template_path = 'foreign_data_wrappers/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did):
+        """
+        This function is used to list all the foreign data wrapper nodes within that collection.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in res['rows']:
+            if row['fdwoptions'] is not None:
+                row['fdwoptions'] = self.tokenize_options(row['fdwoptions'])
+
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+        """
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['fdwoid'],
+                        did,
+                        row['name'],
+                        icon="icon-foreign_data_wrapper"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenize_options(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+
+        Args:
+            option_value: key value option/value pair read from database
+        """
+        if option_value is not None:
+            option_str = option_value.split(',')
+            fdw_options = []
+            for fdw_option in option_str:
+                k, v = fdw_option.split('=', 1)
+                fdw_options.append({'fdwoption': k, 'fdwvalue': v})
+            return fdw_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid):
+        """
+        This function will show the properties of the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fdwoptions'] is not None:
+            res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fid=fid)
+        status, fdw_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fdw_acl_res)
+
+        for row in fdw_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did):
+        """
+        This function will create the foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+        """
+        required_args = [
+            'name'
+        ]
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        try:
+
+            if 'fdwacl' in data:
+                data['fdwacl'] = parse_priv_to_db(data['fdwacl'], ['U'])
+
+            new_list = []
+
+            # Allow user to set the blank value in fdwvalue field in option model
+            if 'fdwoptions' in data:
+                for item in data['fdwoptions']:
+                    new_dict = {}
+                    if item['fdwoption']:
+                        if 'fdwvalue' in item and item['fdwvalue'] and item['fdwvalue'] != '':
+                            new_dict.update(item);
+                        else:
+                            new_dict.update({'fdwoption': item['fdwoption'], 'fdwvalue': ''})
+
+                    new_list.append(new_dict)
+
+                data['fdwoptions'] = new_list
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fname=data['name'], conn=self.conn)
+
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                return jsonify(
+                    node=self.blueprint.generate_browser_node(
+                        row['fdwoid'],
+                        did,
+                        row['name'],
+                        icon='icon-foreign_data_wrapper'
+                    )
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid):
+        """
+        This function will update the data for the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.get_sql(gid, sid, data, did, fid)
+        try:
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Foreign Data Wrapper updated",
+                    data={
+                        'id':  fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid):
+        """
+        This function will delete the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign data wrapper from fid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fid=fid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+            # drop foreign data wrapper node
+            sql = render_template("/".join([self.template_path, 'delete.sql']), name=name, cascade=cascade,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Foreign Data Wrapper dropped"),
+                data={
+                    'id': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid=None):
+        """
+        This function is used to return modified SQL for the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.get_sql(gid, sid, data, did, fid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(data=sql,status=200)
+        else:
+            return make_json_response(data='-- Modified SQL --',status=200)
+
+    def get_sql(self, gid, sid, data, did, fid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            data: Contains the data of the selected foreign data wrapper node
+            fid: foreign data wrapper ID
+        """
+        required_args = [
+            'name'
+        ]
+        try:
+            if fid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['fdwoptions'] is not None:
+                    res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+                for key in ['fdwacl']:
+                    if key in data and data[key] is not None:
+                        if 'added' in data[key]:
+                          data[key]['added'] = parse_priv_to_db(data[key]['added'], ['U'])
+                        if 'changed' in data[key]:
+                          data[key]['changed'] = parse_priv_to_db(data[key]['changed'], ['U'])
+                        if 'deleted' in data[key]:
+                          data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'], ['U'])
+
+                old_data = res['rows'][0]
+                for arg in required_args:
+                    if arg not in data:
+                        data[arg] = old_data[arg]
+
+                new_list_add = []
+                new_list_change = []
+
+                # Allow user to set the blank value in fdwvalue field in option model
+                if 'fdwoptions' in data and 'added' in data['fdwoptions']:
+                    for item in data['fdwoptions']['added']:
+                        new_dict_add = {}
+                        if item['fdwoption']:
+                            if 'fdwvalue' in item and item['fdwvalue'] and item['fdwvalue'] != '':
+                                new_dict_add.update(item);
+                            else:
+                                new_dict_add.update({'fdwoption': item['fdwoption'], 'fdwvalue': ''})
+
+                        new_list_add.append(new_dict_add)
+
+                    data['fdwoptions']['added'] = new_list_add
+
+                # Allow user to set the blank value in fdwvalue field in option model
+                if 'fdwoptions' in data and 'changed' in data['fdwoptions']:
+                    for item in data['fdwoptions']['changed']:
+                        new_dict_change = {}
+                        if item['fdwoption']:
+                            if 'fdwvalue' in item and item['fdwvalue'] and item['fdwvalue'] != '':
+                                new_dict_change.update(item);
+                            else:
+                                new_dict_change.update({'fdwoption': item['fdwoption'], 'fdwvalue': ''})
+
+                        new_list_change.append(new_dict_change)
+
+                    data['fdwoptions']['changed'] = new_list_change
+
+                sql = render_template("/".join([self.template_path, 'update.sql']), data=data, o_data=old_data,
+                                      conn=self.conn)
+            else:
+                for key in ['fdwacl']:
+                    if key in data and data[key] is not None:
+                        data[key] = parse_priv_to_db(data[key], ['U'])
+
+                new_list = []
+
+                # Allow user to set the blank value in fdwvalue field in option model
+                if 'fdwoptions' in data:
+                    for item in data['fdwoptions']:
+                        new_dict = {}
+                        if item['fdwoption']:
+                            if 'fdwvalue' in item and item['fdwvalue'] and item['fdwvalue'] != '':
+                                new_dict.update(item);
+                            else:
+                                new_dict.update({'fdwoption': item['fdwoption'], 'fdwvalue': ''})
+
+                        new_list.append(new_dict)
+
+                    data['fdwoptions'] = new_list
+
+                sql = render_template("/".join([self.template_path, 'create.sql']), data=data, conn=self.conn)
+                sql += "\n"
+            return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid):
+        """
+        This function will generate sql to show it in sql pane for the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+        """
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fdwoptions'] is not None:
+            res['rows'][0]['fdwoptions'] = self.tokenize_options(res['rows'][0]['fdwoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fid=fid)
+        status, fdw_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fdw_acl_res)
+
+        for row in fdw_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        # To format privileges
+        if 'fdwacl' in res['rows'][0]:
+            res['rows'][0]['fdwacl'] = parse_priv_to_db(res['rows'][0]['fdwacl'], ['U'])
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], conn=self.conn)
+        sql += "\n"
+
+        sql_header = """-- Foreign Data Wrapper: {0}
+
+-- DROP FOREIGN DATA WRAPPER {0}
+
+""".format(res['rows'][0]['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def get_validators(self, gid, sid, did):
+        """
+        This function returns the validators for the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            sql = render_template("/".join([self.template_path, 'validators.sql']), conn=self.conn)
+            status, r_set = self.conn.execute_2darray(sql)
+
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                res.append({'label': row['fdwvalue'], 'value': row['fdwvalue']})
+
+            return make_json_response( data=res, status=200)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def get_handlers(self, gid, sid, did):
+        """
+        This function returns the handlers for the selected foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+        """
+        res = [{'label': '', 'value': ''}]
+        try:
+            sql = render_template("/".join([self.template_path, 'handlers.sql']), conn=self.conn)
+            status, r_set = self.conn.execute_2darray(sql)
+
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                res.append({'label': row['fdwhan'], 'value': row['fdwhan']})
+
+            return make_json_response(
+                   data=res,
+                   status=200
+                   )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def dependents(self, gid, sid, did, fid):
+        """
+        This function get the dependents and return ajax response
+        for the foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        dependents_result = self.get_dependents(self.conn, fid)
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, fid):
+        """
+        This function get the dependencies and return ajax response
+        for the foreign data wrapper node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign Data Wrapper ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, fid)
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+ForeignDataWrapperView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py
new file mode 100644
index 0000000..163d211
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py
@@ -0,0 +1,754 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements Foreign Server Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from functools import wraps
+
+
+class ForeignServerModule(CollectionNodeModule):
+    """
+    class ForeignServerModule(CollectionNodeModule)
+
+        A module class for foreign server node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Foreign server module and it's base module.
+
+    * get_nodes(gid, sid, did)
+      - Method is used to generate the browser collection node.
+
+    * script_load(self)
+      - Load the module script for foreign server, when any of the database node is
+        initialized.
+    """
+
+    NODE_TYPE = 'foreign_server'
+    COLLECTION_LABEL = gettext("Foreign Servers")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the Foreign server module and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+
+        self.min_ver = None
+        self.max_ver = None
+
+        super(ForeignServerModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, fid):
+        """
+        Method is used to generate the browser collection node
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+        yield self.generate_browser_collection_node(fid)
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for foreign server, when any of the foreign data wrapper node is initialized.
+
+        Returns: node type of the server module.
+        """
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = ForeignServerModule(__name__)
+
+
+class ForeignServerView(PGChildNodeView):
+    """
+    class ForeignServerView(PGChildNodeView)
+
+        A view class for foreign server node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like updating foreign server
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the ForeignServerView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list(gid, sid, did, fid)
+      - This function is used to list all the foreign server nodes within that collection.
+
+    * nodes(gid, sid, did, fid)
+      - This function will used to create all the child node within that collection.
+        Here it will create all the foreign server node.
+
+    * properties(gid, sid, did, fid, fsid)
+      - This function will show the properties of the selected foreign server node
+
+    * tokenizeOptions(option_value)
+      - This function will tokenize the string stored in database
+
+    * update(gid, sid, did, fid, fsid)
+      - This function will update the data for the selected foreign server node
+
+    * create(gid, sid, did, fid)
+      - This function will create the new foreign server node
+
+    * delete(gid, sid, did, fid, fsid)
+      - This function will delete the selected foreign server node
+
+    * msql(gid, sid, did, fid, fsid)
+      - This function is used to return modified SQL for the selected foreign server node
+
+    * get_sql(data, fid, fsid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, fid, fsid):
+      - This function will generate sql to show it in sql pane for the selected foreign server node.
+
+    * dependents(gid, sid, did, fid, fsid):
+      - This function get the dependents and return ajax response for the foreign server node.
+
+    * dependencies(self, gid, sid, did, fid, fsid):
+      - This function get the dependencies and return ajax response for the foreign server node.
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'fid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'fsid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "foreign_servers/js/foreign_servers.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90300:
+                self.template_path = 'foreign_servers/sql/9.3_plus'
+            else:
+                self.template_path = 'foreign_servers/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, fid):
+        """
+        This function is used to list all the foreign server nodes within that collection.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, fid):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+        """
+
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fid=fid, conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['fsrvid'],
+                        fid,
+                        row['name'],
+                        icon="icon-foreign_server"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenizeOptions(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+
+        Args:
+            option_value: key value option/value pair read from database
+        """
+
+        if option_value is not None:
+            option_str = option_value.split(',')
+            fs_rv_options = []
+            for fs_rv_option in option_str:
+                k, v = fs_rv_option.split('=', 1)
+                fs_rv_options.append({'fsrvoption': k, 'fsrvvalue': v})
+            return fs_rv_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid, fsid):
+        """
+        This function will show the properties of the selected foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fsrvoptions'] is not None:
+            res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fsid=fsid)
+        status, fs_rv_acl_res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=fs_rv_acl_res)
+
+        for row in fs_rv_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, fid):
+        """
+        This function will create the foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+        """
+
+        required_args = [
+            'name'
+        ]
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+        try:
+            if 'fsrvacl' in data:
+                data['fsrvacl'] = parse_priv_to_db(data['fsrvacl'], ['U'])
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            new_list = []
+
+            if 'fsrvoptions' in data:
+                for item in data['fsrvoptions']:
+                    new_dict = {}
+                    if item['fsrvoption']:
+                        if 'fsrvvalue' in item and item['fsrvvalue'] and item['fsrvvalue'] != '':
+                            new_dict.update(item);
+                        else:
+                            new_dict.update({'fsrvoption': item['fsrvoption'], 'fsrvvalue': ''})
+
+                    new_list.append(new_dict)
+
+                data['fsrvoptions'] = new_list
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    r_set['rows'][0]['fsrvid'],
+                    fid,
+                    r_set['rows'][0]['name'],
+                    icon="icon-foreign_server"
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid, fsid):
+        """
+        This function will update the data for the selected foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+        """
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.get_sql(gid, sid, data, did, fid, fsid)
+        try:
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="Foreign server updated",
+                    data={
+                        'id':  fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid, fsid):
+        """
+        This function will delete the selected foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+        """
+
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign data wrapper from fid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fsid=fsid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+            # drop foreign server
+            sql = render_template("/".join([self.template_path, 'delete.sql']), name=name, cascade=cascade,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Foreign Server dropped"),
+                data={
+                    'id': fsid,
+                    'fid': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid, fsid=None):
+        """
+        This function is used to return modified SQL for the selected foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+        """
+
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.get_sql(gid, sid, data, did, fid, fsid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data='-- Modified SQL --',
+                    status=200
+                    )
+
+    def get_sql(self, gid, sid, data, did, fid, fsid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            data: Contains the data of the selected foreign server node
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+        """
+
+        required_args = [
+            'name'
+        ]
+        try:
+            if fsid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['fsrvoptions'] is not None:
+                    res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+                for key in ['fsrvacl']:
+                    if key in data and data[key] is not None:
+                        if 'added' in data[key]:
+                          data[key]['added'] = parse_priv_to_db(data[key]['added'], ['U'])
+                        if 'changed' in data[key]:
+                          data[key]['changed'] = parse_priv_to_db(data[key]['changed'], ['U'])
+                        if 'deleted' in data[key]:
+                          data[key]['deleted'] = parse_priv_to_db(data[key]['deleted'], ['U'])
+
+                old_data = res['rows'][0]
+                for arg in required_args:
+                    if arg not in data:
+                        data[arg] = old_data[arg]
+
+                new_list_add = []
+                new_list_change = []
+
+                # Allow user to set the blank value in fsrvvalue field in option model
+                if 'fsrvoptions' in data and 'added' in data['fsrvoptions']:
+                    for item in data['fsrvoptions']['added']:
+                        new_dict_add = {}
+                        if item['fsrvoption']:
+                            if 'fsrvvalue' in item and item['fsrvvalue'] and item['fsrvvalue'] != '':
+                                new_dict_add.update(item);
+                            else:
+                                new_dict_add.update({'fsrvoption': item['fsrvoption'], 'fsrvvalue': ''})
+
+                        new_list_add.append(new_dict_add)
+
+                    data['fsrvoptions']['added'] = new_list_add
+
+                # Allow user to set the blank value in fsrvvalue field in option model
+                if 'fsrvoptions' in data and 'changed' in data['fsrvoptions']:
+                    for item in data['fsrvoptions']['changed']:
+                        new_dict_change = {}
+                        if item['fsrvoption']:
+                            if 'fsrvvalue' in item and item['fsrvvalue'] and item['fsrvvalue'] != '':
+                                new_dict_change.update(item);
+                            else:
+                                new_dict_change.update({'fsrvoption': item['fsrvoption'], 'fsrvvalue': ''})
+
+                        new_list_change.append(new_dict_change)
+
+                    data['fsrvoptions']['changed'] = new_list_change
+
+                sql = render_template("/".join([self.template_path, 'update.sql']), data=data, o_data=old_data,
+                                      conn=self.conn)
+            else:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                fdw_data = res['rows'][0]
+
+                for key in ['fsrvacl']:
+                    if key in data and data[key] is not None:
+                        data[key] = parse_priv_to_db(data[key], ['U'])
+
+                new_list = []
+
+                if 'fsrvoptions' in data:
+                    for item in data['fsrvoptions']:
+                        new_dict = {}
+                        if item['fsrvoption']:
+                            if 'fsrvvalue' in item and item['fsrvvalue'] and item['fsrvvalue'] != '':
+                                new_dict.update(item);
+                            else:
+                                new_dict.update({'fsrvoption': item['fsrvoption'], 'fsrvvalue': ''})
+
+                        new_list.append(new_dict)
+
+                    data['fsrvoptions'] = new_list
+
+                sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                      conn=self.conn)
+                sql += "\n"
+            return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid, fsid):
+        """
+        This function will generate sql to show it in sql pane for the selected foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['fsrvoptions'] is not None:
+            res['rows'][0]['fsrvoptions'] = self.tokenizeOptions(res['rows'][0]['fsrvoptions'])
+
+        sql = render_template("/".join([self.template_path, 'acl.sql']), fsid=fsid)
+        status, fs_rv_acl_res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=fs_rv_acl_res)
+
+        for row in fs_rv_acl_res['rows']:
+            privilege = parse_priv_from_db(row)
+            if row['deftype'] in res['rows'][0]:
+                res['rows'][0][row['deftype']].append(privilege)
+            else:
+                res['rows'][0][row['deftype']] = [privilege]
+
+        # To format privileges
+        if 'fsrvacl' in res['rows'][0]:
+            res['rows'][0]['fsrvacl'] = parse_priv_to_db(res['rows'][0]['fsrvacl'], ['U'])
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fdwid=fid, conn=self.conn)
+        status, res1 = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res1)
+
+        fdw_data = res1['rows'][0]
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], fdwdata=fdw_data,
+                              conn=self.conn)
+        sql += "\n"
+
+        sql_header = """-- Foreign Server: {0}
+
+-- DROP SERVER {0}
+
+""".format(res['rows'][0]['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def dependents(self, gid, sid, did, fid, fsid):
+        """
+        This function get the dependents and return ajax response
+        for the foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+        dependents_result = self.get_dependents(self.conn, fsid)
+
+        # Fetching dependents of foreign servers
+        query = render_template("/".join([self.template_path, 'dependents.sql']), fsid=fsid)
+        status, result = self.conn.execute_dict(query)
+        if not status:
+            internal_server_error(errormsg=result)
+
+        for row in result['rows']:
+            dependents_result.append({'type': 'user_mapping', 'name': row['name'], 'field': 'normal' if (row['deptype'] == 'n') else ''})
+
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, fid, fsid):
+        """
+        This function get the dependencies and return ajax response
+        for the foreign server node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign Data Wrapper ID
+            fsid: Foreign server ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, fsid)
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+ForeignServerView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/coll-foreign_server.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/coll-foreign_server.png
new file mode 100644
index 0000000000000000000000000000000000000000..c1071768f4d2ed9797585b8725bfce1d3dbfafab
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/foreign_server.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/static/img/foreign_server.png
new file mode 100644
index 0000000000000000000000000000000000000000..dda392a2280c994f48d89e3ed67bbfcbe14ba045
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js
new file mode 100644
index 0000000..855bbea
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/js/foreign_servers.js
@@ -0,0 +1,180 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection',
+        'pgadmin.browser.server.privilege'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+  // Extend the browser's node model class to create a Options model
+  var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          fsrvoption: undefined,
+          fsrvvalue: undefined
+        },
+
+        // Defining schema for the Options model
+        schema: [
+          {id: 'fsrvoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'fsrvvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          // Validation for the option name
+          if (_.isUndefined(this.get('fsrvoption')) ||
+            _.isNull(this.get('fsrvoption')) ||
+            String(this.get('fsrvoption')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter an option name';
+            this.errorModel.set('fsrvoption', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('fsrvoption');
+          }
+          return null;
+        }
+    });
+
+  // Extend the browser's collection class for foreign server collection
+  if (!pgBrowser.Nodes['coll-foreign_server']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-foreign_server'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'foreign_server',
+        label: '{{ _('Foreign Servers') }}',
+        type: 'coll-foreign_server',
+        columns: ['name','fsrvowner','description']
+      });
+  };
+
+  // Extend the browser's node class for foreign server node
+  if (!pgBrowser.Nodes['foreign_server']) {
+    pgAdmin.Browser.Nodes['foreign_server'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'foreign_data_wrapper',
+      type: 'foreign_server',
+      label: '{{ _('Foreign Server') }}',
+      hasSQL:  true,
+      hasDepends: true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+
+        // Avoid multiple registration of menus
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        /* Create foreign server context menu at database,
+         * foreign server collections and foreign server node
+         */
+        pgBrowser.add_menus([{
+          name: 'create_foreign_server_on_coll', node: 'coll-foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon icon-foreign_server', data: {action: 'create'}
+        },{
+          name: 'create_foreign_server', node: 'foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon icon-foreign_server', data: {action: 'create'}
+        },{
+          name: 'create_foreign_server', node: 'foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Server...') }}',
+          icon: 'wcTabIcon icon-foreign_server', data: {action: 'create'}
+        }
+        ]);
+      },
+
+      // Defining model for foreign server node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          fsrvtype: undefined,
+          fsrvversion: undefined,
+          fsrvvalue: undefined,
+          fsrvoptions: [],
+          fsrvowner: undefined,
+          description: undefined,
+          fsrvacl: []
+        },
+
+        // Default values!
+        initialize: function(attrs, args) {
+          var isNew = (_.size(attrs) === 0);
+
+          if (isNew) {
+            var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
+
+            this.set({'fsrvowner': userInfo.name}, {silent: true});
+          }
+          pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
+        },
+
+        // Defining schema for the foreign server node
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: function(m) {
+            if (this.mode == 'edit' && this.node_info.server.version < 90200) {
+              return true;
+            }
+            else
+              return false;
+          }
+        },{
+          id: 'fsrvid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text', disabled: true, mode: ['properties']
+        },{
+          id: 'fsrvowner', label:'{{ _('Owner') }}', type: 'text',
+          control: Backform.NodeListByNameControl, node: 'role',
+          mode: ['edit', 'create', 'properties'], select2: { allowClear: false }
+        },{
+          id: 'fsrvtype', label:'{{ _('Type') }}', cell: 'string',
+          group: '{{ _('Definition') }}', type: 'text', mode: ['edit','create','properties'], disabled: function(m) {
+            return !m.isNew();
+          }
+        },{
+          id: 'fsrvversion', label:'{{ _('Version') }}', cell: 'string',
+          group: '{{ _('Definition') }}', type: 'text'
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline'
+        },{
+          id: 'fsrvoptions', label: 'Options', type: 'collection', group: "Options",
+          model: OptionsModel, control: 'unique-col-collection', mode: ['edit', 'create'],
+          canAdd: true, canDelete: true, uniqueCol : ['fsrvoption'],
+          columns: ['fsrvoption','fsrvvalue']
+         },{
+            id: 'fsrvacl', label: 'Privileges', type: 'collection', group: '{{ _('Security') }}',
+            model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({privileges: ['U']}), control: 'unique-col-collection',
+            mode: ['edit', 'create'], canAdd: true, canDelete: true, uniqueCol : ['grantee']
+         },{
+          id: 'acl', label: '{{ _('Privileges') }}', type: 'text',
+          group: '{{ _('Security') }}', mode: ['properties'], disabled: true
+         }
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-foreign_server'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..59edaa4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/acl.sql
@@ -0,0 +1,27 @@
+SELECT 'fsrvacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+    (SELECT
+        d.grantee, d.grantor, d.is_grantable,
+        CASE d.privilege_type
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+        END AS privilege_type
+    FROM
+        (SELECT srvacl FROM pg_foreign_server fsrv
+            LEFT OUTER JOIN pg_shdescription descr ON (
+            fsrv.oid=descr.objoid AND descr.classoid='pg_foreign_server'::regclass)
+{% if fsid %}
+        WHERE fsrv.oid = {{ fsid|qtLiteral }}::OID
+{% endif %}
+        ) acl,
+        (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable AS is_grantable,
+                (d).privilege_type AS privilege_type
+        FROM (SELECT aclexplode(srvacl) as d FROM pg_foreign_server fsrv1
+        {% if fsid %}
+                WHERE fsrv1.oid = {{ fsid|qtLiteral }}::OID ) a
+        {% endif %}
+        ) d
+    ) d
+    LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+    LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..da2630c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/create.sql
@@ -0,0 +1,40 @@
+{# ============= Create foreign server ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+CREATE SERVER {{ conn|qtIdent(data.name) }}{% if data.fsrvtype %}
+
+    TYPE {{ data.fsrvtype|qtLiteral }}{% endif %}{% if data.fsrvversion %}
+
+    VERSION {{ data.fsrvversion|qtLiteral }}{%-endif %}{% if fdwdata %}
+
+    FOREIGN DATA WRAPPER {{ conn|qtIdent(fdwdata.name) }}{% endif %}{% if data.fsrvoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
+
+{# ============= Set the owner for foreign server ============= #}
+{% if data.fsrvowner %}
+
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+{% endif %}
+{# ============= Set the comment for foreign server ============= #}
+{% if data.description %}
+
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Set the ACL for foreign server ============= #}
+{% if data.fsrvacl %}
+{% for priv in data.fsrvacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..ce89201
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Give foreign server name from foreign server id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign server ============= #}
+{% if name %}
+DROP SERVER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/dependents.sql
new file mode 100644
index 0000000..14b3d0a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/dependents.sql
@@ -0,0 +1,12 @@
+{# ============= Get dependents of foreign server ============= #}
+{% if fsid %}
+WITH umapData AS
+    (
+        SELECT u.oid AS um_oid, CASE WHEN u.umuser = 0::oid THEN 'public'::name ELSE a.rolname END AS name,
+        array_to_string(u.umoptions, ',') AS umoptions FROM pg_user_mapping u
+        LEFT JOIN pg_authid a ON a.oid = u.umuser WHERE u.umserver = {{ fsid }}::OID
+    )
+
+SELECT um.um_oid, name, dep.deptype FROM umapData um
+    LEFT JOIN pg_depend dep ON dep.objid=um.um_oid
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..011378c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/properties.sql
@@ -0,0 +1,27 @@
+{# ============= Give all the properties of foreign server ============= #}
+{% if fdwid %}
+SELECT fdw.oid as fdwoid,
+       fdwname as name
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+WHERE fdw.oid={{fdwid}}::int
+{% else %}
+SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description,
+array_to_string(srvoptions, ',') AS fsrvoptions,
+pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl
+FROM pg_foreign_server srv
+LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+{% if data and fdwdata %}
+WHERE fdw.fdwname = {{ fdwdata.name|qtLiteral }}::text and srvname = {{ data.name|qtLiteral }}::text
+{% elif fdwdata %}
+WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+{% if fid %}
+WHERE srvfdw={{fid}}::int
+{% endif %}
+{% if fsid %}
+WHERE srv.oid={{fsid}}::int
+{% endif %}
+ORDER BY srvname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..b51abfd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.1_plus/update.sql
@@ -0,0 +1,87 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign server name ============= #}
+{% if data.name != o_data.name %}
+ALTER SERVER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign server owner ============= #}
+{% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+
+{% endif %}
+{# ============= Update foreign server version ============= #}
+{% if data.fsrvversion and data.fsrvversion != o_data.fsrvversion %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    VERSION {{ data.fsrvversion|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server options and values ============= #}
+{% if data.fsrvoptions and data.fsrvoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.added %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.changed %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+SET {{conn|qtIdent(variable.fsrvoption)}} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.deleted %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.fsrvoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{# Change the privileges #}
+{% if data.fsrvacl %}
+{% if 'deleted' in data.fsrvacl %}
+{% for priv in data.fsrvacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fsrvacl %}
+{% for priv in data.fsrvacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fsrvacl %}
+{% for priv in data.fsrvacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql
new file mode 100644
index 0000000..56c3be7
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/acl.sql
@@ -0,0 +1,21 @@
+SELECT 'fsrvacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+    (SELECT
+        d.grantee, d.grantor, d.is_grantable,
+        CASE d.privilege_type
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+        END AS privilege_type
+    FROM
+        (SELECT srvacl FROM pg_foreign_server fsrv
+            LEFT OUTER JOIN pg_shdescription descr ON (
+            fsrv.oid=descr.objoid AND descr.classoid='pg_foreign_server'::regclass)
+{% if fsid %}
+  WHERE fsrv.oid = {{ fsid|qtLiteral }}::OID
+{% endif %}
+        ) acl,
+        aclexplode(srvacl) d
+        ) d
+    LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+    LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql
new file mode 100644
index 0000000..ce508b5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/create.sql
@@ -0,0 +1,40 @@
+{# ============= Create foreign server ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data.name %}
+CREATE SERVER {{ conn|qtIdent(data.name) }}{% if data.fsrvtype %}
+
+    TYPE {{ data.fsrvtype|qtLiteral }}{% endif %}{% if data.fsrvversion %}
+
+    VERSION {{ data.fsrvversion|qtLiteral }}{%-endif %}{% if fdwdata %}
+
+    FOREIGN DATA WRAPPER {{ conn|qtIdent(fdwdata.name) }}{% endif %}{% if data.fsrvoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
+
+{# ============= Set the owner for foreign server ============= #}
+{% if data.fsrvowner %}
+
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+{% endif %}
+{# ============= Set the comment for foreign server ============= #}
+{% if data.description %}
+
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Set the ACL for foreign server ============= #}
+{% if data.fsrvacl %}
+{% for priv in data.fsrvacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql
new file mode 100644
index 0000000..ce89201
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Give foreign server name from foreign server id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign server ============= #}
+{% if name %}
+DROP SERVER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/dependents.sql
new file mode 100644
index 0000000..14b3d0a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/dependents.sql
@@ -0,0 +1,12 @@
+{# ============= Get dependents of foreign server ============= #}
+{% if fsid %}
+WITH umapData AS
+    (
+        SELECT u.oid AS um_oid, CASE WHEN u.umuser = 0::oid THEN 'public'::name ELSE a.rolname END AS name,
+        array_to_string(u.umoptions, ',') AS umoptions FROM pg_user_mapping u
+        LEFT JOIN pg_authid a ON a.oid = u.umuser WHERE u.umserver = {{ fsid }}::OID
+    )
+
+SELECT um.um_oid, name, dep.deptype FROM umapData um
+    LEFT JOIN pg_depend dep ON dep.objid=um.um_oid
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql
new file mode 100644
index 0000000..98154b8
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/properties.sql
@@ -0,0 +1,26 @@
+{# ============= Give all the properties of foreign server ============= #}
+{% if fdwid %}
+SELECT fdw.oid as fdwoid, fdwname as name
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+WHERE fdw.oid={{fdwid}}::int
+{% else %}
+SELECT srv.oid as fsrvid, srvname as name, srvtype as fsrvtype, srvversion as fsrvversion, fdw.fdwname as fdwname, description,
+array_to_string(srvoptions, ',') AS fsrvoptions,
+pg_get_userbyid(srvowner) as fsrvowner, array_to_string(srvacl::text[], ', ') as acl
+FROM pg_foreign_server srv
+LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+{% if data and fdwdata %}
+WHERE fdw.fdwname = {{ fdwdata.name|qtLiteral }}::text and srvname = {{ data.name|qtLiteral }}::text
+{% elif fdwdata %}
+WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+{% if fid %}
+WHERE srvfdw={{fid}}::int
+{% endif %}
+{% if fsid %}
+WHERE srv.oid={{fsid}}::int
+{% endif %}
+ORDER BY srvname;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql
new file mode 100644
index 0000000..b51abfd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/templates/foreign_servers/sql/9.3_plus/update.sql
@@ -0,0 +1,87 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign server name ============= #}
+{% if data.name != o_data.name %}
+ALTER SERVER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign server owner ============= #}
+{% if data.fsrvowner and data.fsrvowner != o_data.fsrvowner %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fsrvowner) }};
+
+{% endif %}
+{# ============= Update foreign server version ============= #}
+{% if data.fsrvversion and data.fsrvversion != o_data.fsrvversion %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    VERSION {{ data.fsrvversion|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON SERVER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign server options and values ============= #}
+{% if data.fsrvoptions and data.fsrvoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.added %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+ADD {{ conn|qtIdent(variable.fsrvoption) }} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.changed %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+SET {{conn|qtIdent(variable.fsrvoption)}} {{variable.fsrvvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{% if data.fsrvoptions and data.fsrvoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fsrvoptions.deleted %}
+{% if variable.fsrvoption and variable.fsrvoption != '' %}
+{% if addAlter == "False" %}
+ALTER SERVER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.fsrvoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{# Change the privileges #}
+{% if data.fsrvacl %}
+{% if 'deleted' in data.fsrvacl %}
+{% for priv in data.fsrvacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{% endfor %}
+{% endif %}
+{% if 'changed' in data.fsrvacl %}
+{% for priv in data.fsrvacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN SERVER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% if 'added' in data.fsrvacl %}
+{% for priv in data.fsrvacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN SERVER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
+
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py
new file mode 100644
index 0000000..0e5f7b4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py
@@ -0,0 +1,753 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2016, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""Implements User Mapping Node"""
+
+import json
+from flask import render_template, make_response, request, jsonify
+from flask.ext.babel import gettext
+from pgadmin.utils.ajax import make_json_response, \
+    make_response as ajax_response, internal_server_error
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.browser.collection import CollectionNodeModule
+import pgadmin.browser.server_groups.servers as servers
+from pgadmin.utils.ajax import precondition_required
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+from functools import wraps
+
+
+class UserMappingModule(CollectionNodeModule):
+    """
+    class UserMappingModule(CollectionNodeModule)
+
+        A module class for user mapping node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the user mapping module and it's base module.
+
+    * get_nodes(gid, sid, did, fid, fsid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load(self)
+      - Load the module script for user mapping, when any of the foreign server node is
+        initialized.
+    """
+
+    NODE_TYPE = 'user_mapping'
+    COLLECTION_LABEL = gettext("User Mappings")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the User mapping module and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+
+        self.min_ver = None
+        self.max_ver = None
+
+        super(UserMappingModule, self).__init__(*args, **kwargs)
+
+    def get_nodes(self, gid, sid, did, fid, fsid):
+        """
+        Method is used to generate the browser collection node
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+
+        yield self.generate_browser_collection_node(fsid)
+
+    @property
+    def node_inode(self):
+        """
+        node_inode
+
+        Override this property to make the node as leaf node.
+        """
+        return False
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for user mapping, when any of the foreign server node is initialized.
+
+        Returns: node type of the server module.
+        """
+
+        return servers.ServerModule.NODE_TYPE
+
+blueprint = UserMappingModule(__name__)
+
+
+class UserMappingView(PGChildNodeView):
+    """
+    class UserMappingView(PGChildNodeView)
+
+        A view class for user mapping node derived from PGChildNodeView. This class is
+        responsible for all the stuff related to view like updating user mapping
+        node, showing properties, showing sql in sql pane.
+
+    Methods:
+    -------
+    * __init__(**kwargs)
+      - Method is used to initialize the UserMappingView and it's base view.
+
+    * module_js()
+      - This property defines (if javascript) exists for this node.
+        Override this property for your own logic
+
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * list(gid, sid, did, fid, fsid)
+      - This function is used to list all the user mapping nodes within that collection.
+
+    * nodes(gid, sid, did, fid, fsid)
+      - This function will used to create all the child node within that collection.
+        Here it will create all the user mapping node.
+
+    * properties(gid, sid, did, fid, fsid, umid)
+      - This function will show the properties of the selected user mapping node
+
+    * tokenizeOptions(option_value)
+      - This function will tokenize the string stored in database
+
+    * update(gid, sid, did, fid, fsid, umid)
+      - This function will update the data for the selected user mapping node
+
+    * create(gid, sid, did, fid, fsid)
+      - This function will create the new user mapping node
+
+    * delete(gid, sid, did, fid, fsid, umid)
+      - This function will delete the selected user mapping node
+
+    * msql(gid, sid, did, fid, fsid, umid)
+      - This function is used to return modified SQL for the selected user mapping node
+
+    * get_sql(data, fid, fsid, umid)
+      - This function will generate sql from model data
+
+    * sql(gid, sid, did, fid, fsid, umid):
+      - This function will generate sql to show it in sql pane for the selected user mapping node.
+
+    * dependents(gid, sid, did, fid, fsid, umid):
+      - This function get the dependents and return ajax response for the user mapping node.
+
+    * dependencies(self, gid, sid, did, fid, fsid, umid):
+      - This function get the dependencies and return ajax response for the user mapping node.
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+            {'type': 'int', 'id': 'gid'},
+            {'type': 'int', 'id': 'sid'},
+            {'type': 'int', 'id': 'did'},
+            {'type': 'int', 'id': 'fid'},
+            {'type': 'int', 'id': 'fsid'}
+            ]
+    ids = [
+            {'type': 'int', 'id': 'umid'}
+            ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'delete': [{
+           'delete': 'delete'
+        }],
+        'nodes': [{'get': 'node'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {'get': 'msql'}],
+        'stats': [{'get': 'statistics'}],
+        'dependency': [{'get': 'dependencies'}],
+        'dependent': [{'get': 'dependents'}],
+        'module.js': [{}, {}, {'get': 'module_js'}]
+    })
+
+    def module_js(self):
+        """
+        This property defines (if javascript) exists for this node.
+        Override this property for your own logic.
+        """
+        return make_response(
+                render_template(
+                    "user_mappings/js/user_mappings.js",
+                    _=gettext
+                    ),
+                200, {'Content-Type': 'application/x-javascript'}
+                )
+
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+
+            # If DB not connected then return error to browser
+            if not self.conn.connected():
+                return precondition_required(
+                    gettext(
+                            "Connection to the server has been lost!"
+                    )
+                )
+
+            self.template_path = 'user_mappings/sql/9.1_plus'
+
+            ver = self.manager.version
+            # we will set template path for sql scripts
+            if ver >= 90100:
+                self.template_path = 'user_mappings/sql/9.1_plus'
+
+            return f(*args, **kwargs)
+        return wrap
+
+    @check_precondition
+    def list(self, gid, sid, did, fid, fsid):
+        """
+        This function is used to list all the user mapping nodes within that collection.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return ajax_response(
+                response=res['rows'],
+                status=200
+                )
+
+    @check_precondition
+    def nodes(self, gid, sid, did, fid, fsid):
+        """
+        This function will used to create all the child node within that collection.
+        Here it will create all the user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+
+        res = []
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, conn=self.conn)
+        status, r_set = self.conn.execute_2darray(sql)
+
+        if not status:
+            return internal_server_error(errormsg=r_set)
+
+        for row in r_set['rows']:
+            res.append(
+                    self.blueprint.generate_browser_node(
+                        row['um_oid'],
+                        fsid,
+                        row['name'],
+                        icon="icon-user_mapping"
+                    ))
+
+        return make_json_response(
+                data=res,
+                status=200
+                )
+
+    def tokenizeOptions(self, option_value):
+        """
+        This function will tokenize the string stored in database
+        e.g. database store the value as below
+        key1=value1, key2=value2, key3=value3, ....
+        This function will extract key and value from above string
+
+        Args:
+            option_value: key value option/value pair read from database
+        """
+
+        if option_value is not None:
+            option_str = option_value.split(',')
+            um_options = []
+            for um_option in option_str:
+                k, v = um_option.split('=', 1)
+                um_options.append({'umoption': k,'umvalue': v})
+            return um_options
+
+    @check_precondition
+    def properties(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will show the properties of the selected user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+            umid: User mapping ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['name'] == 'public':
+            res['rows'][0]['name'] = 'PUBLIC'
+
+        if res['rows'][0]['umoptions'] is not None:
+            res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+        return ajax_response(
+                response=res['rows'][0],
+                status=200
+                )
+
+    @check_precondition
+    def create(self, gid, sid, did, fid, fsid):
+        """
+        This function will create the user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+        """
+
+        required_args = [
+            'name'
+        ]
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        for arg in required_args:
+            if arg not in data:
+                return make_json_response(
+                    status=410,
+                    success=0,
+                    errormsg=gettext(
+                        "Couldn't find the required parameter (%s)." % arg
+                    )
+                )
+
+        try:
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            new_list = []
+
+            if 'umoptions' in data:
+                for item in data['umoptions']:
+                    new_dict = {}
+                    if item['umoption']:
+                        if 'umvalue' in item and item['umvalue'] and item['umvalue'] != '':
+                            new_dict.update(item);
+                        else:
+                            new_dict.update({'umoption': item['umoption'], 'umvalue': ''})
+
+                    new_list.append(new_dict)
+
+                data['umoptions'] = new_list
+
+            sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fsid=fsid, data=data,
+                                  conn=self.conn)
+            status, r_set = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=r_set)
+
+            for row in r_set['rows']:
+                return jsonify(
+                    node=self.blueprint.generate_browser_node(
+                        row['um_oid'],
+                        fsid,
+                        row['name'],
+                        icon='icon-user_mapping'
+                )
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def update(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will update the data for the selected user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+            umid: User mapping ID
+        """
+
+        data = request.form if request.form else json.loads(request.data.decode())
+        sql = self.get_sql(gid, sid, data, did, fid, fsid, umid)
+        try:
+            if sql and sql.strip('\n') and sql.strip(' '):
+                status, res = self.conn.execute_scalar(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                return make_json_response(
+                    success=1,
+                    info="User Mapping updated",
+                    data={
+                        'id':  umid,
+                        'fsid': fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+            else:
+                return make_json_response(
+                    success=1,
+                    info="Nothing to update",
+                    data={
+                        'id':  umid,
+                        'fsid': fsid,
+                        'fid': fid,
+                        'did': did,
+                        'sid': sid,
+                        'gid': gid
+                    }
+                )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def delete(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will delete the selected user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+            umid: User mapping ID
+        """
+
+        if self.cmd == 'delete':
+            # This is a cascade operation
+            cascade = True
+        else:
+            cascade = False
+
+        try:
+            # Get name of foreign server from fsid
+            sql = render_template("/".join([self.template_path, 'delete.sql']), fsid=fsid, conn=self.conn)
+            status, name = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=name)
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+            status, res = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = res['rows'][0]
+
+            # drop user mapping
+            sql = render_template("/".join([self.template_path, 'delete.sql']), data=data, name=name, cascade=cascade,
+                                  conn=self.conn)
+            status, res = self.conn.execute_scalar(sql)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("User Mapping dropped"),
+                data={
+                    'id': umid,
+                    'fsid': fsid,
+                    'fid': fid,
+                    'did': did,
+                    'sid': sid,
+                    'gid': gid,
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def msql(self, gid, sid, did, fid, fsid, umid=None):
+        """
+        This function is used to return modified SQL for the selected user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+            umid: User mapping ID
+        """
+
+        data = {}
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v)
+            except ValueError:
+                data[k] = v
+
+        sql = self.get_sql(gid, sid, data, did, fid, fsid, umid)
+        if sql and sql.strip('\n') and sql.strip(' '):
+            return make_json_response(
+                    data=sql,
+                    status=200
+                    )
+        else:
+            return make_json_response(
+                    data='-- Modified SQL --',
+                    status=200
+                    )
+
+    def get_sql(self, gid, sid, data, did, fid, fsid, umid=None):
+        """
+        This function will generate sql from model data.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            data: Contains the data of the selected user mapping node
+            fid: foreign data wrapper ID
+            fsid: foreign server ID
+            umid: User mapping ID
+        """
+
+        required_args = [
+            'name'
+        ]
+        try:
+            if umid is not None:
+                sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+                status, res = self.conn.execute_dict(sql)
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                if res['rows'][0]['umoptions'] is not None:
+                    res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+                old_data = res['rows'][0]
+
+            sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+            status, res1 = self.conn.execute_dict(sql)
+            if not status:
+                return internal_server_error(errormsg=res1)
+
+            fdw_data = res1['rows'][0]
+
+            for arg in required_args:
+                if arg not in data:
+                    data[arg] = old_data[arg]
+
+                    new_list_add = []
+                    new_list_change = []
+
+                    # Allow user to set the blank value in fdwvalue field in option model
+                    if 'umoptions' in data and 'added' in data['umoptions']:
+                        for item in data['umoptions']['added']:
+                            new_dict_add = {}
+                            if item['umoption']:
+                                if 'umvalue' in item and item['umvalue'] and item['umvalue'] != '':
+                                    new_dict_add.update(item);
+                                else:
+                                    new_dict_add.update({'umoption': item['umoption'], 'umvalue': ''})
+
+                            new_list_add.append(new_dict_add)
+
+                        data['umoptions']['added'] = new_list_add
+
+                    # Allow user to set the blank value in fdwvalue field in option model
+                    if 'umoptions' in data and 'changed' in data['umoptions']:
+                        for item in data['umoptions']['changed']:
+                            new_dict_change = {}
+                            if item['umoption']:
+                                if 'umvalue' in item and item['umvalue'] and item['umvalue'] != '':
+                                    new_dict_change.update(item);
+                                else:
+                                    new_dict_change.update({'umoption': item['umoption'], 'umvalue': ''})
+
+                            new_list_change.append(new_dict_change)
+
+                        data['umoptions']['changed'] = new_list_change
+
+                    sql = render_template("/".join([self.template_path, 'update.sql']), data=data, o_data=old_data,
+                                          fdwdata=fdw_data, conn=self.conn)
+                else:
+                    sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+                    status, res = self.conn.execute_dict(sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+                    fdw_data = res['rows'][0]
+
+                    new_list = []
+
+                    if 'umoptions' in data:
+                        for item in data['umoptions']:
+                            new_dict = {}
+                            if item['umoption']:
+                                if 'umvalue' in item and item['umvalue'] \
+                                        and item['umvalue'] != '':
+                                    new_dict.update(item);
+                                else:
+                                    new_dict.update(
+                                        {'umoption': item['umoption'],
+                                         'umvalue': ''}
+                                    )
+                            new_list.append(new_dict)
+
+                        data['umoptions'] = new_list
+
+                    sql = render_template("/".join([self.template_path, 'create.sql']), data=data, fdwdata=fdw_data,
+                                          conn=self.conn)
+                    sql += "\n"
+                return sql
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @check_precondition
+    def sql(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function will generate sql to show it in sql pane for the selected user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign data wrapper ID
+            fsid: Foreign server ID
+            umid: User mapping ID
+        """
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), umid=umid, conn=self.conn)
+        status, res = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if res['rows'][0]['umoptions'] is not None:
+            res['rows'][0]['umoptions'] = self.tokenizeOptions(res['rows'][0]['umoptions'])
+
+        sql = render_template("/".join([self.template_path, 'properties.sql']), fserid=fsid, conn=self.conn)
+        status, res1 = self.conn.execute_dict(sql)
+        if not status:
+            return internal_server_error(errormsg=res1)
+
+        fdw_data = res1['rows'][0]
+
+        sql = ''
+        sql = render_template("/".join([self.template_path, 'create.sql']), data=res['rows'][0], fdwdata=fdw_data,
+                              conn=self.conn)
+        sql += "\n"
+
+        sql_header = """-- User Mapping : {0}
+
+-- DROP USER MAPPING FOR {0} SERVER {1}
+
+""".format(res['rows'][0]['name'], fdw_data['name'])
+
+        sql = sql_header + sql
+
+        return ajax_response(response=sql)
+
+    @check_precondition
+    def dependents(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function get the dependents and return ajax response
+        for the user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: foreign data wrapper ID
+            fsid: Foreign server ID
+            umid: user mapping ID
+        """
+
+        dependents_result = self.get_dependents(self.conn, umid)
+        return ajax_response(
+                response=dependents_result,
+                status=200
+                )
+
+    @check_precondition
+    def dependencies(self, gid, sid, did, fid, fsid, umid):
+        """
+        This function get the dependencies and return ajax response
+        for the user mapping node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did: Database ID
+            fid: Foreign Data Wrapper ID
+            fsid: Foreign server ID
+            umid: user mapping ID
+        """
+        dependencies_result = self.get_dependencies(self.conn, umid)
+        return ajax_response(
+                response=dependencies_result,
+                status=200
+                )
+
+UserMappingView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/coll-user_mapping.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/coll-user_mapping.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e68c2b12866ad4b480a41a7d1032a1df34a1f45
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/user_mapping.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/static/img/user_mapping.png
new file mode 100644
index 0000000000000000000000000000000000000000..e768c9bfc0b3e55f32f12bd037b7ecd52a9e430f
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js
new file mode 100644
index 0000000..8e701ce
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/js/user_mappings.js
@@ -0,0 +1,157 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify', 'pgadmin.browser.collection'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+    // Extend the browser's node model class to create a Options model
+    var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          umoption: undefined,
+          umvalue: undefined
+        },
+
+        // Defining schema for the Options model
+        schema: [
+          {id: 'umoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'umvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          // Validation for the option value
+          if (_.isUndefined(this.get('umoption')) ||
+            _.isNull(this.get('umoption')) ||
+            String(this.get('umoption')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter an option name';
+            this.errorModel.set('umoption', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('umoption');
+          }
+          return null;
+        }
+    });
+
+  // Extend the browser's collection class for user mapping collection
+  if (!pgBrowser.Nodes['coll-user_mapping']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-user_mapping'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'user_mapping',
+        label: '{{ _('User Mappings') }}',
+        type: 'coll-user_mapping',
+        columns: ['name']
+      });
+  };
+
+  // Extend the browser's node class for user mapping node
+  if (!pgBrowser.Nodes['user_mapping']) {
+    pgAdmin.Browser.Nodes['user_mapping'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'foreign_server',
+      type: 'user_mapping',
+      label: '{{ _('User Mapping') }}',
+      hasSQL:  true,
+      hasDepends: true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+
+        // Avoid multiple registration of menus
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        /* Create foreign server context menu at database,
+         * user mapping collections and user mapping node
+         */
+        pgBrowser.add_menus([{
+          name: 'create_user_mapping_on_coll', node: 'coll-user_mapping', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon icon-user_mapping', data: {action: 'create'}
+        },{
+          name: 'create_user_mapping', node: 'user_mapping', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon icon-user_mapping', data: {action: 'create'}
+        },{
+          name: 'create_user_mapping', node: 'foreign_server', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('User Mapping...') }}',
+          icon: 'wcTabIcon icon-user_mapping', data: {action: 'create'}
+        }
+        ]);
+      },
+
+      // Defining model for user mapping node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          um_options: []
+        },
+
+        // Default values!
+        initialize: function(attrs, args) {
+          var isNew = (_.size(attrs) === 0);
+
+          if (isNew) {
+            var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
+
+            this.set({'name': userInfo.name}, {silent: true});
+          }
+          pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
+        },
+
+        // Defining schema for the user mapping node
+        schema: [{
+          id: 'name', label:'{{ _('User') }}', type: 'text',
+          control: Backform.NodeListByNameControl, node: 'role',
+          mode: ['edit', 'create', 'properties'], select2: { allowClear: false },
+          disabled: function(m) { return !m.isNew(); },
+          transform: function(data) {
+            var self = this;
+            node = self.field.get('schema_node');
+            var res =
+            Backform.NodeListByNameControl.prototype.defaults.transform.apply(
+              this, arguments
+            );
+            res.unshift({label: 'CURRENT_USER', value: 'CURRENT_USER', image: 'icon-' + node.type},
+                        {label: 'PUBLIC', value: 'PUBLIC', image: 'icon-' + node.type});
+            return res;
+         }
+        },{
+          id: 'um_oid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text', disabled: true, mode: ['properties'],
+        },{
+          id: 'umoptions', label: 'Options', type: 'collection', group: "Options",
+          model: OptionsModel, control: 'unique-col-collection', mode: ['create', 'edit'],
+          canAdd: true, canDelete: true, uniqueCol : ['umoption']
+        }
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-user_mapping'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..f467ae4
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/create.sql
@@ -0,0 +1,13 @@
+{# ============= Create of user mapping for server ============= #}
+{% if data and fdwdata %}
+CREATE USER MAPPING FOR {% if data.name == "CURRENT_USER" or data.name == "PUBLIC" %}{{ data.name }}{% else %}{{ conn|qtIdent(data.name) }}{% endif %} SERVER {{ conn|qtIdent(fdwdata.name) }}{%endif%}{% if data.umoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.umoptions %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.umoption) }} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{%else%}){% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}{% if data %};{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..0f65d62
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/delete.sql
@@ -0,0 +1,9 @@
+{# ============= Get the foreing server name from id ============= #}
+{% if fsid %}
+SELECT srvname as name FROM pg_foreign_server srv LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw
+    WHERE srv.oid={{fsid}}::int;
+{% endif %}
+{# ============= Drop/Delete cascade user mapping ============= #}
+{% if name and data %}
+DROP USER MAPPING FOR  {{ conn|qtIdent(data.name) }} SERVER {{ conn|qtIdent(name) }}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..69f0588
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/properties.sql
@@ -0,0 +1,23 @@
+{# ============= Get the properties of user mapping ============= #}
+{% if fserid %}
+SELECT srv.oid as fsrvid, srvname as name
+FROM pg_foreign_server srv
+    LEFT OUTER JOIN pg_description des ON (des.objoid=srv.oid AND des.objsubid=0 AND des.classoid='pg_foreign_server'::regclass)
+WHERE srv.oid = {{fserid}}::int
+{% endif %}
+{% if fsid or umid or fdwdata or data %}
+WITH umapData AS
+    (
+        SELECT u.oid AS um_oid, CASE WHEN u.umuser = 0::oid THEN 'public'::name ELSE a.rolname END AS name,
+        array_to_string(u.umoptions, ',') AS umoptions FROM pg_user_mapping u
+        LEFT JOIN pg_authid a ON a.oid = u.umuser {% if fsid %} WHERE u.umserver = {{fsid}}::int {% endif %} {% if umid %} WHERE u.oid= {{umid}}::int {% endif %}
+    )
+    SELECT * FROM umapData
+{% if data %}
+    WHERE {% if data.name == "CURRENT_USER" %} name = {{data.name}} {% elif data.name == "PUBLIC" %} name = {{data.name.lower()|qtLiteral}} {% else %} name = {{data.name|qtLiteral}} {% endif %}
+{% endif %}
+{% if fdwdata %}
+    WHERE fdw.fdwname = {{fdwdata.name|qtLiteral}}::text
+{% endif %}
+    ORDER BY 2;
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..de150de
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/templates/user_mappings/sql/9.1_plus/update.sql
@@ -0,0 +1,36 @@
+{# ============= Update user mapping options and values ============= #}
+{% if o_data.name and data.umoptions and data.umoptions.added and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.added %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.umoption) }} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+{% endif %}
+{% if data.umoptions and data.umoptions.changed and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.changed %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+SET {{conn|qtIdent(variable.umoption)}} {{variable.umvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{%endif%}
+{% endfor %}
+
+{% endif %}
+{% if data.umoptions and data.umoptions.deleted and fdwdata %}
+{% set addAlter = "False" %}
+{% for variable in data.umoptions.deleted %}
+{% if variable.umoption and variable.umoption != '' %}
+{% if addAlter == "False" %}
+ALTER USER MAPPING FOR {{ conn|qtIdent(o_data.name) }} SERVER {{ conn|qtIdent(fdwdata.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{conn|qtIdent(variable.umoption)}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/coll-foreign_data_wrapper.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/coll-foreign_data_wrapper.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b1c8543c69448b928acd21032fe50b21f032dd1
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/foreign_data_wrapper.png b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/static/img/foreign_data_wrapper.png
new file mode 100644
index 0000000000000000000000000000000000000000..0cb967671834e280190bbd5777c3ddc0ab07901d
GIT binary patch
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js
new file mode 100644
index 0000000..09dd348
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/js/foreign_data_wrappers.js
@@ -0,0 +1,180 @@
+define(
+        ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser',
+        'alertify', 'pgadmin.browser.collection',
+        'pgadmin.browser.server.privilege'],
+function($, _, S, pgAdmin, pgBrowser, alertify) {
+
+    // Extend the browser's node model class to create a Options model
+    var OptionsModel = pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          fdwoption: undefined,
+          fdwvalue: undefined
+        },
+
+        // Defining schema for the Options model
+        schema: [
+          {id: 'fdwoption', label:'Options', type:'text', group: null, editable: true},
+          {id: 'fdwvalue', label:'Value', type: 'text', group:null, extraHeaderClasses: 'cellwidth-40', editable: true},
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          // Validation for the option name
+          if (_.isUndefined(this.get('fdwoption')) ||
+            _.isNull(this.get('fdwoption')) ||
+            String(this.get('fdwoption')).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = 'Please enter an option name';
+            this.errorModel.set('fdwoption', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('fdwoption');
+          }
+          return null;
+        }
+    });
+
+  // Extend the browser's collection class for foreign data wrapper collection
+  if (!pgBrowser.Nodes['coll-foreign_data_wrapper']) {
+    var foreign_data_wrappers = pgAdmin.Browser.Nodes['coll-foreign_data_wrapper'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'foreign_data_wrapper',
+        label: '{{ _('Foreign Data Wrappers') }}',
+        type: 'coll-foreign_data_wrapper',
+        columns: ['name','fdwowner','description']
+      });
+  };
+
+  // Extend the browser's node class for foreign data wrapper node
+  if (!pgBrowser.Nodes['foreign_data_wrapper']) {
+    pgAdmin.Browser.Nodes['foreign_data_wrapper'] = pgAdmin.Browser.Node.extend({
+      parent_type: 'database',
+      type: 'foreign_data_wrapper',
+      label: '{{ _('Foreign Data Wrapper') }}',
+      hasSQL:  true,
+      hasDepends: true,
+      canDrop: true,
+      canDropCascade: true,
+      Init: function() {
+
+        // Avoid multiple registration of menus
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        /* Create foreign data wrapper context menu at database,
+         * foreign data wrapper collections and foreign data wrapper node
+         */
+        pgBrowser.add_menus([{
+          name: 'create_foreign_data_wrapper_on_coll', node: 'coll-foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon icon-foreign_data_wrapper', data: {action: 'create'}
+        },{
+          name: 'create_foreign_data_wrapper', node: 'foreign_data_wrapper', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon icon-foreign_data_wrapper', data: {action: 'create'}
+        },{
+          name: 'create_foreign_data_wrapper', node: 'database', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: '{{ _('Foreign Data Wrapper...') }}',
+          icon: 'wcTabIcon icon-foreign_data_wrapper', data: {action: 'create'}
+        }
+        ]);
+      },
+
+      // Defining model for foreign data wrapper node
+      model: pgAdmin.Browser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          fdwowner: undefined,
+          comment: undefined,
+          fdwvalue: undefined,
+          fdwhan: undefined,
+          fdwoption: undefined,
+          fdwacl: []
+        },
+
+        // Default values!
+        initialize: function(attrs, args) {
+          var isNew = (_.size(attrs) === 0);
+
+          if (isNew) {
+            var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user;
+
+            this.set({'fdwowner': userInfo.name}, {silent: true});
+          }
+          pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
+        },
+
+        // Defining schema for the foreign data wrapper node
+        schema: [{
+          id: 'name', label: '{{ _('Name') }}', cell: 'string',
+          type: 'text', disabled: function(m) {
+
+            // name field will be disabled only if edit mode and server version is below 9.2
+            if (this.mode == 'edit' && this.node_info.server.version < 90200) {
+              return true;
+            }
+            else
+              return false;
+          }
+        },{
+          id: 'fdwoid', label:'{{ _('OID') }}', cell: 'string',
+          type: 'text', disabled: true, mode: ['properties']
+        },{
+          id: 'fdwowner', label:'{{ _('Owner') }}', type: 'text',
+          control: Backform.NodeListByNameControl, node: 'role',
+          mode: ['edit', 'create', 'properties'], select2: { allowClear: false }
+        },{
+          id: 'fdwhan', label:'{{ _('Handler') }}', type: 'text', control: 'node-ajax-options',
+          group: '{{ _('Definition') }}', mode: ['edit', 'create', 'properties'], url:'get_handlers'
+        },{
+          id: 'description', label:'{{ _('Comment') }}', cell: 'string',
+          type: 'multiline'
+        },{
+          id: 'fdwoptions', label: 'Options', type: 'collection', group: '{{ _('Options') }}',
+          model: OptionsModel, control: 'unique-col-collection', mode: ['edit', 'create'],
+          canAdd: true, canDelete: true, uniqueCol : ['fdwoption'],
+          columns: ['fdwoption','fdwvalue']
+        },{
+          id: 'fdwvalue', label:'{{ _('Validator') }}', type: 'text', control: 'node-ajax-options',
+          group: '{{ _('Definition') }}', mode: ['edit', 'create', 'properties'], url:'get_validators'
+        },{
+            id: 'fdwacl', label: 'Privileges', type: 'collection', group: '{{ _('Security') }}',
+            model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend({privileges: ['U']}), control: 'unique-col-collection',
+            mode: ['edit', 'create'], canAdd: true, canDelete: true, uniqueCol : ['grantee']
+         },{
+          id: 'acl', label: '{{ _('Privileges') }}', type: 'text',
+          group: '{{ _('Security') }}', mode: ['properties'], disabled: true
+         }
+        ],
+
+        /* validate function is used to validate the input given by
+         * the user. In case of error, message will be displayed on
+         * the browser for the respective control.
+         */
+        validate: function() {
+          var name = this.get('name');
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            var msg = '{{ _('Name can not be empty!') }}';
+            this.errorModel.set('name', msg);
+            return msg;
+          } else {
+            this.errorModel.unset('name');
+          }
+          return null;
+        }
+      })
+  });
+
+  }
+
+  return pgBrowser.Nodes['coll-foreign_data_wrapper'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql
new file mode 100644
index 0000000..61da46f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/acl.sql
@@ -0,0 +1,27 @@
+SELECT 'fdwacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+    (SELECT
+        d.grantee, d.grantor, d.is_grantable,
+        CASE d.privilege_type
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+        END AS privilege_type
+    FROM
+        (SELECT fdwacl FROM pg_foreign_data_wrapper fdw
+            LEFT OUTER JOIN pg_shdescription descr ON (
+            fdw.oid=descr.objoid AND descr.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+    WHERE fdw.oid = {{ fid|qtLiteral }}::OID
+{% endif %}
+        ) acl,
+            (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable AS is_grantable,
+                    (d).privilege_type AS privilege_type
+            FROM (SELECT aclexplode(fdwacl) as d FROM pg_foreign_data_wrapper fdw1
+            {% if fid %}
+                    WHERE fdw1.oid = {{ fid|qtLiteral }}::OID ) a
+            {% endif %}
+            ) d
+    ) d
+    LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+    LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql
new file mode 100644
index 0000000..996fd71
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/create.sql
@@ -0,0 +1,38 @@
+{# ============= Create foreign data wrapper ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data.name %}
+CREATE FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}{% if data.fdwvalue %}
+
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }}{%endif%}{% if data.fdwhan %}
+
+    HANDLER {{ conn|qtIdent(data.fdwhan) }}{% endif %}{% if data.fdwoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}{% endif %}{%if data %};{%endif%}
+
+{# ============= Set the owner for foreign data wrapper ============= #}
+{% if data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Comment on of foreign data wrapper object ============= #}
+{% if data.description %}
+
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Create ACL for foreign data wrapper ============= #}
+{% if data.fdwacl %}
+{% for priv in data.fdwacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}
+{% endfor %}
+{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql
new file mode 100644
index 0000000..5677c99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/delete.sql
@@ -0,0 +1,8 @@
+{# ============= Get foreign data wrapper from fid ============= #}
+{% if fid %}
+SELECT fdwname as name from pg_foreign_data_wrapper WHERE oid={{fid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign data wrapper ============= #}
+{% if name %}
+DROP FOREIGN DATA WRAPPER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql
new file mode 100644
index 0000000..50d27c6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/handlers.sql
@@ -0,0 +1,2 @@
+{# ============= Get the handlers of foreign data wrapper ============= #}
+SELECT proname as fdwhan FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE pronargs=0 AND prorettype=3115;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql
new file mode 100644
index 0000000..af28d13
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/properties.sql
@@ -0,0 +1,14 @@
+{# ============= Get all the properties of foreign data wrapper ============= #}
+SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, vh.proname as fdwhan, vp.proname as fdwvalue, description,
+    array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl
+FROM pg_foreign_data_wrapper fdw
+LEFT OUTER JOIN pg_proc vh on vh.oid=fdwhandler
+LEFT OUTER JOIN pg_proc vp on vp.oid=fdwvalidator
+LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+WHERE fdw.oid={{fid}}::int
+{% endif %}
+{% if fname %}
+WHERE fdw.fdwname={{ fname|qtLiteral }}::text
+{% endif %}
+ORDER BY fdwname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql
new file mode 100644
index 0000000..a73f83b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/update.sql
@@ -0,0 +1,99 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign data wrapper name ============= #}
+{% if data.name != o_data.name %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper owner ============= #}
+{% if data.fdwowner and data.fdwowner != o_data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper validator ============= #}
+{% if data.fdwvalue and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }};
+
+{% endif %}
+{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO VALIDATOR;
+
+{% endif %}
+{# ============= Update foreign data wrapper handler ============= #}
+{% if data.fdwhan and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    HANDLER {{ conn|qtIdent(data.fdwhan) }};
+
+{% endif %}
+{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO HANDLER;
+
+{% endif %}
+{# ============= Update foreign data wrapper comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign data wrapper options and values ============= #}
+{% if data.fdwoptions and data.fdwoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.added %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+
+
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.changed %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+SET {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+
+
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.deleted %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{ conn|qtIdent(variable.fdwoption) }}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{# Change the privileges #}
+{% if data.fdwacl %}
+{% if 'deleted' in data.fdwacl %}
+{% for priv in data.fdwacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}{% endfor %}
+{% endif %}
+{% if 'changed' in data.fdwacl %}
+{% for priv in data.fdwacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% if 'added' in data.fdwacl %}
+{% for priv in data.fdwacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql
new file mode 100644
index 0000000..6f3d019
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.1_plus/validators.sql
@@ -0,0 +1,2 @@
+{# ============= Get the validators of foreign data wrapper ============= #}
+SELECT proname as fdwvalue FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE proargtypes[0]=1009 AND proargtypes[1]=26;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql
new file mode 100644
index 0000000..ea27ed1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/acl.sql
@@ -0,0 +1,21 @@
+SELECT 'fdwacl' as deftype, COALESCE(gt.rolname, 'public') grantee, g.rolname grantor, array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+    (SELECT
+        d.grantee, d.grantor, d.is_grantable,
+        CASE d.privilege_type
+        WHEN 'USAGE' THEN 'U'
+        ELSE 'UNKNOWN'
+        END AS privilege_type
+    FROM
+        (SELECT fdwacl FROM pg_foreign_data_wrapper fdw
+            LEFT OUTER JOIN pg_shdescription descr ON (
+            fdw.oid=descr.objoid AND descr.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+    WHERE fdw.oid = {{ fid|qtLiteral }}::OID
+{% endif %}
+        ) acl,
+        aclexplode(fdwacl) d
+        ) d
+    LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+    LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql
new file mode 100644
index 0000000..3d81c67
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/create.sql
@@ -0,0 +1,37 @@
+{# ============= Create foreign data wrapper ============= #}
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data.name %}
+CREATE FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}{% if data.fdwvalue %}
+
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }}{%endif%}{% if data.fdwhan %}
+
+    HANDLER {{ conn|qtIdent(data.fdwhan) }}{% endif %}{% if data.fdwoptions %}
+
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+{{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %}){% endif %}
+{% endif %}
+{% endfor %}{% endif %}{%if data %};{%endif%}
+
+{# ============= Set the owner for foreign data wrapper ============= #}
+{% if data.fdwowner %}
+
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Comment on of foreign data wrapper object ============= #}
+{% if data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Create ACL for foreign data wrapper ============= #}
+{% if data.fdwacl %}
+{% for priv in data.fdwacl %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql
new file mode 100644
index 0000000..5677c99
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/delete.sql
@@ -0,0 +1,8 @@
+{# ============= Get foreign data wrapper from fid ============= #}
+{% if fid %}
+SELECT fdwname as name from pg_foreign_data_wrapper WHERE oid={{fid}}::int;
+{% endif %}
+{# ============= Delete/Drop cascade foreign data wrapper ============= #}
+{% if name %}
+DROP FOREIGN DATA WRAPPER {{ conn|qtIdent(name) }} {% if cascade %} CASCADE {% endif %};
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql
new file mode 100644
index 0000000..50d27c6
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/handlers.sql
@@ -0,0 +1,2 @@
+{# ============= Get the handlers of foreign data wrapper ============= #}
+SELECT proname as fdwhan FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE pronargs=0 AND prorettype=3115;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql
new file mode 100644
index 0000000..daede2a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/properties.sql
@@ -0,0 +1,14 @@
+{# ============= Get all the properties of foreign data wrapper ============= #}
+SELECT fdw.oid as fdwoid, fdwname as name, fdwhandler, fdwvalidator, vh.proname as fdwhan, vp.proname as fdwvalue, description,
+    array_to_string(fdwoptions, ',') AS fdwoptions, pg_get_userbyid(fdwowner) as fdwowner, array_to_string(fdwacl::text[], ', ') as acl
+FROM pg_foreign_data_wrapper fdw
+    LEFT OUTER JOIN pg_proc vh on vh.oid=fdwhandler
+    LEFT OUTER JOIN pg_proc vp on vp.oid=fdwvalidator
+    LEFT OUTER JOIN pg_description des ON (des.objoid=fdw.oid AND des.objsubid=0 AND des.classoid='pg_foreign_data_wrapper'::regclass)
+{% if fid %}
+WHERE fdw.oid={{fid}}::int
+{% endif %}
+{% if fname %}
+WHERE fdw.fdwname={{ fname|qtLiteral }}::text
+{% endif %}
+ORDER BY fdwname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql
new file mode 100644
index 0000000..8a1b30b
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/update.sql
@@ -0,0 +1,99 @@
+{% import 'macros/privilege.macros' as PRIVILEGE %}
+{% if data %}
+{# ============= Update foreign data wrapper name ============= #}
+{% if data.name != o_data.name %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(o_data.name) }}
+    RENAME TO {{ conn|qtIdent(data.name) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper owner ============= #}
+{% if data.fdwowner and data.fdwowner != o_data.fdwowner %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OWNER TO {{ conn|qtIdent(data.fdwowner) }};
+
+{% endif %}
+{# ============= Update foreign data wrapper validator ============= #}
+{% if data.fdwvalue and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    VALIDATOR {{ conn|qtIdent(data.fdwvalue) }};
+
+{% endif %}
+{% if data.fdwvalue == '' and data.fdwvalue != o_data.fdwvalue %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO VALIDATOR;
+
+{% endif %}
+{# ============= Update foreign data wrapper handler ============= #}
+{% if data.fdwhan and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    HANDLER {{ conn|qtIdent(data.fdwhan) }};
+
+{% endif %}
+{% if data.fdwhan == '' and data.fdwhan != o_data.fdwhan %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    NO HANDLER;
+
+{% endif %}
+{# ============= Update foreign data wrapper comments ============= #}
+{% if data.description and data.description != o_data.description %}
+COMMENT ON FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    IS {{ data.description|qtLiteral }};
+
+{% endif %}
+{# ============= Update foreign data wrapper options and values ============= #}
+{% if data.fdwoptions and data.fdwoptions.added %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.added %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+ADD {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+
+
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.changed %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.changed %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{% endif %}
+SET {{ conn|qtIdent(variable.fdwoption) }} {{variable.fdwvalue|qtLiteral}}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{%endfor%}
+
+
+{% endif %}
+{% if data.fdwoptions and data.fdwoptions.deleted %}
+{% set addAlter = "False" %}
+{% for variable in data.fdwoptions.deleted %}
+{% if variable.fdwoption and variable.fdwoption != '' %}
+{% if addAlter == "False" %}
+ALTER FOREIGN DATA WRAPPER {{ conn|qtIdent(data.name) }}
+    OPTIONS ({% set addAlter = "True" %}{%endif%}
+DROP {{ conn|qtIdent(variable.fdwoption) }}{% if not loop.last %},{% else %});{% endif %}
+{% endif %}
+{% endfor %}
+
+
+{% endif %}
+{# Change the privileges #}
+{% if data.fdwacl %}
+{% if 'deleted' in data.fdwacl %}
+{% for priv in data.fdwacl.deleted %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }} {% endfor %}
+{% endif %}
+{% if 'changed' in data.fdwacl %}
+{% for priv in data.fdwacl.changed %}
+{{ PRIVILEGE.RESETALL(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name) }}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }} {% endfor %}
+{% endif %}
+{% if 'added' in data.fdwacl %}
+{% for priv in data.fdwacl.added %}
+{{ PRIVILEGE.APPLY(conn, 'FOREIGN DATA WRAPPER', priv.grantee, data.name, priv.without_grant, priv.with_grant) }}{% endfor %}
+{% endif %}
+{% endif %}
+{% endif %}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql
new file mode 100644
index 0000000..6f3d019
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/templates/foreign_data_wrappers/sql/9.3_plus/validators.sql
@@ -0,0 +1,2 @@
+{# ============= Get the validators of foreign data wrapper ============= #}
+SELECT proname as fdwvalue FROM pg_proc p JOIN pg_namespace nsp ON nsp.oid=pronamespace WHERE proargtypes[0]=1009 AND proargtypes[1]=26;
diff --git a/web/pgadmin/browser/server_groups/servers/templates/depends/sql/9.1_plus/dependents.sql b/web/pgadmin/browser/server_groups/servers/templates/depends/sql/9.1_plus/dependents.sql
index 614694b..1a4484c 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/depends/sql/9.1_plus/dependents.sql
+++ b/web/pgadmin/browser/server_groups/servers/templates/depends/sql/9.1_plus/dependents.sql
@@ -8,11 +8,14 @@ SELECT DISTINCT dep.deptype, dep.refclassid, cl.relkind, ad.adbin, ad.adsrc,
         WHEN la.oid IS NOT NULL THEN 'l'::text
         WHEN rw.oid IS NOT NULL THEN 'R'::text
         WHEN co.oid IS NOT NULL THEN 'C'::text || contype
-        WHEN ad.oid IS NOT NULL THEN 'A'::text ELSE ''
+        WHEN ad.oid IS NOT NULL THEN 'A'::text
+        WHEN fs.oid IS NOT NULL THEN 'F'::text
+        WHEN fdw.oid IS NOT NULL THEN 'f'::text
+    ELSE ''
     END AS type,
     COALESCE(coc.relname, clrw.relname) AS ownertable,
     CASE WHEN cl.relname IS NOT NULL OR att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
-    ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
+    ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
     END AS refname,
     COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
 FROM pg_depend dep
@@ -33,10 +36,12 @@ LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
 LEFT JOIN pg_language la ON dep.refobjid=la.oid
 LEFT JOIN pg_namespace ns ON dep.refobjid=ns.oid
 LEFT JOIN pg_attrdef ad ON ad.adrelid=att.attrelid AND ad.adnum=att.attnum
+LEFT JOIN pg_foreign_server fs ON fs.oid=dep.refobjid
+LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.refobjid
 {{where_clause}} AND
 refclassid IN ( SELECT oid FROM pg_class WHERE relname IN
-    ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
-    'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger'))
+   ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
+   'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
 ORDER BY refclassid, cl.relkind
 {% endif %}
 
@@ -57,11 +62,14 @@ SELECT DISTINCT dep.deptype, dep.classid, cl.relkind, ad.adbin, ad.adsrc,
         WHEN la.oid IS NOT NULL THEN 'l'::text
         WHEN rw.oid IS NOT NULL THEN 'R'::text
         WHEN co.oid IS NOT NULL THEN 'C'::text || contype
-        WHEN ad.oid IS NOT NULL THEN 'A'::text ELSE ''
+        WHEN ad.oid IS NOT NULL THEN 'A'::text
+        WHEN fs.oid IS NOT NULL THEN 'F'::text
+        WHEN fdw.oid IS NOT NULL THEN 'f'::text
+        ELSE ''
     END AS type,
     COALESCE(coc.relname, clrw.relname) AS ownertable,
     CASE WHEN cl.relname IS NOT NULL AND att.attname IS NOT NULL THEN cl.relname || '.' || att.attname
-    ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname)
+    ELSE COALESCE(cl.relname, co.conname, pr.proname, tg.tgname, ty.typname, la.lanname, rw.rulename, ns.nspname, fs.srvname, fdw.fdwname)
     END AS refname,
     COALESCE(nsc.nspname, nso.nspname, nsp.nspname, nst.nspname, nsrw.nspname) AS nspname
 FROM pg_depend dep
@@ -82,9 +90,11 @@ LEFT JOIN pg_namespace nsrw ON clrw.relnamespace=nsrw.oid
 LEFT JOIN pg_language la ON dep.objid=la.oid
 LEFT JOIN pg_namespace ns ON dep.objid=ns.oid
 LEFT JOIN pg_attrdef ad ON ad.oid=dep.objid
+LEFT JOIN pg_foreign_server fs ON fs.oid=dep.objid
+LEFT JOIN pg_foreign_data_wrapper fdw ON fdw.oid=dep.objid
 {{where_clause}} AND
 classid IN ( SELECT oid FROM pg_class WHERE relname IN
-    ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
-    'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger'))
+   ('pg_class', 'pg_constraint', 'pg_conversion', 'pg_language', 'pg_proc', 'pg_rewrite', 'pg_namespace',
+   'pg_trigger', 'pg_type', 'pg_attrdef', 'pg_event_trigger', 'pg_foreign_server', 'pg_foreign_data_wrapper'))
 ORDER BY classid, cl.relkind
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py
index e78dc5e..7f525b0 100644
--- a/web/pgadmin/browser/utils.py
+++ b/web/pgadmin/browser/utils.py
@@ -426,6 +426,8 @@ class PGChildNodeView(NodeView):
             'y': 'type',
             'T': 'trigger',
             'l': 'language',
+            'f': 'foreign_data_wrapper',
+            'F': 'foreign_server',
             'R': None,
             'C': None,
             'A': None
diff --git a/web/pgadmin/misc/depends/static/js/depends.js b/web/pgadmin/misc/depends/static/js/depends.js
index ffb8980..97b364c 100644
--- a/web/pgadmin/misc/depends/static/js/depends.js
+++ b/web/pgadmin/misc/depends/static/js/depends.js
@@ -49,7 +49,7 @@ define(
                   (node['node_image']).apply(node, [null, null]) :
                   (node['node_image'] || ('icon-' + res.type))) :
                   ('icon-' + res.type);
-          res.type = S.capitalize(res.type, true);
+          res.type = node['label'] || S.capitalize(res.type, true);
           return res;
         }
       });
@@ -82,7 +82,7 @@ define(
                   cell: Backgrid.Cell.extend({
                     render: function() {
                       Backgrid.Cell.prototype.render.apply(this, arguments);
-                      this.$el.addClass(this.model.get('icon')).css({"padding-left": "18px"});
+                      this.$el.prepend($('<i>', {class: "wcTabIcon " + this.model.get('icon')}));
                       return this;
                     }
                   }),
diff --git a/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js b/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js
index 5734b0b..a6aca11 100644
--- a/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js
+++ b/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js
@@ -117,6 +117,8 @@ function(alertify, S) {
           return;
         }
       }
-      alertify.alert().show().set('message', msg).set('title', promptmsg);
+      alertify.alert().show().set(
+        'message', msg.replace(new RegExp('\r?\n','g'), '<br />')
+        ).set('title', promptmsg);
   };
 });
