Skip navigation

OpenVista CIS

11 Posts tagged with the openvista_cis tag
0

We've packaged and uploaded a new release candidate (RC2, a.k.a. 0.9.96) that includes a number of bugfixes that have been sitting on our code repository.  The packaged release should make it easier for end users to download and install.  You can grab the new release here.

 

Here's a list of the changes since the previous release:

  • Lengthy INTRO MESSAGE makes CIS login dialog unusable
  • CIS Reminder Dialog Incomplete Items Default
  • CIS- WVHDDR stage -Facility window should be persistent after resized
  • Fix the poppler-sharp config file.
  • wkfl0001 fails with CIS crasher
  • Reduce the startup time for the Login dialog.
  • LMCNY-Appts/Visit Section Under column labelled "Location" some entries display NUMBERS only
  • More strongwind test fixes
  • Reduce the amount time that takes to be able to interact with CIS's main window after selecting a patient.
  • Various tasks to facilitate open source development
  • WVDHHR stage-"No type of service" Processing error in CIS up on signing diet order and order gets cancelled.
  • [CIS BETA-LMC Med Order Dialog CIS Not Working]
  • Valid access/verify fail after previous failed login
  • [CIS BETA] Graphical display of VS unreadable
  • Fix artf4586.py strongwind test
  • [CIS BETA] IV rate missing in CIS
  • Additional Signers Dialog Box -Clicks
  • CIS- "Could not find a part of the path" crasher while printing Ped growth chart.
  • Note Selection Area--Cannot see all information
  • Crasher when attempting to print problem detail to a local printer
  • [CIS BETA LMCNY- Spell Check and Grammar Check missing in Template Editor]
  • Home Medications: Home medications bold if not released not working
  • Orders Detail: need to add additional patient identifiers
  • [TEST] Create strongwind test for artf4586
  • Crasher When Placing an Aspirin Order on a Patient Allergic to Aspirin.
  • Running CIS without the correct dependencies corrupts mono addins cache
  • [RELEASE] CIS 1.0-RC1 Open Source Release

 

Thanks to everyone who tested the previous RC!

587 Views 0 Comments Permalink Tags: release, release, openvista_cis
0

One of the features of OpenVista CIS is that it is extensible. Without modifying the core of CIS, you can drop in additional functionality, such as new application tabs, new image format rendering support, new preferences tabs, etc.

 

In order to make OpenVista CIS extensible, it uses Mono.Addins for a plugin system. This allows developers to dynamically add more functionality to CIS without having to change its internals. Mono.Addins allows developers to specify "extension points" and then inspect and load all extensions that attach to that extension point. Here is a simple example showing one of the CIS extension points, and a simple extension that implements it.

The Extension Point

Let's look at one of the core UI extension points in CIS, the IApplicationTab. This extension point is used to provide tabs visible in the main window of CIS. Here is the relevant code from the definition of that extension point interface:

using Gtk;

[Mono.Addins.TypeExtensionPoint ("/Interface/ApplicationTab")]
public interface IApplicationTab
{
     Widget LabelWidget {
         get;
     }
     Widget Widget {
          get;
     }
     .
     .
     .
}

 

This extension node is found in the Medsphere.OpenVista.Core.UI.dll assembly, and must define an "AddinRoot" in order to let this extension point be used. The following is from the AssemblyInfo.cs file in that assembly:

using Mono.Addins;

[assembly:AddinRoot ("Medsphere.OpenVista.Core.UI", "1.0")]

A Simple Extension

 

We are going to create a new assembly that contains our application tab extension. We need to specify both our addins dependencies, as well as advertise it the addin itself, in the AssemblyInfo.cs file:

using Mono.Addins;

[assembly: Addin]
[assembly: AddinDependency ("Medsphere.OpenVista.Core.UI", "1.0")]

 

Next we will define our simple hello world extension in HelloWorldSheet.cs:

using System;
using Gtk;
using Medsphere.OpenVista.Core.UI;

[Mono.Addins.Extension ("/Interface/ApplicationTab")]
public class HelloWorldSheet : IApplicationTab
{
        public Widget LabelWidget {
                 get { return _label; }
        }

        public Widget Widget {
                 get { return _widget; }
        }
        .
        .
        .
        public HelloWorldSheet ()
        {
                 _label = new Label ("Hello\nWorld");
                 _widget = new Label ("Hello World!");
        }

        Label _label, _widget;
}

We can now compile our addin with the following command line (of course, this could just as easily be done in Visual Studio, MonoDevelop, etc):

gmcs -r:Mono.Addins.dll -r:Medsphere.OpenVista.Core.UI.dll -pkg:gtk-sharp-2.0 \
     -t:library -out:Medsphere.OpenVista.CIS.Demo.dll HelloWorldSheet.cs AssemblyInfo.cs

 

Now when we run CIS, we see that our hello world application tab has been automatically loaded:

 

openvista-cis-hello-world-plugin.png

 

Conclussion

 

For further reading on Mono.Addins, check out the Mono.Addins page on http://www.mono-project.com/. If you want to get started on extending CIS, grab the CIS source code! The full source code for the simple CIS tab plugin is attached to this document, so you can see the full details.

676 Views 0 Comments 0 References Permalink Tags: c#, cis, mono_addins, openvista_cis_internals, openvista_cis, open_source
0

This instructions are the same instructions that are in the INSTALL file in our releases.

 

Prerequisite:

  • Make sure you uninstall any previous Gtk# installation before installing Gtk# from the installers we recommend.
  • If you had installed the Gtk# Runtime from those installers before, you must uninstall it before installing the Gtk# SDK (the Gtk# SDK and the Gtk# Runtime are mutually exclusive).
  • We only tested that OpenVistaCIS works properly with the Gtk# installer Medsphere provides.
  • Install the latest Gtk#'s SDK from here: http://sourceforge.net/projects/openvista/files/Gtk%23%20Windows%20Installers/

 

Download the latest release for OpenVistaCIS from http://medsphere.org/download/project/openvista-cis

 

Unzip it.

 

From VS .NET 2005, open the file OpenVista2k5.sln contained in the top level folder that the extraction process of the zip file created.

 

A few warning dialogs about the project location not being trusted will appear, just check the option of not showing the message again  and click ok.

 

Right click the OpenVista2k5 solution and select Properties.

Click "Startup Project" from the left tree view.

Click the "Single startup project" radio button, and then change the  selection in the combo to be OpenVistaCIS2k5.

Next, click the "Configuration Properties" item from the left tree view.

Uncheck the Build boxes next to Medsphere.OpenVista.Core.Test2k5,  Medsphere.OpenVista.Shared.Test2k5, and OpenVistaCIS.Test2k5 to indicate that they should not be built. Click Ok.

 

Building:

 

You should finally be able to build the solution by clicking Build -> Build Solution from the menu bar or pressing F6.

909 Views 0 Comments Permalink Tags: openvista_cis, building, compile, compiling, visual_studio_2005, visual_studio_2k5
0

Medsphere's OpenVistaCIS development team is happy and proud to announce OpenVistaCIS 1.0 Release Candidate 1.

 

Countless hours were spent to make this release happen by my team members Albert Gnandt, Andy Pardue, Bill Gibbons, Jon Tai, Peter Johanson, and our previous team members and friends Anthony Taranto, Brad Taylor, and Cody Russell; also kudos to our QA department's members Evangeline Nunez, Janet Michaels, Karthick Krishnan, Karuna Dantuluri, Kristina Borja, and Lynne Mundi; our documentation writer Kathy Steele; and project manager Fay Struble.

 

Some of the highlights for this release are:

 

  • Print support for the Graph widget.
  • Medical Reconciliation support.
  • Deprecation and removal of the Bridge.
  • and gazillions of bug fixes.

 

Release notes.

Download.

 

For those users running the Windows operating system, make sure you use the latest Gtk# installer.

542 Views 0 Comments Permalink Tags: openvista_cis, gtk, mono, c#, release, candidate, 2009, .net, client, gtk#
4

One of the things us CIS developer constantly face is the question, "What the heck does this RPC do?!" Seasoned (or masochistic) developers will often jump into FileMan, and inspect the entry from the REMOTE PROCEDURE and go on their merry way. However, for those of us looking for something a little easier on the eyes (and minds), one of our developers wrote a handy RPC reference page. We've put a copy of it up where other's can get to, so it's now available at:

 

http://medsphere.org/docs/vista-rpcs/

 

This is driven by a static file generated from the latest public release of OpenVista Server. Hope others find this useful!

934 Views 4 Comments Permalink Tags: openvista_server, remote_procedure_call, rpc, openvista_cis
0

P/Invoke, short term for Platform Invoke, is the mechanism provided by the .NET framework to invoke unmanaged code (methods or functions from libraries written in C or C++ programming languages) from managed code. As an example let's look at some code from the OpenVistaCIS code base.

 

Let's look at the code that brings spelling support. If you have CIS's source code available go ahead and read the file src/Medsphere.OpenVista.Spelling/AspellSpeller.cs. The basic P/Invoke suport is based on the use of the DllImport attribute. What the DllImport attribute does is to provide the information needed to call a function from unmanaged code, which is described by the method's signature (which involves the name, return type and parameters types).

 

In order to create an Aspell dictionary on OpenVistaCIS we have two external libraries definitions that take care of what's the platform we are running on, either GNU/Linux or MS Windows

[DllImport ("aspell-15.dll", EntryPoint="new_aspell_speller")]
private static extern IntPtr new_aspell_speller_win32 (IntPtr config);
 
[DllImport ("libaspell")]
private static extern IntPtr new_aspell_speller (IntPtr config);

 

The first parameter for the DllImport attribute is the library name, that for the Win32 version is aspell-15.dll but for the Linux version is libaspell, we have to define two external method declarations due to that fact, then for the Win32's signature comes a named argument called EntryPoint that let us map the declaration to the original name of the method in the unmanaged library, so in that case we map new_aspell_speller_win32 to new_aspell_speller. Another important thing that we must highlight is the use of the extern method's modifier to "mark" the method as being implemented externally (that allow us to just use semi-colon as the method's body. And finally, we must highlight the use of the IntPtr type to represent a pointer or handle that's coming back from the unmanaged library.

 

Now, the way we use them inside the managed code is as follows:

public AspellSpeller (AspellConfig config)
{
    if (IsWindows) {
        error = new AspellCanHaveError (new_aspell_speller_win32 (config.Handle));
    } else {
        error = new AspellCanHaveError (new_aspell_speller (config.Handle));
    }
    .
    .
    .
}

 

Where the IsWindows property is defined as:

private static bool IsWindows {
    get { return ((int)Environment.OSVersion.Platform <= 3); }
}

 


The types used in an external method declaration can go from very simple Int32, String or more complicated types that need explicit marshalling. One very detailed article about is the one found in the Mono project's Interop with Native Libraries. Check it out for more details about P/Invoke.

654 Views 0 Comments Permalink Tags: cis, linux, openvista_cis, openvista_cis_internals
2

Internationalization.

 

I really like the way the internationalization concept is presented in the Gettext1 manual so I am going to quote them:

"By internationalization, one refers to the operation by which a program, or a set of programs turned into a package, is made aware of and able to support multiple languages. This is a generalization process, by which the programs are untied from calling only English strings or other English specific habits, and connected to generic ways of doing the same, instead."

What that means is that an internationalized application is designed in such a way that as soon as the proper values for a specific locale is provided, the application is able adapt to those values and change it's behavior accordingly. For example an internationalized application that's given a proper translation package for a different language should be able to display the new strings/messages and modify the text orientation in case is needed depending on the locale.


In particular for applications written with Gtk# we want to be able to have the capability of displaying the different shapes depending on the actual locale. As a consequence of building OpenVistaCIS with Gtk+ which uses Pango as the layout and rendering engine for text we gained all that for free.

 

 

 

Localization.

 

 

 

I really like the way the localization concept is explained in the Gettext  manual so I am going to quote them again:

"By localization, one means the operation by which, in a set of programs already internationalized, one gives the program all needed information so that it can adapt itself to handle its input and output in a fashion which is correct for some native language and cultural habits. This is a particularization process, by which generic methods already implemented in an internationalized program are used in specific ways."

In general what a locale must describe is the kind of characters and codesets, the currency, how dates are displayed, the type of number representation, and the last but no least the messages.

The way we ensure that OpenVistaCIS is easily translatable is making us of Gettext's routines everytime we want to show or display a message. The class that contains such methods is named Catalog and can be found in the file src/Medsphere.OpenVista.Shared/utilities/Catalog.cs.

The important pieces of that class are the methods GetString and GetPluralString

 

public class Catalog {     public static string GetString (string s)     {     }     public static string GetPluralString (string s, string p, int n)     {     } }

 

 

That we use it as follows:

 

TreeViewColumn primary = FactorsTreeView.AppendColumn (Catalog.GetString ("Primary"), toggle, new TreeCellDataFunc (FactorsListRenderer))

 

or

 

protected override string MessagePrefix {     get {        return Catalog.GetPluralString ("The surrogate settings cannot be set because of the following error",                                        "The surrogate settings cannot be set because of the following errors",                                        validator_group.InvalidCount);    } }

 

Now, the interesting part comes when third party contributor want to help translation OpenVistaCIS. The way all the pieces come together is the following. In our source code tree we have a subdir called po, you'll find various incomplete translation files de_DE.po, es_AR.po, pt_BR.po, and th.po. There must be on .po file per language.

In case you want to contribute to any of the languages that we already have translations for do the following:

Go to the po/ subdir and type:

 

make update-po

 

That command will update the current translation files from the source code.

Then you should edit the .po file for the language you want to contribute to, after that perform the following command:

 

intltool-update --dist language-you-edited.po

 

And send us the language-you-edited.po file so we can update the translation files.

 

In case you want to create a translation for a new language do the following:

 

msginit --locale=ll_CC

 

where ll_CC is formed with ll being a language code and CC should be a country code. For example for a Mexican spanish translation you would perform the following command:

 

msginit --locale es_MX

 

and a new file named es_MX.po should get created.

Now that you have your favorite language's template you can go crazy translating the strings contained in it.

When you run penVistaCIS you can change the language that OpenVistaCIS uses by setting an environment variable:

 

export LANG=ll_CC

 

For example, the code below would make OpenVistaCIS use the german language:

 

export LANG=de_DE

 

1 http://www.gnu.org/software/gettext/

1,065 Views 2 Comments Permalink Tags: i18n, l10n, openvista_cis, openvista_cis_internals, translation, translate, multilingual
0

Accessibility in the context of software can be defined as how a user with disabilities can access electronic information, that is achieved through the use of assistive technologies (AT's) such as voice interfaces, screen readers, alternate input devices, etc.


OpenVistaCIS is developed with C# and Gtk#, Gtk# is the C# wrapper for the Gtk+ user interface toolkit which has accessibility support built-in. The way all works is the following:

- The applications (Gtk+ apps, Firefox, OpenOffice, QT apps) are the producers of accessibility information.

- The Assistive Technologies (screen readers such as Orca and LSR, automated test frameworks such as Strongwind, Dogtail or LDTP, and accessibility explorers like Accerciser) are the consumers of the accessibility information.

- The producers provide the accessibility information by implementing the appropriate interfaces from the Accessibility Toolkit (ATK). ATK defines a set of interfaces that must be implemented by the UI components in order to make them accessible.


- For Gtk, the implementation of such interfaces is in a library called GAIL (GNOME Accessibility Implementation Library). GAIL is dynamically loadable at runtime by an application written in Gtk (you must set the environment variable GTK_MODULES to
  gail:atk-bridge in order to enable assistive technology support).

- On Linux all the information required by the Assistive Technologies is provided by a toolkit-independent Service Provider Interface (SPI) that exposes a stable API and gets its data from the specific accessibility toolkit API (ATK on Linux) through a bridge (atk-bridge on Linux).

For testing OpenVistaCIS Medsphere Systems Corporation developed Strongwind, Strongwind is an automated UI test framework inspired by Dogtail. Strongwind internally uses the py-atspi python binding for at-spi to get access programatically to the different widgets and exercise the functionality provided by the application.

448 Views 0 Comments 0 References Permalink Tags: openvista_cis, a11y
0

Medsphere's open source release of OpenVista CIS allows you to download, examine, build, run, and modify the application. One of the easiest ways to manipulate the codebase is to use an integrated development environment (IDE). On Linux, the MonoDevelop project offers a fully functional open source IDE. You should be able to install MonoDevelop using your GNU/Linux distribution's package manager.

 

 

 

Next, you'll need to download the OpenVista CIS code. All of Medsphere's open source code is available from sourceforge.net. The list of available code archives can be found here. Although archives of specific subsections of the the codebase are offered, as well as a few different formats, this tutorial describes using the .zip file containing the entire codebase. You can download the current version (0.9.9) by clicking here.

 

 

 

Now, you'll extract the source tree from the file you've downloaded. There are a few ways to do this. From the command line, we can cd into the directory that contains the .zip file and run the following command:

 

 

 

$ unzip openvistacis-0.9.9.zip

 

 

 

This will create a directory called openvistacis-0.9.9 that contains the source code and configuration information of the project. You may also be able to extract the file using your desktop environment. For example, in the GNOME desktop, you can right click on the file and select ""Extract Here" from the context menu as shown:

 

 

 

MonoDevelop0.png

 

 

 

Extracting the archive creates a new directory. In the top level of this new directory you will find a file named OpenVista.mds. This is the MonoDevelop solution file. You can open this file in a few ways. You can invoke MonoDevelop from the command line:

 

 

 

$ monodevelop OpenVista.mds

 

 

 

Depending on your desktop environment, you may also be able to double click the OpenVista.mds file to start MonoDevelop. Finally, you can open the file from within MonoDevelop by choosing "Open..." from MonoDevelop's "File" menu, or by clicking "Open a Solution / File" from the MonoDevelop welcome screen.

 

 

 

MonoDevelop1.png

 

 

 

Once you've opened the solution file, you'll see the list of assemblies that comprise the OpenVista CIS codebase.

 

 

 

MonoDevelop2.png

 

 

 

There are three executables contained within the OpenVista CIS project source tree.

 

  1. OpenVista CIS, the main client GUI.

  2. OpenVista Vitals, the vital signs functionality from CIS, deployable as a standalone application.

  3. Bridge, a middleware layer that handles RPC communication with the VistA Broker and provides a Binary Remoting interface to the client.

 

The most straightforward method of running OpenVista CIS is to connect to the Bridge running on the OpenVista Public Demo server. To do this, you won't need to run your own Bridge locally, or the OpenVista Vitals app. To prevent MonoDevelop from starting these applications, right click on the first/top row of the Solution list and select "Options" from the context menu.

 

 

 

MonoDevelop3.png

 

 

 

From the list on the left of the "Solution Options" dialog, select "Startup Properties". You'll notice that the "Multiple Startup Project" radio button is active. Since you only want to start OpenVista CIS, activate the "Single Startup Project" radio button and choose "OpenVistaCIS" from the menu underneath. Click "OK" when you are finished.

 

 

 

NOTE: Due to a minor bug in MonoDevelop 1.0, when you select "Startup Properties", the correct user interface may not appear. Instead, you may see the text "label5". In this case, select any of the other option categories in the list ("Solution Information" for example, and then reselect "Startup Properties".

 

 

 

MonoDevelop4.png

 

 

 

 

 

Now we are ready to build and run OpenVista CIS from within MonoDevelop. To do this, choose "Run" from MonoDevelop's "Project" menu. You can also use the keyboard shortcut to invoke this action by pressing the F5 key. Since OpenVista CIS is a rather large program and you must build the entire tree at this time, this step may take some time. Subsequent builds only need to rebuild modified sections of the codebase, and will likely be much faster. When the build process finishes, you'll notice that two windows appear on your screen.

 

 

 

  1. An empty terminal window titled "MonoDevelop External Console". Any output from OpenVista CIS that is sent to stdout or stderr will appear in this window. It can be a useful tool to diagnose and fix errors in the program, and to allow you to see the output of print statements you've inserted into the code.

  2. The OpenVista CIS login dialog, entitled "Connect to Medsphere OpenVista Server". Note that for security purposes this window and the application will close after a period of inactivity.

 

 

 

To login to the OpenVista Public Demo Server as a physician user, enter "PU1234" into the Login ID entry, "PU1234! In future posts, we'll discuss how to make changes to the codebase using MonoDevelop.

1,158 Views 0 Comments 0 References Permalink Tags: cis, mono, monodevelop, linux, openvista_cis, tutorial, walkthrough
0

One of the major benefits of OpenVista CIS is that it empowers users to choose the platform to run on.  At the core, we use Microsoft .NET on Windows platforms and Mono on others.  The user interface is developed using GTK+, which is portable across Windows, Linux (and other Unix variants such as OpenSolaris and FreeBSD), and MacOS X.  This is one of the major reasons that it was chosen as the development platform for Medsphere OpenVista client applications.  I'll try to give a brief introduction to the platform stack here, as many new CIS developers may be coming from a different development background.

 

GTK+ is written entirely in C, and has binding layers to other languages such as C++, Ruby, and Perl.  Medsphere uses the Gtk# binding to develop OpenVista CIS using GTK in C#.  The Gtk# binding layer gives us the cross-platform user interface toolkit but with the power and ease of C#; it connects the Mono/.NET garbage collector with GTK's reference counting system for memory management, maps GLib containers that are used by GTK+ to System.Collections (the container class library used by .NET and Mono), maps between the events and delegates in Mono/.NET and the signal slots and C function callbacks used in unmanaged land, and generally allows us to almost[1] seamlessly work with the GObject memory space as though it were part of the .NET object system.

 

The GTK+ stack is split into various components:

  • GLib provides general utility functions and cross-platform suppport.  It provides the mainloop that GTK+'s event processing is built on top of, and it provides GObject.  GObject is the basis for the object system on which GTK+ is written.  Yes, GTK+ is written in C and is also object-oriented.
  • ATK is the accessibility toolkit.  Essentially, this provides the groundwork for alternate input and interface methods, which allowed the application to be more easily accessible for impaired users (such as vision-impaired users, for example).  It is also the basis for how Medsphere's automated testing framework, Strongwind, is able to automate actions on the user interface.
  • Pango is the font and text rendering library.  It supports a lot of fairly advanced things that you may never need, but they're available.  For example, Pango supports bidirectional text layout for languages such as Hebrew and Arabic.
  • Cairo is the vector graphic renderer that GTK uses for a lot of its graphics.  We also use this directly for things such as the Graph widget.  It allows us to render really beautiful scalable vector graphics with high-quality antialiasing.
  • Gdk is the low-level windowing side of GTK+, and is the place that abstracts between the different windowing systems of Win32, MacOSX, and the X-Window System that is used by Linux.  This deals with the basic input and output of the whole user interface.
  • Gtk is the main widget library that handles such things as buttons, labels, and treeviews.  Note that Gtk typically does not use platform native controls (the one exception is the print dialog on Win32).  It implements all the controls using its own widget system and then optionally uses a theme engine to make them look like native controls.  This has a distinct advantage for us over using native controls in that we get the same behavior across different platforms, and we get a consistent API to develop with across them all.
  • The theme engine is what styles the widgets to look the way they do.  For example, on Win32 platforms the theme engine uses the native parts and states Win32 APIs to draw the GTK widgets to look like native Windows controls.

 

Medsphere adds a few more open-source components to the CIS stack, on top of GTK+ itself:

  • libglade allows us to design dialogs that are saved in XML files and loaded at runtime.
  • poppler# is a C# binding for the poppler PDF renderer
  • Mono.Addins is used for loading plugins at runtime

 

[1].  Note that the one thing we can't yet treat seamlessly between the GObject system and the .NET object model are interfaces.  Like .NET, GObject supports single inheritance and interfaces, but the glue between them is not yet in a place where we can use it.

587 Views 0 Comments 0 References Permalink Tags: openvista_cis, openvista_cis_internals, gtk
0

Overview

CIS includes an assembly consisting of core functionality, called Medsphere.OpenVista.Core. In this assembly, our core "service" infrastructure, consists of ServiceManager, IService, and the attributes ServiceReferenceAttribute and LazyServiceAttribute. A service is any persistent object/model you want accessed by any other part of the software. It loosely fills the role of "Singleton" but providing a mechanism for abstracting things out behind interfaces, to allow for platform/application dependant implementation of certain services, and to aid in unit testing. Services are accessed via ServiceManager, and can be registered into ServiceManager one of two ways:

  1. Manually using ServiceManager.RegisterService (IService service)

  2. Dynamically via Mono.Addins by decorating the IService subclass with [Mono.Addins.Extension ("/Core/Services")]

IService

IService is the base interface for all services. It is extremely simple, as of this writing:

public interface IService
{       
        /// Initialize any resources needed by the service.
        /// @return Used to indicate success/failure in intializing any needed resources.
        bool Initialize ();
}

Creating an IService Subclass

At a minimum, you need to implement the IService interface in a subclass, and manually register the service with ServiceManager.RegisterService (IService service). After the service is registered, it can be accessed via IService ServiceManager.GetService (Type type). Here's a rough psuedo-C# example:

public class MyService : IService
{
        public string Name { get { return "MyService"; } }

        public bool Initialize () { return true; }
}

// Create the service instance.
IService my_service = new MyService ();

// Services registered dynamically are automatically initialized,
// but since we're doing it manually, we'll do it by hand here.
my_service.Initialize ();

// Register the service.
ServiceManager.RegisterService (my_service);

// Fetch the service back, and verify it's the right service.
IService my_service_2 = ServiceManager.GetService (typeof (MyService));
Assert.AreEqual (my_service, my_service_2);

Dynamically Registered Service

If you would like CIS to automatically register your service into ServiceManager at start-up, via Mono.Addins, you do the following:

[Mono.Addins.Extension ("/Core/Services")]
public class MyService : IService
{
        public string Name { get { return "MyService"; } }

        public bool Initialize () { return true; }
}

Lazy Loaded Services

NOTE: The following section only applies to services dynamically registered via Mono.Addins.

You can also make dynamically registered services be "lazy loaded", that is, they will not be created nor initialized until someone attempts to fetch references to them. This improves application start time by avoiding having to load all services when the application is first run. To make you service lazy-loaded, simply decorate it with the LazyServiceAttribute. Here's an example:

[LazyService]
[Mono.Addins.Extension ("/Core/Services")]
public class MyService : IService
{
        public string Name { get { return "MyService"; } }

        public bool Initialize () { return true; }
}

When the service is needed, because of a ServiceDependencyAttribute, a ServiceReferenceAttribute or when requted via ServiceManager.GetService, the service, and any services it depends on, will be loaded and initialized.

Conventions

There are a few conventions and best practices that can aid you in writing services.

  1. Most services should use an intermediary interface that defines the public API of the service. E.g. MyService -> IMyService -> IService. This will aid in unit testing code that consumes those services.

  2. Service sub-interfaces and subclasses should have names ending in 'Service', e.g. IFooService and FooService.

Service Dependencies

If your service depends on other services being loaded first (either to consume/use them, or due to potential load order issues), you can use ServiceDependencyAttribute on your service class. Here's an example:

[ServiceDependency (typeof (IMyOtherService))]
[Mono.Addins.Extension ("/Core/Services")]
public class MyService : IService
{
        public string Name { get { return "MyService"; } }

        public bool Initialize () { return true; }
}

This will ensure that IMyOtherService is loaded and initialized before MyService.

Fetching Services, Two Approaches

There are two approaches to fetching references to services from ServiceManager. One, as previously mentioned is to use IService ServiceManager.GetService (Type type). The other way is to use the ServiceReferenceAttribute applied to fields on your class.

IService ServiceManager.GetService (Type type)

The direct way to fetch a service is with IService ServiceManager.GetService (Type type). Here is an example:

IMyService my_svc = ServiceManager.GetService (typeof (IMyService)) as IMyService;

ServiceManager will return null if the service is not found, so often you will want to add a null check to ensure you got the service you wanted from ServiceManager.

ServiceReferenceAttribute and ServiceManager.BindFields (object obj, Type type)

The other way to get references to services registered into ServiceManager is to decorate your fields with the ServiceReferenceAttribute, e.g.:

public class MyServiceConsumer
{
        [ServiceReference]
        private IMyService my_svc;

        public MyServiceConsumer ()
        {
                ServiceManager.BindFields (this, typeof (MyServiceConsumer));
        }
}

You'll notice that in order to have the fields actually set to the references of the service, the class must call ServiceManager.BindFields (object obj, Type type). This call makes ServiceManager iterate over all the fields in the class, and assign values to the ones decorated with the ServiceReferenceAttribute.

NOTE: For IService subclasses that are dynamically registered via Mono.Addins, you do not need to use ServiceManager.BindFields. The fields will automatically be bound by ServiceManager after your service is created, and before the IService.Initialize () method is called on your service. This convenience allows you to write services that consume other services very easily.

Conclusion

The ServiceManager functionality provided in Medsphere.OpenVista.Core provides a powerful way to create persistent, shared models between parts of CIS, CIS plugins, etc. When writing CIS plugins, or enhancing the base CIS code, it is the prefered way to achieve a singleton pattern, with all the benefits that come from interface abstraction, etc. Some example services you can see in CIS are:

  • Medsphere.OpenVista.Shared.UI.FontService

  • Medsphere.OpenVista.Shared.UI.UserIdleService

  • Medsphere.OpenVista.Shared.UI.MessageService

694 Views 0 Comments 0 References Permalink Tags: openvista_cis, openvista_cis_internals, openvista_cis