def HandleLocalTransferRequest(self, request, response):
        """Handles Local Transferring request.

    Args:
      request: request object.
      response: response object.
    Raises:
      SearchPushServeException, psycopg2.Warning/Error.
    """
        logger.debug("HandleLocalTransferRequest...")
        src_path = request.GetParameter(constants.FILE_PATH)
        dest_path = request.GetParameter(constants.DEST_FILE_PATH)

        if (not src_path) or (not dest_path):
            raise exceptions.SearchPushServeException(
                "HandleLocalTransferRequest: Missing src/dest paths")

        src_path = os.path.normpath(src_path)
        dest_path = os.path.normpath(dest_path)
        logger.debug("HandleLocalTransferRequest: %s to %s", src_path,
                     dest_path)

        force_copy = request.IsForceCopy()
        prefer_copy = request.IsPreferCopy()
        if serve_utils.LocalTransfer(src_path, dest_path, force_copy,
                                     prefer_copy, self.allow_symlinks):
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        else:
            raise exceptions.SearchPushServeException(
                "Local transfer FAILED: from %s to %s" % (src_path, dest_path))
    def HandleSyncRequest(self, request, response):
        """Handles database sync request.

    Args:
      request: request object.
      response: response object.
    Returns:
      in response object, the list of files that need to be transfered.
    Raises:
      SearchPushServeException in case of invalid database.
    """
        logger.debug("HandleSyncRequest...")
        client_host_name = request.GetClientHostName()
        if not client_host_name:
            raise exceptions.SearchPushServeException(
                "HandleSyncRequest: missing Hostname.")

        db_name = request.GetParameter(constants.DB_NAME)
        if not db_name:
            raise exceptions.SearchPushServeException(
                "HandleSyncRequest: missing database name.")

        # Difference between stream and search publishers. The search publisher
        # does not care if the database does not exist coz there may be
        # no POI files to sync.
        db_id = self.QueryDbId(client_host_name, db_name)
        if db_id == 0:
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
            return

        transfer_file_paths = self.__SynchronizeDb(db_id, client_host_name)
        if not transfer_file_paths:
            # All the DB files are pushed, return success.
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        else:
            # Put in response files that need to be transferred on server and return
            # the status 'upload needed'.
            for transfer_file_path in transfer_file_paths:
                http_io.ResponseWriter.AddBodyElement(response,
                                                      constants.HDR_FILE_NAME,
                                                      transfer_file_path)

            http_io.ResponseWriter.AddBodyElement(
                response, constants.HDR_STATUS_CODE,
                constants.STATUS_UPLOAD_NEEDED)
    def __ReadDavConfig(self):
        """Reads WebDAV config (server_prefix)."""
        sub_groups = utils.MatchPattern(SearchPushManager.DAV_CONF_PATH,
                                        "^Alias\\s+/search_space\\s+(.*)")
        if sub_groups:
            self.server_prefix = sub_groups[0]

        if not self.server_prefix:
            raise exceptions.SearchPushServeException(
                "Unable to read WebDAV Config.")
        logger.info("Server Prefix: " + self.server_prefix)
    def HandleDeleteDbRequest(self, request, response):
        """Handles delete database request.

    Args:
      request: request object.
      response: response object.

    Raises:
      SearchPushServeException, psycopg2.Warning/Error.
    """
        logger.debug("HandleDeleteDbRequest...")
        client_host_name = request.GetClientHostName()
        if not client_host_name:
            raise exceptions.SearchPushServeException(
                "HandleDeleteDbRequest: missing Hostname.")

        db_name = request.GetParameter(constants.DB_NAME)
        if not db_name:
            raise exceptions.SearchPushServeException(
                "HandleDeleteDbRequest: missing database name.")

        # Check if the database exists. If it doesn't then just return success.
        db_id = self.QueryDbId(client_host_name, db_name)
        if db_id == 0:
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
            return

        # Delete the db_poi mappings. The POI tables are not deleted.
        # These will be garbage collected at the request of the user.
        query_string = "DELETE FROM db_poi_table WHERE db_id = %s"
        self._DbModify(query_string, (db_id, ))

        # Delete the entry in db_table.
        query_string = "DELETE FROM db_table WHERE db_id = %s"
        self._DbModify(query_string, (db_id, ))

        http_io.ResponseWriter.AddBodyElement(response,
                                              constants.HDR_STATUS_CODE,
                                              constants.STATUS_SUCCESS)
 def __ReadPublishRootConfig(self):
     self.allow_symlinks = "N"
     config_path = os.path.join(os.path.dirname(self.server_prefix),
                                ".config")
     try:
         # Older publish roots may not have the .config file so we default to "N".
         if os.path.exists(config_path):
             sub_groups = utils.MatchPattern(
                 config_path, "^AllowSymLinks:\\s*([YyNn])\\s*$")
             if sub_groups:
                 self.allow_symlinks = sub_groups[0]
             else:
                 raise exceptions.SearchPushServeException(
                     "Invalid Publish root config.")
     finally:
         logger.info("AllowSymlinks: " + self.allow_symlinks)
    def HandleQueryRequest(self, request, response):
        """Handles query requests.

    Args:
      request: request object.
      response: response object
    Raises:
      SearchPushServeException, psycopg2.Error/Warning.
    """
        query_cmd = request.GetParameter(constants.QUERY_CMD)
        if not query_cmd:
            raise exceptions.SearchPushServeException(
                "Internal Error - Missing Query Command.")

        if query_cmd == constants.QUERY_CMD_LIST_DBS:
            # List all DBs registered on the server.
            query_string = "SELECT host_name, db_name, db_pretty_name FROM db_table"
            results = self._DbQuery(query_string)
            for line in results:
                http_io.ResponseWriter.AddBodyElement(response,
                                                      constants.HDR_HOST_NAME,
                                                      line[0])
                http_io.ResponseWriter.AddBodyElement(response,
                                                      constants.HDR_DB_NAME,
                                                      line[1])
                http_io.ResponseWriter.AddBodyElement(
                    response, constants.HDR_DB_PRETTY_NAME, line[2])

            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        elif query_cmd == constants.QUERY_CMD_DB_DETAILS:
            # Preview details for a specific DB.
            db_name = request.GetParameter(constants.DB_NAME)
            if not db_name:
                raise exceptions.SearchPushServeException(
                    "HandleQueryRequest: missing database name.")
            client_host_name = request.GetClientHostName()
            if not client_host_name:
                raise exceptions.SearchPushServeException(
                    "HandleQueryRequest: missing Hostname.")
            # TODO: implement db details request handling:
            # maybe return list of poi tables.

            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        elif query_cmd == constants.QUERY_CMD_SERVER_PREFIX:
            # Get server prefix - path to search space directory.
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_SERVER_PREFIX,
                                                  self.server_prefix)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        elif query_cmd == constants.QUERY_CMD_HOST_ROOT:
            # Host root is the top-level directory where a particular fusion client
            # host will put its files. Currently this is the same as host name but
            # we might set it to whatever we want.
            client_host_name = request.GetClientHostName()
            if not client_host_name:
                raise exceptions.SearchPushServeException(
                    "HandleQueryRequest: missing Hostname.")

            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_HOST_ROOT,
                                                  client_host_name)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        elif query_cmd == constants.QUERY_CMD_SERVER_HOST:
            # Get server host name.
            host_name = socket.gethostname()
            full_host_name = socket.getfqdn()
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_SERVER_HOST,
                                                  host_name)
            http_io.ResponseWriter.AddBodyElement(
                response, constants.HDR_SERVER_HOST_FULL, full_host_name)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        elif query_cmd == constants.QUERY_CMD_ALLOW_SYM_LINKS:
            # Get allow symbolic links status.
            http_io.ResponseWriter.AddBodyElement(
                response, constants.HDR_ALLOW_SYM_LINKS, self.allow_symlinks)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
        else:
            raise exceptions.SearchPushServeException(
                "Internal Error - Invalid Query Command: %s." % query_cmd)
    def HandleAddDbRequest(self, request, response):
        """Handles add database request.

    Args:
      request: request object.
      response: response object.

    Raises:
      SearchPushServeException, psycopg2.Warning/Error.
    """
        logger.debug("HandleAddDbRequest...")
        client_host_name = request.GetClientHostName()
        if not client_host_name:
            raise exceptions.SearchPushServeException(
                "HandleAddDbRequest: missing Hostname.")

        db_name = request.GetParameter(constants.DB_NAME)
        db_pretty_name = request.GetParameter(constants.DB_PRETTY_NAME)
        if not db_name:
            raise exceptions.SearchPushServeException(
                "HandleAddDbRequest: missing database name.")

        if not db_pretty_name:
            raise exceptions.SearchPushServeException(
                "HandleAddDbRequest: missing pretty database name.")

        poi_file_paths = request.GetMultiPartParameter(constants.FILE_PATH)
        poi_file_sizes = request.GetMultiPartParameter(constants.FILE_SIZE)

        if ((poi_file_paths and (not poi_file_sizes))
                or ((not poi_file_paths) and poi_file_sizes)):
            raise exceptions.SearchPushServeException(
                "Internal Error - HandleAddDbRequest: missing file paths or sizes"
            )

        if len(poi_file_paths) != len(poi_file_sizes):
            raise exceptions.SearchPushServeException(
                "Internal Error - HandleAddDbRequest:"
                " poi file_paths/file_sizes mismatch: %d/%d" %
                (len(poi_file_paths), len(poi_file_sizes)))

        logger.debug("poi_file_paths: %s", str(poi_file_paths))
        logger.debug("poi_file_sizes: %s", str(poi_file_sizes))

        # Check if database already exists.
        # The assumption is if it already exists, all the files and db-to-files
        # links have already been pushed to the database.
        db_id = self.QueryDbId(client_host_name, db_name)
        logger.debug("HandleAddDbRequest: db_id: %d", db_id)

        if db_id > 0:
            # It's ok if the database already exists. Don't throw an exception.
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_CODE,
                                                  constants.STATUS_SUCCESS)
            return

        # We will now add the following entries into the db:
        # 1) the db_table entry for the database
        # 2) the poi_table entries for each poi  file path
        # 3) the db_poi_table entries linking each file to this database

        # TODO: If anything fails, we want to remove
        # the db_table entry and db_poi_table entries
        # so that publish will start from this point on the next try.

        # Add the db entry.
        query_string = (
            "INSERT INTO db_table (host_name, db_name, db_pretty_name) "
            "VALUES(%s, %s, %s)")

        self._DbModify(query_string,
                       (client_host_name, db_name, db_pretty_name))

        db_id = self.QueryDbId(client_host_name, db_name)
        if db_id == 0:
            raise exceptions.SearchPushServeException(
                "HandleAddDbRequest: unable to add database")

        insert_into_poi_table = (
            "INSERT INTO poi_table "
            "(query_str, style, num_fields, host_name, "
            "poi_file_path, poi_file_size, status) "
            "VALUES('empty query', 'empty_style', 0, %s, %s, %s, 0)")
        insert_into_db_poi_table = ("INSERT INTO db_poi_table (db_id, poi_id) "
                                    "VALUES(%s, %s)")

        # Add entries for the poi_table and db_poi_table.
        for i in xrange(len(poi_file_paths)):
            # See if the search table entry already exists.
            poi_id = self._QueryPoiId(client_host_name, poi_file_paths[i])
            if poi_id == 0:
                # Add POI table entry.
                self._DbModify(
                    insert_into_poi_table,
                    (client_host_name, poi_file_paths[i], poi_file_sizes[i]))
                poi_id = self._QueryPoiId(client_host_name, poi_file_paths[i])
                logger.debug("inserted %s into poi_table with id of %d",
                             poi_file_paths[i], poi_id)

            assert poi_id != 0
            # Add db_poi mapping table entry.
            self._DbModify(insert_into_db_poi_table, (db_id, poi_id))

        http_io.ResponseWriter.AddBodyElement(response,
                                              constants.HDR_STATUS_CODE,
                                              constants.STATUS_SUCCESS)
    def DoGet(self, request, response):
        """Handles request by delegating it to search push manager."""
        # Check for init failure and return an error status and appropriate message.
        if not self._search_push_manager:
            if response:
                http_io.ResponseWriter.AddBodyElement(
                    response, constants.HDR_STATUS_MESSAGE,
                    "Server-side Internal Error: Failure to init SearchPusher")
                http_io.ResponseWriter.AddBodyElement(
                    response, constants.HDR_STATUS_CODE,
                    constants.STATUS_FAILURE)

            return

        try:
            cmd = request.GetParameter(constants.CMD)

            if not cmd:
                raise exceptions.StreamPublisherServletException(
                    "Internal Error - Missing Request Command.")

            # Handle query requests.
            if cmd == constants.CMD_QUERY:
                self._search_push_manager.HandleQueryRequest(request, response)
            # Handle gesearch DB ping request.
            elif cmd == constants.CMD_PING:
                self._search_push_manager.HandlePingRequest(request, response)
            # Handle registering DB request.
            elif cmd == constants.CMD_ADD_DB:
                self._search_push_manager.HandleAddDbRequest(request, response)
            # Handle delete DB request.
            elif cmd == constants.CMD_DELETE_DB:
                self._search_push_manager.HandleDeleteDbRequest(
                    request, response)
            # Handle sync DB request (pushing search data and creating poi tables).
            elif cmd == constants.CMD_SYNC_DB:
                self._search_push_manager.HandleSyncRequest(request, response)
            # Deprecated.
            elif cmd == constants.CMD_PUBLISH_DB:
                # Note: Search data publishing is deprecated after 5.0.1. Return
                # success to keep compatibility between Fusion 5.0.1 and Server 5.0.2
                # and later versions.
                http_io.ResponseWriter.AddBodyElement(
                    response, constants.HDR_STATUS_CODE,
                    constants.STATUS_SUCCESS)
            # Handle garbage collecting request - deleting not used files from
            # publish assetroot and cleaning up postgres tables.
            elif cmd == constants.CMD_GARBAGE_COLLECT:
                self._search_push_manager.HandleGarbageCollectRequest(
                    request, response)
            # Handle file transferring request.
            elif cmd == constants.CMD_LOCAL_TRANSFER:
                self._search_push_manager.HandleLocalTransferRequest(
                    request, response)
            else:
                raise exceptions.SearchPushServeException(
                    "Internal Error - Invalid Request Command: %s." % cmd)
            return
        except exceptions.SearchPushServeException as e:
            logger.error(e)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_MESSAGE,
                                                  e)
        except (psycopg2.Warning, psycopg2.Error) as e:
            logger.error(e)
            http_io.ResponseWriter.AddBodyElement(response,
                                                  constants.HDR_STATUS_MESSAGE,
                                                  e)
        except Exception as e:
            logger.error(e)
            http_io.ResponseWriter.AddBodyElement(
                response, constants.HDR_STATUS_MESSAGE,
                "Server-side Internal Error")

        # Set failure status whether we reach this point.
        http_io.ResponseWriter.AddBodyElement(response,
                                              constants.HDR_STATUS_CODE,
                                              constants.STATUS_FAILURE)