Blitz Gateway documentation
---------------------------

The epydoc-generated documentation of methods provided by OMERO Gateway
is available showing :javadoc:`wrapper classes <epydoc/omero.gateway-module.html>`.

Specifically, the API for the 'conn' connection wrapper created above is
:javadoc:`here <epydoc/omero.gateway._BlitzGateway-class.html>`.

When working with :javadoc:`OMERO model objects <slice2html/omero/model.html>`
(omero.model.Image etc) the Gateway will wrap these objects in classes
such as :javadoc:`omero.gateway.ImageWrapper <epydoc/omero.gateway._ImageWrapper-class.html>`
to handle object loading and hierarchy traversal. For example:

::

    >>> for p in conn.listProjects():         # Initially we just load Projects
    ...     print p.getName()
    ...     for dataset in p.listChildren():      # lazy-loading of Datasets here
    ...             print "  ", dataset.getName()
    ... 
    TestProject
       Aurora-B
    tiff stacks
       newTimeStack
       test
    siRNAi
       CENP
       live-cell
       survivin

Access to the OMERO API services
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you need access to API methods that are not provided by the gateway
library, you can get hold of the |OmeroApi|.

.. note::
 
    These services will always work with omero.model objects and not the
    gateway wrapper objects.

The gateway handles creation and reuse of the API services, so that new
ones are not created unnecessarily. Services can be accessed using the
methods of the underlying :javadoc:`Service
Factory <slice2html/omero/api/ServiceFactory.html>`
with the Gateway handling reuse as needed. Stateless services (those
retrieved with get… methods e.g.
:javadoc:`getQueryService <slice2html/omero/api/ServiceFactory.html#getQueryService>`)
are always reused for each call, e.g. blitzon.getQueryService() whereas
stateful services e.g.
:javadoc:`createRenderingEngine <slice2html/omero/api/ServiceFactory.html#createRenderingEngine>`
may be created each time.

Not all methods of the service factory are currently supported in the
gateway. You can get an idea of the currently supported services by
looking at the source code under the
:javadoc:`\_createProxies <epydoc/omero.gateway-pysrc.html#_BlitzGateway._createProxies>`
method.

Example: ContainerService can load Projects and Datasets in a single
call to server (no lazy loading)

::

    cs = conn.getContainerService()
    projects = cs.loadContainerHierarchy("Project", None, None)
    for p in projects:                # omero.model.ProjectI
        print p.getName().getValue()     # need to 'unwrap' rstring
        for d in p.linkedDatasetList():
            print d.getName().getValue()

Stateful services, reconnection, error handling etc
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The Blitz gateway was designed for use in the |OmeroWeb| framework and it is
not expected that stateful services will be maintained on the client for
significant time.
There is various error-handling functionality in the Blitz gateway that
will close existing services and recreate them in order to maintain a
working connection. If this happens then any stateful services that you
have on the client-side will become stale. We will attempt to document
this a little better in due course, but our general advice is to create,
use and close the stateful services in the shortest practicable time.

Overwriting and extending omero.gateway classes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

When working with
:javadoc:`omero.gateway <epydoc/omero.gateway._BlitzGateway-class.html>`
or wrapper classes such as
:javadoc:`omero.gateway.ImageWrapper <epydoc/omero.gateway._ImageWrapper-class.html>`
you might want to add your own functionality or customize an existing
one. NB: Note the call to ``omero.gateway.refreshWrappers()`` to ensure
that your subclasses are returned by calls to getObjects() For example:

::

    class MyBlitzGateway (omero.gateway.BlitzGateway):

        def __init__ (self, *args, **kwargs):
            super(MyBlitzGateway, self).__init__(*args, **kwargs)
            
            ...do something, e.g. add new field...
            self.new_field = 'foo'

        def connect (self, *args, **kwargs):
                    
            rv = super(MyBlitzGateway, self).connect(*args,**kwargs)
            if rv: 
                ...do something, e.g. modify new field...
                self.new_field = 'bla'
            
            return rv
        
    omero.gateway.BlitzGateway = MyBlitzGateway

    class MyBlitzObjectWrapper (object):
        
        annotation_counter = None

        def countAnnotations (self):
            """
            Count on annotations linked to the object and set the value
            on the custom field 'annotation_counter'.

            @return     Counter
            """
            
            if self.annotation_counter is not None:
                return self.annotation_counter
            else:
                container = self._conn.getContainerService()
                m = container.getCollectionCount(self._obj.__class__.__name__, type(self._obj).ANNOTATIONLINKS, [self._oid], None)
                if m[self._oid] > 0:
                    self.annotation_counter = m[self._oid]
                    return self.annotation_counter
                else:
                    return None

    class ImageWrapper (MyBlitzObjectWrapper, omero.gateway.ImageWrapper):
        """
        omero_model_ImageI class wrapper overwrite omero.gateway.ImageWrapper
        and extends MyBlitzObjectWrapper.
        """
        
        def __prepare__ (self, **kwargs):
            if kwargs.has_key('annotation_counter'):
                self.annotation_counter = kwargs['annotation_counter']

    omero.gateway.ImageWrapper = ImageWrapper

    # IMPORTANT to update the map of wrappers for 'Image' etc. returned by getObjects("Image")
    omero.gateway.refreshWrappers()

This page provides some background information on the OMERO Python client
'gateway' (omero.gateway module) and describes work to improve the API.

The Blitz Gateway is a Python client-side library that facilitates working
with the OMERO API, handling connection to the server, loading of data objects
and providing convenience methods to access the data. It was originally
designed as part of the |OmeroWeb| framework, to provide connection and data
retrieval services to various web clients. However, we have now decided to
encourage its use for all access to the OMERO Python API.

Wrapper objects
^^^^^^^^^^^^^^^

The Gateway consists of a number of wrapper objects:

Connection wrapper
""""""""""""""""""

The BlitzGateway class (see :javadoc:`API of development code <epydoc/omero.gateway._BlitzGateway-class.html>`)
is a wrapper for the OMERO client and session objects. It provides
various methods for connecting to the OMERO server, querying the status
or context of the current connection and as a starting point for
retrieving data objects from OMERO.

::

    from omero.gateway import *

    conn = BlitzGateway("username", "password", host="localhost", port=4064)
    conn.connect()

    for p in conn.listProjects():
        print p.name

Model object wrappers
"""""""""""""""""""""

OMERO model objects, e.g. omero.model.Project, omero.model.Pixels etc.
(see :javadoc:`full list <slice2html/omero/model.html>`)
are code-generated and mapped to the OMERO database schema. They are
language agnostic and their data is in the form of omero.rtypes as
described in :ref:`about model objects <AdvancedClientDevelopment#Objects>`).

::

    import omero
    from omero.model import *
    from omero.rtypes import rstring
    p = omero.model.ProjectI()
    p.name = rstring("My Project")   # attributes are all rtypes
    print p.getName().getValue()     # getValue() to unwrap the rtype
    print p.name.val                 # short-hand 

To facilitate work in Python, particularly in web page templates, these
Python model objects are wrapped in Blitz Object Wrappers. This hides
the use of rtypes.

::

    import omero
    from omero.model import *
    from omero.rtypes import rstring
    p = omero.model.ProjectI()
    p.setName(rstring("Omero Model Project"))   # attributes are all rtypes
    print p.getName().getValue()                # getValue() to unwrap the rtype
    print p.name.val                            # short-hand

    from omero.gateway import *
    project = ProjectWrapper(obj=p)             # wrap the model.object
    project.setName("Project Wrapper")          # Don't need to use rtypes
    print project.getName()
    print project.name

    print project._obj                  # access the wrapped object with ._obj

These wrappers also have a reference to the BlitzGateway connection wrapper,
so they can make calls to the server and load more data when needed (lazy
loading).

E.g.

::

    # connect as above
    for p in conn.listProjects():
        print p.name
        for dataset in p.listChildren():   # lazy loading of datasets, wrapped in DatasetWrapper
            print "Dataset", d.name

Wrapper coverage
""""""""""""""""

The OMERO data model has a large number of objects, not all of which are used
by the |OmeroWeb|. Therefore, the Blitz gateway (which was
originally built for this framework) has not yet been extended to wrap every
omero.model object with a specific Blitz Object Wrapper. The current list of
object wrappers can be found in the omero.gateway module
:javadoc:`API <epydoc/omero.gateway-module.html>`.
As more functionality is provided by the Blitz Gateway, the coverage of object
wrappers will increase accordingly.