Personal tools
You are here: Home Статьи Как использовать xmlrpc c Zope3
Document Actions

Как использовать xmlrpc c Zope3

by cray last modified 2007-11-29 08:15

В статье на простом примере дан краткий рассказ об использовании xmlrpc в Zope3.

Как использовать xmlrpc c Zope3:

XMLRPC - протокол вызова удаленных процедур, использующий в качестве транспорта HTTP, а в качестве метода кодирования - вызовы XML. XML-RPC очень простой протокол, определяющий минимум типов данных и команд: его полное описание может поместится на двух листах бумаги. Основная идея, так же как и у большинства RPC систем - прозрачность удаленного вызова. По хорошо написанному коду трудно понять, какая часть кода выполняется локально, а какая удаленно. В питоне xmlrpc поддерживается библиотекой xmlrpclib, входящей в стандартную поставку.

На самом деле это достаточно просто: как обычно, составляется специальный адаптер, который регистрируется как вид для обращения к xmlrpc, к которому потом при помощи модуля libxmlrpc можно обращатся, чтобы выполнять различные операции.

Постановка задачи :

В качестве простой задачи, напишем утилиту, которая будет подключаться к серверу, просматривать рекурсивно его объекты, отбирать из них заданные атрибуты и передавать некоторой программе, результат обработки которой будет загружается обратно. Такая утилита может пригодится для тестирования или для массового редактирования новостей. Пример в этой статье написан на основе программы pd.subversion.notify, которую можно получить на http://pypi.python.org/pypi

Для начала, программа-клиент (это немного проще):

Текст всей программы-клиента включает в себя много обвязки, поэтому здесь приведен сокращенный вариант - только то, что имеет отношение к делу. Для начала функция просмотра дерева объектов:

              from xmlrpclib import ServerProxy, Error
              from urllib import quote,unquote

              def walk(rpcserver,attributes,klass,interface='zope.interface.Interface') :
                  server = ServerProxy(rpcserver)
                  if not klass or klass == server.klass() : 
                      if server.check(interface) :
                          for attr in attributes :
                              yield (rpcserver,server,attr)

                  for item in server.keys() :
                      for x in walk(rpcserver + "/" + item,attributes,klass,interface) :
                          yield x

Немного поясним. Данная функция работает с гипотетическим "интерфейсом" удаленного объекта (в обобщенном смысле слова), который предоставляет функции просмотра и редактирования атрибутов, а также возможность просмотра контейнера (если он контейнер, не контейнер рассматривается как пустой контейнер).

Чтобы в дальнейшем обрабатывать найденные атрибуты, потребуется такой код:

            for (path,server,attr) in walk(rpcserver,attributes,klass,interface) :
                value = server.getattr(interface,attr) 
                fn=tempfile.mktemp()
                open(fn,"w").write(value)
                os.system(execute % {"name":fn })
                value = open(fn,"r").read()
                server.setattr(interface,attr,value)

Этот код делает итерацию по найденным коннекторам к объектам, после чего запускает внешнюю программую для их обработки. Мы используем system, а не popen, потому что такие у нас программы :), ваш выбор может быть другим.

Ключевая фраза во всем параграфе выше - это вызов xmlrpclib.ServerProxy(url). Если требуется пароль для доступа к серверу, указывайте url вот так:

            http://<ИМЯ>:<ПАРОЛЬ>@<САЙТ>/<ПУТЬ>, например:

            http://theuser:[email protected]/about

Серверная часть:

Вообще, в смысле компонентной модели, стоило бы для серверной части, для каждого объекта со своими интерфейсами сделать свой адаптер и таким образом все реализовать. В нашем случае мы пока пошли простым путем: реализовали универсальный xmlrpc-вид, который более-менее разбирается с интерфейсами объекта, который он предоставляет.

С точки зрения архитектуры Zope, xmlrpc-вид - это адаптер от пары:

            (for_, IXMLRPCRequest)

где for_ - это интерфейс объекта, который обслуживается этим видом.

Получаемый интерфейс:

Interface

Если при регистрации вида использовался параметр interface, то он будет использован только для настройки методов и выдачи прав, а результатом адаптации все равно останется Interface, что, впрочем, также, как и для других видов.

Использование всего этого можно увидеть в :

zope/app/publisher/xmlrpc
регистрация и работа директив;
zope/publisher/xmlrpc.py
определение xmlrpc запроса и ответа;

Исходный код xmlrpc-вида приведен ниже:

            class XMLRPCEdit(object) :

                def getattr(self,interface,name) :
                    """ Вернуть значение атрибута после адаптирования к указанному интерфейсу """
                    return getattr(nameToInterface(self.context,interface)(self.context),name) or ""                   

                def setattr(self,interface,name,value) :
                    """ Установить значение атрибута после адаптирования к указанному интерфейсу """
                    setattr(nameToInterface(self.context,interface)(self.context),name,value) 
                    notify(ObjectModifiedEvent(self.context))

                def keys(self) :
                    """ Вернуть список вложенных объектов """
                    if IContainer.providedBy(self.context) :
                        return list(IContainer(self.context).keys())
                    return []                        

                def klass(self) :
                    """ Вернуть название класса """
                    ob = removeSecurityProxy(self.context)
                    return ob.__class__.__module__ + "." + ob.__class__.__name__

                def check(self,interface) :
                    """ Проверить возможность адаптации к интерфейсу """
                    try :
                        nameToInterface(self.context,interface)(self.context)
                    except TypeError,msg :
                        return False
                    return  True

                __nonzero__ = True

Регистрируется вид следующим образом:

            <xmlrpc:view
                for="*"
                permission="zope.ManageContent"
                class=".xmlrpcedit.XMLRPCEdit"
                methods="getattr setattr keys klass check"
                />

В атрибуте methods должны быть зарегистрированы все методы, которые будут использовать xmlrpc-клиенты через этот вид. Если имя вида не указано, то для каждого метода будет создан, грубо говоря, свой собственныей вид, поэтому на самом деле образуется сложная смесь методов. Это не очень хорошо, но легко реализуется. Вместо перечисления методов можно, как вариант, указать интерфейс, в котором эти методы описаны.

Заключение:

Основное назначение xmlrpc написание толстых клиентов, взаимодействующих с сервером, чтобы проверить данные на нем или еще что-то в этом роде. В качестве примера сошлемся на две программы, написанные с использованием xmlrpc:

ng.xmlrpcscan
программа, на примере которой написана эта статья, и которая реально используется для проверки орфографии;
pd.subversion.notify
программа, пересылающая заметки о изменениях сабвершена "куда надо".

Хотелось бы увидеть "толстый" визуальный редактор, действующий через xmlrpc, но пока такого не видно.


Powered by Plone CMS, the Open Source Content Management System