protected function init_service_class() {
        global $USER, $DB;

        // Initialise service methods and struct classes.
        $this->servicemethods = array();
        $this->servicestructs = array();

        $params = array();
        $wscond1 = '';
        $wscond2 = '';
        if ($this->restricted_serviceid) {
            $params = array('sid1' => $this->restricted_serviceid, 'sid2' => $this->restricted_serviceid);
            $wscond1 = 'AND s.id = :sid1';
            $wscond2 = 'AND s.id = :sid2';
        }

        $sql = "SELECT s.*, NULL AS iprestriction
                  FROM {external_services} s
                  JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0)
                 WHERE s.enabled = 1 $wscond1

                 UNION

                SELECT s.*, su.iprestriction
                  FROM {external_services} s
                  JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1)
                  JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)
                 WHERE s.enabled = 1 AND (su.validuntil IS NULL OR su.validuntil < :now) $wscond2";
        $params = array_merge($params, array('userid' => $USER->id, 'now' => time()));

        $serviceids = array();
        $remoteaddr = getremoteaddr();

        // Query list of external services for the user.
        $rs = $DB->get_recordset_sql($sql, $params);

        // Check which service ID to include.
        foreach ($rs as $service) {
            if (isset($serviceids[$service->id])) {
                continue; // Service already added.
            }
            if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) {
                continue; // Cap required, sorry.
            }
            if ($service->iprestriction and !address_in_subnet($remoteaddr, $service->iprestriction)) {
                continue; // Wrong request source ip, sorry.
            }
            $serviceids[$service->id] = $service->id;
        }
        $rs->close();

        // Generate the virtual class name.
        $classname = 'webservices_virtual_class_000000';
        while (class_exists($classname)) {
            $classname++;
        }
        $this->serviceclass = $classname;

        // Get the list of all available external functions.
        $wsmanager = new webservice();
        $functions = $wsmanager->get_external_functions($serviceids);

        // Generate code for the virtual methods for this web service.
        $methods = '';
        foreach ($functions as $function) {
            $methods .= $this->get_virtual_method_code($function);
        }

        $code = <<<EOD
/**
 * Virtual class web services for user id $USER->id in context {$this->restricted_context->id}.
 */
class $classname {
$methods
}
EOD;
        // Load the virtual class definition into memory.
        eval($code);
    }