Glasnost

Exemple de création d'un nouveau serveur

Le but de cet exemple est de montrer toutes les actions à faire pour créer un serveur simple. Le serveur que nous allons faire permet de gérer les contacts. Pour un contact nous aurons son nom, son prénom, son adresse mail et son numéro de téléphone. Nous pourrons ensuite créer de nouveau contact, en supprimer et en modifier.

Note: pour un tel exemple, utiliser le CardsServer est une meilleure solution dans la pratique.

Nous nous placerons dans le cas où Glasnost est installé et que le serveur contact est en fonctionnement. Tous les fichiers sont donc ceux que l'on trouve après une installation de Glasnost, et non pas ceux que l'on a dans les sources du projet.

Le fichier /usr/lib/python2.1/site-packages/glasnost/common/ContactsCommon.py contient le code commun au server et au proxy

__doc__ = """Glasnost Contacts Common Models"""

__version__ = '0.5.4'

from ObjectsCommon import AdminCommon, ObjectCommon

class AdminContactsCommon(AdminCommon):
    pass


class ContactCommon(ObjectCommon):
    name = None
    name_kind_isPublicForXmlRpc = 1
    name_kind_isRequired = 1
    name_kindName = 'String'

    firstname = None
    firstname_kind_isPublicForXmlRpc = 1
    firstname_kind_isRequired = 0
    firstname_kindName = 'String'

    email = None
    email_kind_isPublicForXmlRpc = 1
    email_kind_isRequired = 0
    email_kindName = 'String'

    phone = None
    phone_kind_isPublicForXmlRpc = 1
    phone_kind_isRequired = 0
    phone_kindName = 'String'

    readersSet = None
    readersSet_kind_isPublicForXmlRpc = 1
    readersSet_kind_item_kindName = 'Id'
    readersSet_kind_item_kind_serverRoles = ['groups', 'people']
    readersSet_kindName = 'Sequence'

    writersSet = None
    writersSet_kind_isPublicForXmlRpc = 1
    writersSet_kind_item_kindName = 'Id'
    writersSet_kind_item_kind_serverRoles = ['groups', 'people']
    writersSet_kind_requiredCount = 1
    writersSet_kindName = 'Sequence'

    def canCache(self):
        return 1

    def getLabel(self):
        label = self.name
        if label is None:
            return ''
        return label

Le fichier /usr/lib/glasnost/servers/ContactsServer/ContactsServer.py contient le code server.

#!/usr/bin/env python

__version__ = '0.5.4'

import __builtin__
__builtin__.__dict__['_'] = lambda x: x
__builtin__.__dict__['N_'] = lambda x: x

import time

from glasnost.common.faults import *
from glasnost.common.ContactsCommon import *
from glasnost.server.ObjectsServer import ObjectServerMixin, AdminServerMixin, ObjectsServer
from glasnost.server.things import register

applicationName = 'ContactsServer'
applicationRole = 'contacts'   # all time in lowercase
applicationTokens = None
dispatcher = None

class AdminContacts(AdminServerMixin, AdminContactsCommon):
    pass
register(AdminContacts)

class Contact(ObjectServerMixin, ContactCommon):
    pass
register(Contact)

class ContactsServer(ObjectsServer):
    Admin = AdminContacts
    useAdminWritersSet = 1
    useModificationTime = 1
    useReadersSet = 1
    useWritersSet = 1
    version = __version__

    def deleteAll(self, virtualServerId, applicationToken, userToken):
        if not self.isAdmin(virtualServerId, userToken):
            raise FaultUserAccessDenied()
        //put code here

    def registerXmlRpcMethods(self):
        ObjectsServer.registerXmlRpcMethods(self)
        self.registerXmlRpcMethod('deleteAll')
        
contactsServer = ContactsServer()

if __name__ == "__main__":
    contactsServer.launch(applicationName, applicationRole)

Dans ce serveur nous avons commencé la méthode deleteAll, qui vérifie que la personne qui essaie de tout supprimer en a les droits. Le code qui supprime réellement tous les contacts n'a pas été fait pour que cet exemple reste simple. Une fois notre méthode écrite il faut l'enregistrer pour que le proxy puisse l'utiliser, ceci se fait par la méthode registerXmlRpcMethod.

Le fichier /usr/lib/python2.1/site-packages/glasnost/proxy/ContactsProxy.py contient le code du proxy.

__doc__ = """Glasnost Contacts Proxy"""

__version__ = '0.5.4'

from glasnost.common.ContactsCommon import *

from DispatcherProxy import callServer, getApplicationToken
from ObjectsProxy import register, ObjectsProxy, ObjectProxyMixin
from tools import *



class AdminContacts(AdminContactsCommon):
    pass
register(AdminContacts)


class Contact(ObjectProxyMixin, ContactCommon):
    def getProxy(self):
        return contactsProxy
register(Contact)


class ContactsProxy(ObjectsProxy):
    adminClassName = 'AdminContacts'
    objectClassName = 'Contact'
    objectIdName = 'contactId'
    objectName = N_('contact')
    objectNameCapitalized = N_('Contact')
    objectsName = N_('contacts')
    objectsNameCapitalized = N_('Contacts')
    serverRole = 'contacts'

    def deleteAll(self, userToken, context = None, serverId = None):
        serverId = self.getServerId(context=context, serverId=serverId)
        callServer(serverId, 'deleteAll',
            [serverId, getApplicationToken(context=context), userToken])


contactsProxy = ContactsProxy()

Le fichier /usr/lib/python2.1/site-packages/glasnost/web/ContactsWeb.py ontient le code du web.

__doc__ = """Glasnost Contacts Web"""

__version__ = '0.5.4'

from glasnost.proxy.ContactsProxy import *
from ObjectsWeb import register, AdminMixin, ObjectWebMixin, ObjectsWebMixin

class AdminContacts(AdminMixin, AdminContacts):
    pass
register(AdminContacts)


class Contact(ObjectWebMixin, Contact):
    name_kind_widget_fieldLabel = N_('Name')
    name_kind_widget_size = 40
    name_kind_widgetName = 'InputText'

    firstname_kind_widget_fieldLabel = N_('Firstname')
    firstname_kind_widget_size = 40
    firstname_kind_widgetName = 'InputText'

    email_kind_widget_fieldLabel = N_('Email')
    email_kind_widget_size = 40
    email_kind_widgetName = 'InputText'

    phone_kind_widget_fieldLabel = N_('Phone')
    phone_kind_widget_size = 40
    phone_kind_widgetName = 'InputText'

    readersSet_kind_item_kind_defaultValue = 'user'
    readersSet_kind_item_kind_widget_noneLabel = N_('Everybody')
    readersSet_kind_item_kind_widgetName = 'SelectId'
    readersSet_kind_widget_fieldLabel = N_('Reader')
    readersSet_kind_widget_fieldLabelPlural = N_('Readers')
    readersSet_kind_widgetName = 'Multi'

    writersSet_kind_item_kind_defaultValue = 'user'
    writersSet_kind_item_kind_widgetName = 'SelectId'
    writersSet_kind_widget_fieldLabel = N_('Writer')
    writersSet_kind_widget_fieldLabelPlural = N_('Writers')
    writersSet_kind_widgetName = 'Multi'

register(Contact)


class ContactsWeb(ObjectsWebMixin, ContactsProxy):
    adminClass = AdminContacts


contactsWeb = ContactsWeb()

En plus de nos champs, on définit aussi les champs writers et readers. Sans cela nous ne pourrions pas mettre des droits particuliers pour chaque fiche contact.

Il nous reste maintenant à modifier quelques fichiers pour que notre serveur soit pris en compte dans l'application.

Ouvrez le fichier /usr/lib/python2.1/site-packages/glasnost/web/tools.py, et modifiez la fonction getServerRoleAndIdNameFromModuleName pour lui ajouter la ligne:

        'contacts': ('contacts', 'contactId'),

Dans le même fichier, dans la fonction getWebForServerRole ajouter la ligne

    from ContactsWeb import contactsWeb

Ouvrez le fichier /usr/lib/python2.1/site-packages/glasnost/proxy/tools_new.py et modifiez la fonction getAllBaseProxies pour lui ajouter la ligne:

    from ContactsProxy import contactsProxy

Il nous reste maintenant le fichier de configuration de Glasnost à modifier pour indiquer qu'il existe un nouveau serveur. Ouvrez le fichier /etc/glasnost/config et à la fin de ce fichier ajouté une entrée pour votre serveur comme ceci:

[ContactsServer]
ServerHostName = localhost
ServerPort = 8030

Vous devrez sûrement choisir un autre serverPort que le 8030, car il sera sûrement déjà utilisé par un autre serveur Glasnost.

Voila, vous venez de finir, il ne vous reste plus qu'à redémarrer Glasnost et le serveur web.

/etc/init.d/glasnost restart ; /etc/init.d/apache restart