SOA Services

De Wiki Expresso V3
Ir para: navegação, pesquisa

Conteúdo

Introdução

O ExpressoBr introduz uma nova tecnologia agregada ao ambiente colaborativo. É sua capacidade de disponibilização de serviços através de uma camada de serviços, permitindo com isto que outras aplicações atuem como cliente e possam com isso conectarem-se aos serviços oferecidos pelo ExpressoBr.

Com a arquitetura voltada a serviços a interoperabilidade, desempenho e conectividade são afetados direta e positivamente. Com ela é possível oferecer um desktop como a aplicação, capaz de gerenciar dados de diferentes serviços.

O cliente pré-desenvolvido e distribuído com ExpressoBr é o cliente JavaScript suportado sob o framework ExtJs.

Resumidamente o ExpressoBr é dividido em duas camadas de componentes quase que totalmente independentes:

Service Provider

Um componente servidor que atua como prestador de serviços para o cliente. Diferente de outros fornecedores de colaboração com interfaces web, o ExpressoBr não entrega HTML para seus clientes. O backend php, baseado no Zend Framework atua no webserver e representa esta camada do serviço. O service provider cria um web service e possibilita a publicação da interface de acesso que o serviço possui. Cada provider deve decidir que serviços ele irá expor e em que níveis. Por exemplo, um determinado serviço somente poderá ser exposto caso o usuário requisite o serviço de login previamente. Ou mesmo uma determinada funcionalidade de um módulo somente poderá ser exposta caso o usuário logado anteriormente possua privilégios suficientes de acesso.

Service Consumer

Para o ExpressoBr o client é constituído de uma plataforma Javascript. A grande vantagem é que ele pode ser executado em qualquer navegador padrão. Para este javascript, o servidor HTTP funciona como um servidor de aplicativos para o primeiro pedido e todos os pedidos seguintes são transferidos usando o protocolo JSON apenas com a troca de dados e não mais html inteiro, aliviando com isto consideravelmente a performance e tráfego de in formações na rede. O frontend javascript é baseado no framework Extjs e executado nos browses dos usuários representando esta camada do client. Este cliente pode ser um componente GUI para interação com os usuários ou mesmo outro sistema requisitando algum dado, em alguma linguagem que suporte o protocolo Json.

Arquitetura

Fluxo de requisições Json

Fluxo de chamada de serviços JSON:

index.php 

	Tinebase_Core.php 

	Se Request: 

		Content_type='application/Json' ou HTTP_X_TINE2-_REQUEST_TYPE='JSON' ou Request_Type='JSON' 

	Tinebase_Server_Json.php 

	Se metodo vazio aciona getServiceMAP() para mapeamento dos serviços 

	Pega o TineBase 

	Pega as aplicações 

	checa chave HTTTP_X_TINE20_JSONKEY 

	check_Json_key($method,$jsonkey) 

	checa se metodos anomimos 

Frontend_Json.php --> metodo

Ao Tinebase

Basicamente o fluxo de requests passa pelas seguintes etapas:


$_REQUEST => index.php => Tinebase_Controller->handle() => JSON ou HTTP 
Caso o $_REQUEST['method'] estiver setado e a requisição for uma requisição jsonrpc o Json do tinebase será acionado: ../Tinebase/Json.php
Caso contrário o request http-Server normal será acionado: ../Tinebase/Frontend/Http.php
Um método consiste em duas partes: APPLICATION.FUNCTION.  A parte FUNCTION é o nome da função a ser chamada no servidor JSON ou HTTP .

JSON Login

Requisição para JSON ao Tinebase-Login

Para o login o cliente passa os argumentos: - o tipo de request "jsonrpc":"2.0"; - o metodo Tinebase.login; - username; - password. Por tratar-se de login, quem oferece este serviço é o Tinebase, portanto na estrutura de diretório …/Tinebase/Frontend encontra-se o Json.php que irá tratar todas as requisições Json, incluindo a função publica login que recebe como parâmetros username e password.

Exemplo:
--> {
   "jsonrpc":"2.0",
   "method":"Tinebase.login",
   "params": {
       "username":"tine20admin",
       "password":"lars"
   },
   "id":2
}

Resposta do JSON Tinebase-Login

Caso você tenha a possibilidade de ver o arquivo ../Tinebase/Frontend/Json.php verificará que existe nele uma função publica que retornará uma menssagem de boas vindas "welcomeMessage": "Welcome to Tine 2.0!" e "success":true indicando que o login fora bem sucedido. Juntamente com a resposta é passada um chave denominada jsonKey, que será a chave de persistência deste login para chamadas a metodos e funções subsequentes.

Exemplo:
<-- {
"id":"2",
"jsonrpc":"2.0",
"result":{
   "success":true,
   "account": {
       "accountId":"0e7d07cb453b15f520021e0a433956b234a7c0bd",
       "accountDisplayName":"Admin Account, Tine 2.0",
       "accountLastName":"Admin Account",
       "accountFirstName":"Tine 2.0",
       "accountFullName":"Tine 2.0 Admin Account",
       "contact_id":"1"
   },
   "jsonKey":"85160b59b4421bbe2f350c5b3888a2efdbfcb949",
   "welcomeMessage":"Welcome to Tine 2.0!"
}}


JSON-RPC

Estes dois níveis de comunicação, client e server, comunicam-se sob a especificação do protocolo JSON-RPC[1]. O Expresso3.0 suporta JSON-RPC version 2.0. O JSON-RPC é muito fácil de ser implementado, existem implementações sob várias linguagens com JavaScript, Php, Java, Ruby, Pyton ou Perl. O cliente disponibilizado com o Expresso3.0 também suporta JSON/SMD, que será abordado adiante.

Estrutura de diretórios

Fisicamente, no server frontend, a arquitetura JSON da aplicação se encontra sob estrutura de diretório com o nome da aplicação chamante, neste caso representada por Application_Name:

Application_Name/Frontend/Json.php  

Json Frontend

Com esta abstração de frontend json, torna-se muito simples criar-se um serviço json para uma aplicação. Esta classe representa uma API publica de sua aplicação e poderá ser usada por requisições AJAX do Javascript(cliente default do ExpressoV3). Tudo o que é necessário é estabelecer o nome da aplicação no constructor e definir as funções basicas para search/delete/get/save + model name na sua classe. Estas funções chamam uma função genérica na classe Tinebase_Frontend_Json_Abstract.

Exemplo: FRONTEND JSON(server php)

…/Application/Frontend/Json.php: 
/**
*
* This class handles all Json requests for the application
*
* @package     Application
* @subpackage  Frontend
*/
class Application_Frontend_Json extends Tinebase_Frontend_Json_Abstract
{    
   /**
   * controller
   *
   * @var Application_Controller_Record
   */
  protected $_recordController = NULL;
  /**
   * the constructor
   *
   */
  public function __construct()
  {
      $this->_applicationName = 'Application';
      $this->_recordController = Application_Controller_Record::getInstance();
  }
  /**
   * Search for records matching given arguments
   *
   * @param string $filter json encoded
   * @param string $paging json encoded
   * @return array
   */
  public function searchRecords($filter, $paging)
  {
      return $this->_search($filter, $paging, $this->_recordController, 'Application_Model_RecordFilter');
  }    
  /**
   * Return a single record
   *
   * @param   string $uid
   * @return  array record data
   */
  public function getRecord($uid)
  {
      return $this->_get($uid, $this->_recordController);
  }
  /**
   * creates/updates a record
   *
   * @param  string $recordData
   * @return array created/updated record
   */
  public function saveRecord($recordData)
  {
      return $this->_save($recordData, $this->_recordController, 'Record');
  }    
  /**
   * deletes existing records
   *
   * @param string $ids 
   * @return string
   */
  public function deleteRecords($ids)
  {
      $this->_delete($ids, $this->_recordController);
  }   
}

Exemplo FRONTEND HTTP(server)

…/Application/Frontend/http.php: 
/**
* This class handles all Http requests for the application
*
* @package     Application
* @subpackage  Frontend
*/
class Application_Frontend_Http extends Tinebase_Frontend_Http_Abstract
{
  protected $_applicationName = 'Application';   
  /**
   * Returns all JS files which must be included for this app
   *
   * @return array Array of filenames
   */
  public function getJsFilesToInclude()
  {
      return array(
          'Application/js/Application.js',
          'Application/js/Models.js',
          'Application/js/GridPanel.js',
          'Application/js/EditDialog.js',
      );
  }
}


JavaScript FrontEnd

Para construção do frontend javascript, vários arquivos são necessários. Se você não quiser usar o painel genérico, tree, grid e edit dialog você poderá definir seu próprio stuff. A vantagem deste tipo de estrutura é a padronização dos objetos javascript, que terão o mesmo padrão visual para qualquer aplicação.

../Application/js/Application.js/
Ext.namespace('Tine', 'Tine.Application');
// default mainscreen
Tine.Application.MainScreen = Tine.Tinebase.widgets.app.MainScreen;
Tine.Application.TreePanel = function(config) {
  Ext.apply(this, config);
  
  this.id = 'ApplicationTreePanel',
  this.recordClass = Tine.Application.Record;
  Tine.Application.TreePanel.superclass.constructor.call(this);
}
Ext.extend(Tine.Application.TreePanel , Tine.widgets.container.TreePanel);
Tine.Application.RecordBackend = new Tine.Tinebase.widgets.app.JsonBackend({
  appName: 'Application',
  modelName: 'Record',
  recordClass: Tine.Application.Model.Record
});
../Application/js/Models.js
Define o javascript record models. Este deve ter os mesmos campos como no modelo php em../Application/Model/xxxx.php.
Ext.namespace('Tine', 'Tine.Application.Model');
Tine.Application.Model.RecordArray = Tine.Tinebase.Model.genericFields.concat([
  { name: 'id' },
  { name: 'container_id' },
  /*** define more fields here ***/
]);
Tine.Application.Model.Record = Tine.Tinebase.Record.create(Tine.Application.Model.RecordArray, {
  appName: 'Application',
  modelName: 'Record',
  idProperty: 'id',
  //titleProperty: 'title',
  recordName: 'Record',
  recordsName: 'Records',
  containerProperty: 'container_id',
  containerName: 'Record list',
  containersName: 'Record lists'
});
Tine.ExampleApplication.Model.ExampleRecord.getFilterModel = function() {
  var app = Tine.Tinebase.appMgr.get('ExampleApplication');      
  return [     
      {label : _('Quick search'), field : 'query', operators : [ 'contains' ]}, 
      {filtertype : 'tine.widget.container.filtermodel', app : app
          , recordClass : Tine.ExampleApplication.Model.ExampleRecord}, 
      {filtertype : 'tinebase.tag', app : app} 
  ];
};
/*** add more models here if you need them ***/
../Application/js/GridPanel.js
Ext.namespace('Tine.Application');
Tine.Application.RecordGridPanel = Ext.extend(Tine.Tinebase.widgets.app.GridPanel, {
  // model generics
  recordClass: Tine.Application.Model.Record,   
  // grid specific
  defaultSortInfo: {field: 'creation_time', direction: 'DESC'},
  gridConfig: {
      loadMask: true,
      autoExpandColumn: 'title'
  },   
  initComponent: function() {
      this.recordProxy = Tine.Application.RecordBackend;       
      this.gridConfig.columns = this.getColumns();
      this.filterToolbar = this.filterToolbar || this.getFilterToolbar();       
      this.plugins = this.plugins || [];
      this.plugins.push(this.filterToolbar);       
      Tine.Application.RecordGridPanel.superclass.initComponent.call(this);
  },    
  getColumns: function(){
      return [
      /*** define your columns here, like this: ***/
      /*{
          id: 'number',
          header: this.app.i18n._("Number"),
          width: 100,
          sortable: true,
          dataIndex: 'number'
      }*/];
  }
}
../Application/js/EditDialog.js
Ext.namespace('Tine.Application');
Tine.Application.RecordEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {   
  /**
   * @private
   */
  windowNamePrefix: 'RecordEditWindow_',
  appName: 'Application',
  recordClass: Tine.Application.Model.Record,
  recordProxy: Tine.Application.RecordBackend,
  loadRecord: false,
  tbarItems: [{xtype: 'widget-activitiesaddbutton'}],   
  /**
   * overwrite update toolbars function (we don't have record grants yet)
   */
  updateToolbars: function() {
  },   
  /**
   * returns dialog
   * 
   * NOTE: when this method gets called, all initalisation is done.
   */
  getFormItems: function() {
      return {
          xtype: 'tabpanel',
          border: false,
          plain:true,
          activeTab: 0,
          border: false,
          items:[{               
              title: this.app.i18n._('Record'),
              autoScroll: true,
              border: false,
              frame: true,
              layout: 'border',
              items: [{
                  region: 'center',
                  xtype: 'columnform',
                  labelAlign: 'top',
                  formDefaults: {
                      xtype:'textfield',
                      anchor: '100%',
                      labelSeparator: ,
                      columnWidth: .333
                  },
                  items: [[
                      /*** define your form fields here, like this ***/
                      /* {
                      fieldLabel: this.app.i18n._('Number'),
                      name: 'number',
                      allowBlank: false
                      } */
                      }]] 
              }]
          ]
      };
  }
});
Tine.Application.RecordEditDialog.openWindow = function (config) {
  var id = (config.record && config.record.id) ? config.record.id : 0;
  var window = Tine.WindowFactory.getWindow({
      width: 600,
      height: 400,
      name: Tine.Application.RecordEditDialog.prototype.windowNamePrefix + id,
      contentPanelConstructor: 'Tine.Application.RecordEditDialog',
      contentPanelConstructorConfig: config
  });
  return window;
};
../Application/CSS
Dispõe dos arquivos Css a serem utilizados;


Serviços providos pelo Expresso V3

JSON-SMD - Lista Serviços Disponíveis

Uma importante funcionalidade do protocolo é o JSON-SMD ou Service Mapping Description(SMD). É uma representação JSON dos serviços e seus parâmetros providos pelo servidor JSON-RPC. Estando você habilitado a buscar o SMD você terá uma lista de funções disponíveis e acessíveis pelo cliente JSON-RPC. O serviço JSON-RPC do Expresso3.0 desviará para o JSON-SMD quando receber um request com o metodo setado para NULL e o request-type for application/json-rpc. Estando autorizado, você receberá uma lista de todas as funções disponíveis e portando havendo diferenças antes de login a após login. Caso sua implementação client não suporte JSON-SMD você poderá simplesmente analisar as classes do arquivo Frontend/Json.php do diretório da aplicação que você deseja, para obter os métodos disponíveis.

Serviços disponibilizados pelo ExpressoV3

Modulo Tinebase

Tinebase.attachTagToMultipleRecords 
Returns: null 
Parameters: 
  1. type: array 
  2. name: filterData 
  3. optional: false 
  1. type: string 
  2. name: filterName 
  3. optional: false 
  1. type: any 
  2. name: tag 
  3. optional: false 
Tinebase.authenticate 
Returns: array 
Parameters: 
 1. type: string 
 2. name: username 
 3. optional: false 
 1. type: string 
 2. name: password 
 3. optional: false 
Tinebase.changePassword 
Returns: array 
Parameters: 
 1. type: string 
 2. name: oldPassword 
 3. optional: false 
 1. type: string 
 2. name: newPassword 
 3. optional: false 
Tinebase.clearState 
Returns: null 
Parameters: 
 1. type: string 
 2. name: name 
 3. optional: false 
Tinebase.deleteTags 
Returns: array 
Parameters: 
 1. type: array 
 2. name: ids 
 3. optional: false 
Tinebase.getAllRegistryData 
Returns: any 
Parameters: 
Tinebase.getAvailableTranslations 
Returns: array 
Parameters: 
Tinebase.getConfig 
Returns: array 
Parameters: 
 1. type: string 
 2. name: id 
 3. optional: false 

Tinebase.getCountryList 
Returns: array 
Parameters: 
Tinebase.getNoteTypes 
Returns: null 
Parameters: 
Tinebase.getRegistryData 
Returns: any 
Parameters: 
Tinebase.getUserProfile 
Returns: array 
Parameters: 
1. type: string 
2. name: userId 
3. optional: false 
Tinebase.getUserProfileConfig 
Returns: object 
Parameters: 
Tinebase.getUsers 
Returns: array 
Parameters: 
1. type: string 
2. name: filter 
3. optional: false 
1. type: string 
2. name: sort 
3. optional: false 
1. type: string 
2. name: dir 
3. optional: false 
1. type: integer 
2. name: start 
3. optional: false 
1. type: integer 
2. name: limit 
3. optional: false 
Tinebase.loadState 
Returns: array 
Parameters: 
Tinebase.login 
Returns: array 
Parameters: 
1. type: string 
2. name: username 
3. optional: false 
1. type: string 
2. name: password 
3. optional: false 
Tinebase.logout
Returns: array 
Parameters: 
Tinebase.ping 
Returns: null 
Parameters: 
Tinebase.saveConfig
Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Tinebase.savePreferences 
Returns: array 
Parameters: 
1. type: string 
2. name: data 
3. optional: false 
1. type: boolean 
2. name: adminMode 
3. optional: false 
Tinebase.saveTag
Returns: array 
Parameters: 
1. type: array 
2. name: tag 
3. optional: false 
Tinebase.searchCustomFieldValues
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 

Tinebase.searchDepartments 
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Tinebase.searchNotes 
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 

Tinebase.searchPreferencesForApplication 
Returns: array 
Parameters: 
1. type: string 
2. name: applicationName 
3. optional: false 
1. type: array 
2. name: filter 
3. optional: false 
Tinebase.searchRoles 
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 

Tinebase.searchTags 
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Tinebase.setLocale 
Returns: array 
Parameters: 
1. type: string 
2. name: localeString 
3. optional: false 
1. type: boolean 
2. name: saveaspreference 
3. optional: false 
1. type: boolean 
2. name: setcookie 
3. optional: false 
Tinebase.setState 
Returns: null 
Parameters: 
1. type: string 
2. name: name 
3. optional: false 
1. type: string 
2. name: value 
3. optional: false 

Tinebase.setTimezone
Returns: string 
Parameters: 
1. type: string 
2. name: timezoneString 
3. optional: false 
1. type: boolean 
2. name: saveaspreference 
3. optional: false 
Tinebase.setUserProfileConfig
Returns: null 
Parameters: 
1. type: array 
2. name: configData 
3. optional: false 
Tinebase.updateCredentialCache
Returns: array 
Parameters: 
1. type: string 
2. name: password 
3. optional: false 
Tinebase.updateUserPofile
Returns: array 
Parameters: 
1. type: array 
2. name: profileData 
3. optional: false 
Tinebase.void
Returns: null 
Parameters:


Modulo Expressomail

Expressomail.addFlags 
Returns: [array, array] 
Parameters: 
1. type: array 
2. name: filterData 
3. optional: false 
1. type: [string, array] 
2. name: flags 
3. optional: false 
Expressomail.addFolder
Returns: array 
Parameters: 
1. type: string 
2. name: name 
3. optional: false 
1. type: string 
2. name: parent 
3. optional: false 
1. type: string 
2. name: accountId 
3 . optional: false 
Expressomail.changeCredentials
Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
1. type: string 
2. name: username 
3. optional: false 
1. type: string 
2. name: password 
3. optional: false 
Expressomail.clearFlags
Returns: [array, array] 
Parameters: 
1. type: array 
2. name: filterData 
3. optional: false 
1. type: [string, array] 
2. name: flags 
3. optional: false 
Expressomail.deleteAccounts
Returns: array 
Parameters: 
1. type: array 
2. name: ids 
3. optional: false 
Expressomail.deleteFolder 
Returns: array 
Parameters: 
1. type: string 
2. name: folder 
3. optional: false 
1. type: string 
2. name: accountId 
3. optional: false 
Expressomail.emptyFolder 
Returns: array 
Parameters: 
1. type: string 
2. name: folderId 
3. optional: false 
Expressomail.getAccount 
Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
Expressomail.getMessage 
Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
Expressomail.getRegistryData 
Returns: any 
Parameters: 
Expressomail.getRules 
Returns: array 
Parameters: 
1. type: string 
2. name: accountId 
3. optional: false 
Expressomail.getVacation 
Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
Expressomail.moveMessages 
Returns: array 
Parameters: 
1. type: array 
2. name: filterData 
3. optional: false 
1. type: string 
2. name: targetFolderId 
3. optional: false 
Expressomail.refreshFolder 
Returns: array 
Parameters: 
1. type: string 
2. name: folderId 
3. optional: false 
Expressomail.renameFolder 
Returns: array 
Parameters: 
1. type: string 
2. name: newName 
3. optional: false 
1. type: string 
2. name: oldGlobalName 
3. optional: false 
1. type: string 
2. name: accountId 
3. optional: false 
Expressomail.saveAccount 
Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Expressomail.saveMessage 
Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Expressomail.saveMessageInFolder 
Returns: array 
Parameters: 
1. type: string 
2. name: folderName 
3. optional: false 
1. type: array 
2. name: recordData 
3. optional: false 
Expressomail.saveRules 
Returns: array 
Parameters: 
1. type: array 
2. name: accountId 
3. optional: false 
1. type: array 
2. name: rulesData 
3. optional: false 
Expressomail.saveVacation 
Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Expressomail.searchAccounts 
Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
Expressomail.searchFolders Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
Expressomail.searchMessages Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Expressomail.updateFlags Returns: array 
Parameters: 
1. type: string 
2. name: folderId 
3. optional: false 
1. type: integer 
2. name: time 
3. optional: false 
Expressomail.updateFolderCache Returns: array 
Parameters: 
1. type: string 
2. name: accountId 
3. optional: false 
1. type: string 
2. name: folderName 
3. optional: false 
Expressomail.updateMessageCache Returns: array 
Parameters: 
1. type: string 
2. name: folderId 
3. optional: false 
1. type: integer 
2. name: time 
3. optional: false


Modulo Adressbook

Addressbook.deleteContacts Returns: array 
Parameters: 
1. type: array 
2. name: ids 
3. optional: false 
Addressbook.getContact Returns: array 
Parameters: 
1. type: integer 
2. name: id 
3. optional: false 
Addressbook.getDefaultAddressbook Returns: array 
Parameters: 

Addressbook.getRegistryData Returns: any 
Parameters: 
Addressbook.getSalutations Returns: array 
Parameters: 

Addressbook.importContacts Returns: array 
Parameters: 
1. type: array 
2. name: files 
3. optional: false 
1. type: array 
2. name: importOptions 
3. optional: false 
1. type: string 
2. name: definitionId 
3. optional: false 
Addressbook.saveContact Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Addressbook.searchContacts Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Addressbook.searchLists Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false


Modulo Calendar

Calendar.createRecurException Returns: [array, array] 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
1. type: boolean 
2. name: deleteInstance 
3. optional: false 
1. type: boolean 
2. name: deleteAllFollowing 
3. optional: false 
1. type: boolean 
2. name: checkBusyConficts 
3. optional: true 
default: false 
Calendar.deleteEvents Returns: string 
Parameters: 
1. type: array 
2. name: ids 
3. optional: false 

Calendar.deleteResources Returns: string 
Parameters: 
1. type: array 
2. name: ids 
3. optional: false 
Calendar.deleteRecurSeries Returns: null 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 

Calendar.getEvent Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
Calendar.getRegistryData Returns: any 
Parameters: 
Calendar.getResource Returns: array 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
Calendar.searchEvents Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Calendar.searchResources Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Calendar.saveEvent Returns: [array, array] 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
1. type: boolean 
2. name: checkBusyConficts 
3. optional: true 
default: false 
Calendar.saveResource Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Calendar.setAttenderStatus Returns: array 
Parameters: 
1. type: array 
2. name: eventData 
3. optional: false 
1. type: array 
2. name: attenderData 
3. optional: false 
1. type: string 
2. name: authKey 
3. optional: false 
Calendar.updateRecurSeries Returns: [array, array] 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
1. type: boolean 
2. name: checkBusyConficts 
3. optional: true 
default: false 

Modulo Tarefas(Tasks)

Tasks.searchTasks Returns: array 
Parameters: 
1. type: array 
2. name: filter 
3. optional: false 
1. type: array 
2. name: paging 
3. optional: false 
Tasks.getTask Returns: [object, object, object] 
Parameters: 
1. type: string 
2. name: id 
3. optional: false 
1. type: integer 
2. name: containerId 
3. optional: true 
4. default: -1 
1. type: string 
2. name: relatedApp 
3. optional: true 
4. default: 
Tasks.saveTask Returns: array 
Parameters: 
1. type: array 
2. name: recordData 
3. optional: false 
Tasks.deleteTasks Returns: string 
Parameters: 
1. type: array 
2. name: ids 
3. optional: false 

Tasks.getDefaultContainer Returns: array 
Parameters: 
Tasks.getAllStatus Returns: object 
Parameters: 
Tasks.getRegistryData Returns: any 
Parameters: 

Modulo Activesync

public function setDeviceContentFilter($deviceId, $class, $filterId) 
public function getRegistryData() 


Modulo Admin

public function __construct() 
public function getRegistryData() 
public function deleteAccessLogs($ids) 
public function searchAccessLogs($filter, $paging) 
public function getApplication($applicationId) 
public function getApplications($filter, $sort, $dir, $start, $limit) 
public function setApplicationState($applicationIds, $state) 
public function getUser($id) 
public function getUsers($filter, $sort, $dir, $start, $limit) 
public function searchUsers($filter, $paging) 
public function searchGroups($filter, $paging) 
public function saveUser($recordData) 
public function deleteUsers($ids) 
public function setAccountState($accountIds, $status) 
public function resetPassword($account, $password, $mustChange) 
public static function resolveAccountName(array $_items, $_hasAccountPrefix =FALSE, $_removePrefix = FALSE) 
public function searchSharedAddressbooks($filter, $paging) 
public function getGroup($groupId) 
public function getGroups($filter, $sort, $dir, $start, $limit) 
public function getGroupMembers($groupId) 
public function saveGroup($groupData, $groupMembers) 
public function deleteGroups($groupIds) 
public function searchSambaMachines($filter, $paging) 
public function getSambaMachine($id) 
public function saveSambaMachine($recordData) 
public function deleteSambaMachines($ids) 
public function getTag($tagId) 
public function getTags($query, $sort, $dir, $start, $limit) 
public function saveTag($tagData) 
public function deleteTags($tagIds) 
public function getRole($roleId) 
public function getRoles($query, $sort, $dir, $start, $limit) 
public function saveRole($roleData, $roleMembers, $roleRights) 
public function deleteRoles($roleIds) 
public function getRoleMembers($roleId) 
public function getRoleRights($roleId) 
public function getAllRoleRights() 
public function searchContainers($filter, $paging) 
public function getContainer($id) 
public function saveContainer($recordData) 
public function deleteContainers($ids) 

Modulo Phone

public function dialNumber($number, $phoneId, $lineId) 
public function searchCalls($filter, $paging) 
public function getMyPhone($id) 
public function saveMyPhone($recordData) 
public function getRegistryData() 


Modulo Setup

public function login($username, $password) 
public function logout() 
public function installApplications($applicationNames, $options = null) 
public function updateApplications($applicationNames) 
public function uninstallApplications($applicationNames) 
public function searchApplications() 
public function envCheck() 
public function loadConfig() 
public function saveConfig($data) 
public function checkConfig() 
public function loadAuthenticationData() 
public function saveAuthentication($data) 
public function getEmailConfig() 
public function saveEmailConfig($data) 
public function getRegistryData() 
public function getAllRegistryData() 


Modulo Sipgate

public function dialNumber($_number) 
public function getCallHistory($_sipUri, $_start, $_stop, $_pstart = 0, $_plimit = 20) 
public function sendSms($_number,$_content) 
public function getPhoneDevices() 
public function getFaxDevices() 
public function getSessionStatus($sessionId) 
public function closeSession($sessionId) 
public function getRegistryData() 


Modulo VoipManager

public function searchSnomPhones($filter, $paging) 
public function getSnomPhone($id) 
public function saveSnomPhone($recordData) 
public function deleteSnomPhones($ids) 
public function resetHttpClientInfo($phoneIds) 
public function getSnomPhoneSettings($id) 
public function saveSnomPhoneSettings($recordData) 
public function deleteSnomPhoneSettings($ids) 
public function searchSnomLocations($filter, $paging) 
public function getSnomLocation($id) 
public function saveSnomLocation($recordData) 
public function deleteSnomLocations($ids) 
public function searchSnomSoftwares($filter, $paging) 
public function getSnomSoftware($id) 
public function saveSnomSoftware($recordData) 
public function deleteSnomSoftwares($ids) 
public function searchSnomTemplates($filter, $paging) 
public function getSnomTemplate($id) 
public function saveSnomTemplate($recordData) 
public function deleteSnomTemplates($ids) 
public function searchSnomSettings($filter, $paging) 
public function getSnomSetting($id) 
public function saveSnomSetting($recordData) 
public function deleteSnomSettings($ids) 
public function searchAsteriskContexts($filter, $paging) 
public function getAsteriskContext($id) 
public function saveAsteriskContext($recordData) 
public function deleteAsteriskContexts($ids) 
public function searchAsteriskMeetmes($filter, $paging) 
public function getAsteriskMeetme($id) 
public function saveAsteriskMeetme($recordData) 
public function deleteAsteriskMeetmes($ids) 
public function searchAsteriskSipPeers($filter, $paging) 
public function getAsteriskSipPeer($id) 
public function saveAsteriskSipPeer($recordData) 
public function updatePropertiesAsteriskSipPeer($id, $data) 
public function deleteAsteriskSipPeers($ids) 
public function searchAsteriskVoicemails($filter, $paging) 
public function getAsteriskVoicemail($id) 
public function saveAsteriskVoicemail($recordData) 
public function deleteAsteriskVoicemails($ids) 


Modulo Crm

public function searchLeads($filter, $paging) 
public function getLead($id) 
public function saveLead($recordData) 
public function deleteLeads($ids) 
public function getRegistryData() 
public function getSettings() 
public function saveSettings($recordData) 


Modulo RequestTraker

public function searchQueues() 
public function searchTickets($filter, $paging) 
public function getTicket($id) 

Exemplos de chamadas aos serviços

Na linguagem PHP – Loga e Insere um Contato ao Usuário

O Código em PHP foi gerado usando o Zend Framework.

O exemplo em questão faz uma conexão ao ExpressoV3, mostra as duas formas de buscar informações no serviço. Neste caso em específico busca dados do usuário logado e insere um novo contato no catalogo do mesmo.

// set include path to find all needed classes 
$time_start = microtime(true); 
$paths = array( 
 realpath(dirname(__FILE__)), 
 realpath(dirname(__FILE__) . '/library'), 
 get_include_path() 
); 
set_include_path(implode(PATH_SEPARATOR, $paths)); 
require_once 'Zend/Loader/Autoloader.php'; 
$autoloader = Zend_Loader_Autoloader::getInstance(); 
$autoloader->setFallbackAutoloader(true); 
// url of your Tine 2.0 installation 
$tine20Url = 'http://xx.xx.xx.xx/expressov3/index.php'; 
// login name 
$tine20Loginname = ""; 
// password 
$tine20Password = ""; 
// initialize  service 
$tine20 = new Zend_Service_Tine20($tine20Url); 
// login  
$loginData = $tine20->login($tine20Loginname, $tine20Password); 
//call Tinebase.getAllRegistryData directly 
$result = $tine20->call('Tinebase.getAllRegistryData'); 
//ou via proxy 
$tinebase = $tine20->getProxy('Tinebase'); 
$result = $tinebase->getAllRegistryData(); 
// get a proxy class for the Addressbook namespace 
$addressbook = $tine20->getProxy('Addressbook'); 
///busca informações do usuário para poder inserir depois 
$userData = $addressbook->getContact($loginData['account']['contact_id']); 
// create a new contact 
$newContact = array( 
'n_given' => 'Nome', 
'n_family' => 'Sobrenome', 
'container_id' => $userData['container_id']['id'], 
); 
$contact = $addressbook->saveContact($newContact); 
// logout from Tine 2.0 
$tine20->logout(); 

Linguagem Python – Loga e Busca uma mensagem de um Usuário

Neste script é definida uma mensagem (específica de uma caixa postal) e a mesma é buscada na lista de mensagens do usuário logado.

#!/usr/bin/python 
# coding: utf-8 
# Exemplo simples de acesso remoto a funções do expresso 3 utilizando Python 
import cookielib, urllib2, json 
#Usuário e senha no sistema, strings. 
usuario = "" 
senha = "" 
#URL do controlador do TINE 
url = "http://xx.xxx.xxx.xx/index.php" 
#Método do tine a ser acessado, string. 
metodo = "Expressomail.getMessage" 
#parâmetros para o método, um mapa com os valores ou um mapa vazio sem nenhum parâmetro. 
parametros = {"id":"a983490edb585f80b992878eab5db6c501ac6136"} 
#cookies inicializados 
cj = cookielib.CookieJar() 
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) 
urllib2.install_opener(opener) 
#requisição do login 
cont= 1 
data = json.dumps({"jsonrpc":"2.0","method":"Tinebase.login","params": 
{"username":usuario,"password":senha},"id":cont}) 
req = urllib2.Request(url=url,data=data) 
req.add_header('Content-type', 'application/json') 
r = urllib2.urlopen(req) 
resp = r.read() 
data = json.loads(resp) 
#para manter a sessão criada é preciso o jsonkey da resposta do login 
jsonkey = data["result"]["jsonKey"] 
# aqui é feita a requisição, note que o jsonkey deve ser passado como header. 
cont = cont+1 
data = json.dumps({"jsonrpc":"2.0","method":metodo,"params":parametros,"id":cont}) 
req = urllib2.Request(url=url,data=data) 
req.add_header('Content-type', 'application/json') 
req.add_header('X-Tine20-JsonKey',jsonkey) 
r = urllib2.urlopen(req) 
resp = r.read() 
#imprime a resposta na tela já convertida para um objeto no python. 
print json.loads(resp)

Linguagem Java – Busca Catálogo de Serviços, loga e manipula Email

Neste exemplo utilizamos o apache HttpClient 4 (http://hc.apache.org/) para a conexão Http com o servidor Expressov3 e o jackson Json Processor 1.9 (http://jackson.codehaus.org/) para processar/gerar conteúdo serializado em Json.

Faz um request SMD e então formata a resposta e grava em um arquivo "/tmp/smdNotLogged.txt" . Depois faz uma chamada à "Tinebase.login", passando os parâmetros username e password, se login foi realizado com sucesso, faz uma chamada à Expressomail.getRegistryData, para recuperar o filtro inical. Então adiciona a regra ao filtro para buscar folders que possuam o campo globalname = "", realizando uma chamada à "Expressomail.searchFolders" isto retornará o folder / e o folder INBOX e então recupera Id do folder index, monta o caminho do folder INBOX e o imprime.


Classe Main.java 
package expresso3client; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.UnsupportedEncodingException; 
import java.util.ArrayList; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import json.JsonLoginResponse; 
import json.JsonRpc; 
import json.JsonSMD; 
import org.apache.http.HttpResponse; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.methods.HttpPost; 
import org.apache.http.entity.StringEntity; 
import org.apache.http.impl.client.DefaultHttpClient; 
import org.codehaus.jackson.JsonFactory; 
import org.codehaus.jackson.map.ObjectMapper; 
/** 
* 
* @author "Mário César Kolling" <mario.kolling@serpro.gov.br> 
*/ 
public class Main { 
/** 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 
String username = ""; 
String password = ""; 
String url = ""; 
if (args.length < 3) { 
 System.out.println("Usage: java -jar Expresso3Client.jar username password url"); 
 System.exit(1); 
 } 
else 
 { 
 username = args[0]; 
 password = args[1]; 
 url = args[2]; 
} 
try { 
 // Instancia o HttpClient 
 DefaultHttpClient client = new DefaultHttpClient(); 
 // Instancia a classe que monta request serializado em Json 
 JsonRpc jsonrpc = new JsonRpc(); 
 // Configura um Post request 
 System.out.print("SMDRequest: "); 
 // Expresso3 always use the index.php as controller 
 HttpPost post = new HttpPost(url); 
 // Instancia o conteúdo do post como uma StringEntity 
 StringEntity entity = new StringEntity(jsonrpc.generateSmdRequest(), "UTF-8"); 
 entity.writeTo(System.out); System.out.println(); 
 // Adiciona o conteúdo ao Post 
 post.setEntity(entity); 
 // Define o header ContentType como "application/json; charset=UTF-8" 
 post.setHeader("Content-Type", "application/json; charset=UTF-8"); 
 //
 //
 // Executa o Post e obtém a resposta 
 // Cuidado!!! O contentType desta resposta é text/html ao invés de application/json 
 // embora o conteúdo seja serializado em Json. 
 // Alguns frameworks testam este valor para carregar o parser apropriado 
 // para tratar o conteúdo e podem lançar uma exceção. 
 HttpResponse response = client.execute(post);
 ObjectMapper mapper = new ObjectMapper(new JsonFactory()); 
 // Mapeia o conteúdo da resposta como um objeto da classe JsonSMD 
 JsonSMD smdResponse = mapper.readValue(response.getEntity().getContent(), JsonSMD.class); 
 smdResponse.writeContent(new FileWriter("/tmp/smdNotLogged.txt")); 
 // Logando no Expresso3 
 System.out.println("Login request: "); 
 // Adiciona os parâmetros da chamada ao método Tinebase.login 
 jsonrpc.addParam("username", username); 
 jsonrpc.addParam("password", password); 
 // Instancia o conteúdo do Post como uma StringEntity 
 entity = new StringEntity(jsonrpc.generateRequest("Tinebase.login"), "UTF-8"); 
 System.out.print("LoginRequest: "); entity.writeTo(System.out); 
 System.out.println();
// define a entidade no Post 
post.setEntity(entity); 
// Executa o Post e pega a resposta 
response = client.execute(post); 
// Mapeia o conteúdo da resposta para um objeto da classe JsonLoginResponse 
JsonLoginResponse loginResponse = 
mapper.readValue(response.getEntity().getContent(), 
JsonLoginResponse.class); 
// Testa se login obteve sucesso 
if (loginResponse.getResult().getSuccess()) { 
System.out.println("Expressomail.getRegistryData após login: "); 
// Recupera a jsonKey, chave que controla a sessão no servidor 
String jsonKey = loginResponse.getResult().getJsonKey(); 
jsonrpc.clearParams(); 
entity = new 
StringEntity(jsonrpc.generateRequest("Expressomail.getRegistryData"),  "UTF-8"); 
System.out.print("Expressomail.getRegistryData Request: "); 
entity.writeTo(System.out); System.out.println(); 
post.setEntity(entity); 
// Define o header HTTP X-Tine20-jsonKey cujo valor deve ser o da chave 
// jsonKey, para que o Expresso3 saiba que já estamos em uma sessão logada. 
post.addHeader("X-Tine20-jsonKey", jsonKey); 
response = client.execute(post); 
//
//
// Mapeando resultado para um Map<String, Object> 
// E recuperando o valor filter 
Map<String, Object> ExpressomailGetRegistryDataResponse = 
mapper.readValue(response.getEntity().getContent(), Map.class); 
LinkedHashMap<String,Object> result = (LinkedHashMap<String,Object>) 
ExpressomailGetRegistryDataResponse.get("result"); 
LinkedHashMap<String,Object> accounts = (LinkedHashMap<String,Object>) 
result.get("accounts"); 
ArrayList filter = (ArrayList) accounts.get("filter"); 
// Adiciona regra ao filtro para buscar folders que possuam o campo 
// globalname = "", isto retornará o folder / e o folder INBOX 
LinkedHashMap<String,Object> otherFilter = new LinkedHashMap(); 
otherFilter.put("field", "globalname"); 
otherFilter.put("operator", "equals"); 
otherFilter.put("value", ""); 
ArrayList searchFilter = (ArrayList) filter.clone(); 
searchFilter.add(otherFilter); 
// Executa o a chamada à Expressomail.searchFolders passando o parâmetro 
// filter (ArrayList) 
jsonrpc.addParam("filter", searchFilter); 
entity = new StringEntity(jsonrpc.generateRequest("Expressomail.searchFolders"), "UTF-8"); 
System.out.println("Expressomail.searchFolders Request:" 
+jsonrpc.generateRequest("Expressomail.searchFolders")); 
post.setEntity(entity); 
response = client.execute(post); 
// Recupera Id do folder INDEX e caminho passando 
Map<String, Object> ExpressomailSearchFoldersResponse = 
mapper.readValue(response.getEntity().getContent(), Map.class); 
result = (LinkedHashMap<String,Object>) 
ExpressomailSearchFoldersResponse.get("result"); 
ArrayList results = (ArrayList) result.get("results"); 
for (Object folder : results) { 
  String globalname = (String) 
  ((LinkedHashMap<String,Object>) folder).get("globalname"); 
  if (globalname != null && globalname.equalsIgnoreCase("INBOX")) { 
    System.out.println("Folder "+globalname+" path: "); 
  } 
} 
String path = "/"; 
path += (String)((LinkedHashMap<String,Object>)results.get(1)).get("id"); 
path += "/"; 
path += (String)((LinkedHashMap<String,Object>)results.get(0)).get("id"); 
System.out.println(path); 
} 
else 
 { 
 Logger.getLogger(Main.class.getName()).log(Level.INFO, 
 loginResponse.getResult().getErrorMessage()); 
 } 
} 
catch (ClientProtocolException ex) { 
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); 
} catch (UnsupportedEncodingException ex) { 
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); 
} catch (IOException ex) { 
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); 
} 
} 
} 
Classe JsonRpc.java 
package json; 
import java.io.IOException; 
import java.io.StringWriter; 
import java.math.BigDecimal; 
import java.math.BigInteger; 
import java.util.ArrayList; 
import java.util.Calendar; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.Random; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import org.codehaus.jackson.JsonFactory; 
import org.codehaus.jackson.JsonGenerator; 
/** 
* Classe que constrói requests no formato Json-RPC 2.0 
* 
* @author "Mário César Kolling" <mario.kolling@serpro.gov.br> 
*/ 
public class JsonRpc { 
public static String VERSION = "2.0"; 
private final Random rdm = new Random(Calendar.getInstance().getTimeInMillis()); 
private Map<String, Object> params = new HashMap<String, Object>();  
/** 
* Método que contrói um request cuja resposta é um Json-SMD. 
* Um Json-SMD request para o Expresso3 é um request Json onde o método é nulo 
* e params é vazio. 
* 
* @return Request serializado em Json 
*/ 
public String generateSmdRequest() { 
this.clearParams(); 
return generateRequest(null); 
} 
/** 
* Método que monta um request Json-RPC. 
* TODO: Criar método recursivo que gera parâmetros {@code} array, já que podemos 
* ter vários níveis de recursão dentro deste tipo de parâmetros 
* 
* @param method Método a ser executado pelo servidor Expresso3. Ex: Tinebase.login 
* @return Request serializado em Json 
*/ 
public String generateRequest(String method) { 
int id = Math.abs(rdm.nextInt()); 
StringWriter writer = new StringWriter(); 
JsonFactory factory = new JsonFactory(); 
try { 
JsonGenerator gen = factory.createJsonGenerator(writer); 
// Initialize Json 
gen.writeStartObject(); 
gen.writeStringField("jsonrpc", JsonRpc.VERSION); 
// Add method param 
gen.writeStringField("method", method); 
// Add params Object 
gen.writeObjectFieldStart("params");  
for (Iterator<String> i = this.params.keySet().iterator(); i.hasNext();) { 
String param = i.next(); 
Object value = this.params.get(param); 
if (value instanceof String) { 
gen.writeStringField(param, (String) value); 
} 
else if (value instanceof Boolean) { 
gen.writeBooleanField(param, ((Boolean) value).booleanValue()); 
} 
else if (value instanceof Integer) { 
gen.writeNumberField(param, ((Integer) value).intValue()); 
} 
else if (value instanceof Long) { 
gen.writeNumberField(param, ((Long) value).longValue()); 
} 
else if (value instanceof BigInteger) { 
gen.writeNumberField(param, ((BigInteger) value).longValue()); 
} 
else if (value instanceof Double) { 
gen.writeNumberField(param, ((Double) value).doubleValue()); 
} 
else if (value instanceof BigDecimal) { 
gen.writeNumberField(param, (BigDecimal) value); 
} 
else if (value instanceof ArrayList) { 
ArrayList<LinkedHashMap<String, String>> values = 
(ArrayList<LinkedHashMap<String, String>>) value; 
//
// Start array 
gen.writeArrayFieldStart(param); 
for (LinkedHashMap<String, String> arrayValue : values) { 
// Start Object 
gen.writeStartObject(); 
for (Iterator<String> arrayI = arrayValue.keySet().iterator(); 
arrayI.hasNext();) { 
String arrayKey = arrayI.next(); 
gen.writeStringField(arrayKey, arrayValue.get(arrayKey)); 
} 
// End Object 
gen.writeEndObject(); 
} 
// End array 
gen.writeEndArray(); 
} 
} 
// Close params Object 
gen.writeEndObject(); 
// Add id field 
gen.writeNumberField("id", id); 
// End Json 
gen.writeEndObject(); 
gen.close(); 
} 
catch (IOException ex) { 
Logger.getLogger(JsonRpc.class.getName()).log(Level.SEVERE, null, ex); 
} 
return writer.toString(); 
} 
/** 
* Método que limpa os parâmetros que serão usados para montar o request 
* 
*/ 
public void clearParams() { 
this.params = new HashMap<String, Object>(); 
} 
/** 
* Adiciona um parâmetro ao método que está sendo criado 
* 
* @param param Nome do parâmetro do método 
* @param value Valor do parâmetro 
*/ 
public void addParam(String param, Object value){ 
this.params.put(param, value); 
} 
/** 
* Adiciona um conjunto ({@code} Map<String, String>) com os parâmetros do  
* método a ser chamado 
* 
* @param params Um mapa com todos os parâmetros 
*/ 
public void setParams(Map<String, Object> params) { 
this.params = params; 
} 
} 
Classe JsonRpc.java 
package json; 
import java.io.IOException; 
import java.io.Writer; 
import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import org.codehaus.jackson.annotate.JsonIgnoreProperties; 
/** 
* Classe que mapeia o conteúdo da resposta de um request Json-SMD 
* 
* @author "Mário César Kolling" <mario.kolling@serpro.gov.br> 
*/ 
@JsonIgnoreProperties(ignoreUnknown = true) 
public class JsonSMD { 
/** 
* Classe que mapeia os serviços que o Expresso3 suporta 
*/ 
public static class Service { 
private String _envelope, _transport; 
private Object _returns; 
private ArrayList<Object> _parameters; 
public String getEnvelope() { 
return _envelope; 
} 
public ArrayList<Object> getParameters() { 
return _parameters; 
} 
public String getTransport() { 
return _transport; 
} 
public Object getReturns() { 
return _returns; 
} 
public void setEnvelope(String _envelope) { 
this._envelope = _envelope; 
} 
public void setParameters(ArrayList<Object> _parameters) { 
this._parameters = _parameters; 
} 
public void setTransport(String _transport) { 
this._transport = _transport; 
} 
public void setReturns(Object returns) { 
this._returns = returns; 
} 
} 
private Double _SMDVersion; 
private String _transport, _envelope, _contentType, _target; 
private Map<String, Service> _services; 
public Double getSMDVersion() { 
return _SMDVersion; 
} 
public String getContentType() { 
return _contentType; 
} 
public String getEnvelope() { 
return _envelope; 
} 
public Map<String, Service> getServices() { 
return _services; 
} 
public String getTarget() { 
return _target; 
} 
public String getTransport() { 
return _transport; 
}
public void setSMDVersion(Double _SMDVersion) { 
this._SMDVersion = _SMDVersion; 
} 
public void setContentType(String _contentType) { 
this._contentType = _contentType; 
} 
public void setEnvelope(String _envelope) { 
this._envelope = _envelope; 
} 
public void setServices(Map<String, Service> _services) { 
this._services = _services; 
} 
public void setTarget(String _target) { 
this._target = _target; 
} 
public void setTransport(String _transport) { 
this._transport = _transport; 
} 
/** 
* Imprime o conteúdo desta resposta 
*/ 
@SuppressWarnings("empty-statement") 
public void printContent() { 
System.out.println("Transport: " + this.getTransport()); 
System.out.println("Envelope: " + this.getEnvelope()); 
System.out.println("ContentType: " + this.getContentType()); 
System.out.println("Target: " + this.getTarget()); 
System.out.println("Services: "); 
for (Iterator<String> i = getServices().keySet().iterator(); i.hasNext();){ 
String serviceName = i.next(); 
System.out.println("\t"+serviceName+": "); 
System.out.println("\t\tTransport: " + 
getServices().get(serviceName).getTransport()); 
System.out.println("\t\tEnvelope: " + 
getServices().get(serviceName).getEnvelope()); 
System.out.println("\t\tReturns: " + getServices().get(serviceName).getReturns()); 
System.out.println("\t\tParameters: "); 
for (Object params : getServices().get(serviceName).getParameters()){ 
if (params instanceof LinkedHashMap) { 
LinkedHashMap<String, Object> lhm = (LinkedHashMap<String, Object>) 
params; 
for (Iterator<String> j = lhm.keySet().iterator(); j.hasNext();) { 
String paramKey = j.next(); 
System.out.println("\t\t\t"+paramKey+": "+lhm.get(paramKey)); 
} 
} 
} 
} 
} 
/** 
* Escreve o conteúdo desta resposta em um writer 
* 
* @param writer Para onde escreveremos 
* @throws IOException 
*/ 
public void writeContent(Writer writer) throws IOException { 
writer.write("Transport: " + this.getTransport()); writer.write('\n'); 
writer.write("Envelope: " + this.getEnvelope()); writer.write('\n'); 
writer.write("ContentType: " + this.getContentType()); writer.write('\n'); 
writer.write("Target: " + this.getTarget()); writer.write('\n'); 
writer.write("Services: "); writer.write('\n'); 
for (Iterator<String> i = getServices().keySet().iterator(); i.hasNext();){ 
String serviceName = i.next(); 
writer.write("\t"+serviceName+": "); writer.write('\n'); 
writer.write("\t\tTransport: " + getServices().get(serviceName).getTransport()); 
writer.write('\n'); 
writer.write("\t\tEnvelope: " + getServices().get(serviceName).getEnvelope()); 
writer.write('\n'); 
writer.write("\t\tReturns: " + getServices().get(serviceName).getReturns()); 
writer.write('\n'); 
writer.write("\t\tParameters: "); writer.write('\n'); 
for (Object params : getServices().get(serviceName).getParameters()){ 
if (params instanceof LinkedHashMap) { 
LinkedHashMap<String, Object> lhm = (LinkedHashMap<String, Object>) 
params; 
for (Iterator<String> j = lhm.keySet().iterator(); j.hasNext();) { 
String paramKey = j.next(); 
writer.write("\t\t\t"+paramKey+": "+lhm.get(paramKey)); writer.write('\n'); 
} 
writer.write('\n'); 
} 
} 
} 
writer.close(); 
} 
} 
Classe JsonLoginResponse.java 
package json; 
import org.codehaus.jackson.annotate.JsonIgnoreProperties; 
/** 
* Classe que define um objeto que mapeia a resposta do método Tinebase.login 
* TODO: Definir classe abstrata GenericResponse e especializar a classe result 
* para cada método a ser tratado 
* @author "Mário César Kolling" <mario.kolling@serpro.gov.br> 
*/ 
@JsonIgnoreProperties(ignoreUnknown = true) 
public class JsonLoginResponse { 
// Classe que Mapeia um Objeto Account 
// TODO: Defininir como uma classe do pacote json, ao invés de uma classe 
// interna da Classe JsonLoginResponse 
public static class Account { 
private String _accountId, _accountDisplayName, _accountFullName, 
_accountFirstName, 
_accountLastName, _contact_id; 
public String getAccountDisplayName() { 
return _accountDisplayName; 
} 
public String getAccountFirstName() { 
return _accountFirstName; 
} 
public String getAccountFullName() { 
return _accountFullName; 
} 
public String getAccountId() { 
return _accountId; 
} 
public String getAccountLastName() { 
return _accountLastName; 
} 
public String getContact_id() { 
return _contact_id; 
} 
public void setAccountDisplayName(String _accountDisplayName) { 
this._accountDisplayName = _accountDisplayName; 
} 
public void setAccountFirstName(String _accountFirstName) { 
this._accountFirstName = _accountFirstName; 
} 
public void setAccountFullName(String _accountFullName) { 
this._accountFullName = _accountFullName; 
} 
public void setAccountId(String _accountId) { 
this._accountId = _accountId; 
} 
public void setAccountLastName(String _accountLastName) { 
this._accountLastName = _accountLastName; 
} 
public void setContact_id(String _contact_id) { 
this._contact_id = _contact_id; 
} 
} 
// Classe que mapeia o resultado 
public static class Result { 
private String _jsonKey, _welcomeMessage, _errorMessage; 
private boolean _success; 
private Account _account; 
public Account getAccount() { 
return _account; 
} 
public String getJsonKey() { 
return _jsonKey; 
} 
public boolean getSuccess() { 
return _success; 
} 
public String getWelcomeMessage() { 
return _welcomeMessage; 
} 
public String getErrorMessage() { 
return _errorMessage; 
} 
public void setAccount(Account _account) { 
this._account = _account; 
} 
public void setJsonKey(String _jsonKey) { 
this._jsonKey = _jsonKey; 
} 
public void setSuccess(boolean _success) { 
this._success = _success; 
} 
public void setWelcomeMessage(String _welcomeMessage) { 
this._welcomeMessage = _welcomeMessage; 
} 
public void setErrorMessage(String _errorMessage) { 
this._errorMessage = _errorMessage; 
} 
} 
private int _id; 
private String _jsonrpc; 
private Result _result; 
public int getId() { 
return _id; 
} 
public String getJsonrpc() { 
return _jsonrpc; 
} 
public Result getResult() { 
return _result; 
} 
public void setId(int _id) { 
this._id = _id; 
} 
public void setJsonrpc(String _jsonrpc) { 
this._jsonrpc = _jsonrpc; 
} 
public void setResult(Result _result) { 
this._result = _result; 
} 
}

Linguagem Ruby – Conecta, Loga e Pesquisa Msgs do Usuário

Este script conecta, busca os serviços de um usuário não logado, loga um usuário, pesquisa na caixa de mensagens as mensagens do usuário e então lista os serviços do usuário logado.

require 'net/http' 
require 'rubygems' 
require 'json' 
#classe para fazer a conexão com o expresso3/tine20 
class JSONRPCTineConnection 
OUR_UNSAFE = /[^ _\.!~*'()a-zA-Z\d;\/?:@&=+$,{}\"-]/nm unless defined?(OUR_UNSAFE) 
@req = nil 
@uri = nil 
@host = nil 
@port = nil 
@json_key = nil 
@tine_key = nil 
def initialize(uri) 
@uri = URI.parse(uri) 
@host = @uri.host 
@port = @uri.port 
end 
def send(method, method_id, args=nil) 
@req = Net::HTTP::Post.new(@uri.request_uri, initheader = {'Content-Type' 
=>'application/json'}) 
json_body = {:jsonrpc => '2.0', :method => method, :id => method_id} 
json_body.merge!({:params => args}) unless args.nil? 
@req.body = uri_escape_sanely( json_body.to_json ) 
add_request_fields #headers e cookies 
response, body = Net::HTTP.new(@uri.host, @uri.port).start {|http| http.request(@req) } 
puts "Response #{response.code} #{response.message}: #{response.body}" 
json_return = JSON.parse(body) 
unless @tine_key && @json_key 
@json_key = json_return['result']['jsonKey'] if json_return['result'] 
@tine_key = response.get_fields('Set-Cookie').to_s.split(';')[0].split('=')[1] 
end 
puts "TINE_KEY: "+@tine_key if @tine_key 
puts "JSON_KEY: "+@json_key if @json_key 
return response, body 
end 
def close 
@req = nil 
@uri = nil 
@host = nil 
@port = nil 
@json_key = nil 
@tine_key = nil 
end 
protected 
def add_request_fields 
#headers sempre enviados 
@req.add_field 'User-Agent', 'Ruby JSON-RPC Client 2.0' 
@req.add_field 'Accept', 
#
#
'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' 
@req.add_field 'Content-Type', 'application/json; charset=UTF-8' 
@req.add_field 'X-Tine20-Request-Type', 'JSON' 
#
#header e cookie enviados pelo usuario logado 
@req.add_field 'X-Tine20-JsonKey', @json_key if @json_key 
@req.add_field 'Cookie', 'TINE20SESSID='+@tine_key if @tine_key 
end 
def uri_escape_sanely(str) 
URI.escape(str, OUR_UNSAFE).gsub('%5B', '[').gsub('%5D', ']') # Ruby's regexes are 
BRAIN-DEAD. 
end 
end 
def type(msg)  
sleep 1 #pausa para poder ler 
puts msg 
sleep 2 #pausa para observar os resultados 
end 
type "### Abrindo conexao com o servidor do expresso3/tine20" 
json_tine = JSONRPCTineConnection.new "http://<servidor>/tine20/index.php" 
#
#
type "### Listando metodos do usuario nao logado ###" 
response, body = json_tine.send , '1' 
#
#
type "### Efetuando login ###" 
#
#
response, body = json_tine.send 'Tinebase.login', '2', {"user" => 
'<username>',"password" => '<password>'} 
#
type "### Pesquisando contatos ###" 
response, body = json_tine.send 'Addressbook.searchContacts', '10' 
#
#
type "### Carregando mensagens ###" 
#
#
response, body = json_tine.send 'Expressomail.searchMessages', '21', 
{"filter"=>{"field"=>"flags","operator"=>"in","value"=>"\\Flagged"},"paging"=>{"sort"= 
>"received","dir"=>"DESC","start"=>0,"limit"=>50}} 
type "### Listando metodos do usuario logado ###" 
response, body = json_tine.send , '1' 

Autores

  • Bruno Vieira Costa bruno.vieira-costa@serpro.gov.br
  • Mario Cesar Kolling mario.kolling@serpro.gov.br
  • Fernando Lages fernando.lages@serpro.gov.br
  • Rommel Cysne rommel.cysne@serpro.gov.br
  • Cassiano Dal Pizzol cassiano.dalpizzol@serpro.gov.br
  • Walter Zapalowski walter.zapalowski@serpro.gov.br
Ferramentas pessoais
Espaços nominais

Variantes
Ações
Navegação
Ferramentas