Showing posts with label gaphor. Show all posts
Showing posts with label gaphor. Show all posts

Tuesday, March 23, 2010

Stable Gaphor

Its been a while in beta mode but Gaphor 0.15.0 stable is now available for download. Try it out if you haven't already. It is the ideal UML modeling tool for Python developers.

Tuesday, January 26, 2010

Gaphor 0.15.0 Beta

Gaphor, the UML modeling tool written in Python, has a new release available. The 0.15.0 beta release has many enhancements and features but there are two notable fixes that make this beta release a worthwhile upgrade from the latest stable release.

The latest stable Gaphor release introduced an element editor dialog. This dialog was a nice enhancement because it freed up more space for the diagram canvas. However, it was painful to use if you have multiple desktop windows open. Trying to switch between windows was a hassle. This has been fixed by making the element editor a modal dialog that is part of the main Gaphor window.

Another huge improvement was made in the element editor dialog. It can now be re-sized. This doesn't sound like a big deal but if you wanted to work with a large class that has dozens of attributes and methods, you simply could not do it. Now you can.

Thursday, October 29, 2009

Gaphor Idle Threads

The Gaphor UML modeling tool written in Python uses GTK as its' user interface library. GTK is a good choice as it is portable across many platforms and has a nice feature set. What is also nice about the GTK library, from a development perspective, is it as fairly straightforward to handle events that are triggered from the user interface. Such events may be user-generated, such as mouse clicks on widgets. Other events, may be generated by the widgets themselves. Either way, adding a handler for any event such as these is trivial. Using gobject, developers can also add handlers that are executed in between events, such as when the event loop is idle.

In any GTK application, there is a main event loop that must be instantiated within the application code. This is going to be one of the very first actions executed because without it, there will be no responses to GTK events. Every time an event is triggered inside a GTK main event loop, the event instance is placed in a pending event queue. Once the event has been processed, or handled, the event is no longer considered pending and is removed from the queue. So what this means is that the GTK main loop can be viewed, at a high level, as having two distinct states; pending and free. These states are illustrated below.



Here, the initial state represents the instantiation of the GTK main event loop while the final state represents the termination of the main loop. The termination often means that the user has exited the application successfully but could also mean that the application has exited erroneously. Regardless, there are longer any GTK events that will be processed once the main loop has exited, even if the containing application has not exited.

As illustrated, the GTK main loop as to states while running and two transitions between these states. The GTK main event loop will transition to a pending state when there are one or more pending events. The GTK main event loop will transition to a free state when there are zero pending events.

Gaphor defines an idle thread class that makes good use of all this GTK event machinery. The GIdleThread class uses gobject.idle_add() to add a callback to the GTK main event loop. This callback is only executed when there are zero pending events. Actually, it will still execute if there are pending events with a lower priority but that doesn't necessarily concern the concept here. The key concept is that the callbacks created by GIdleThread are only executed when the GTK main loop is idle. The GIdleThread class is illustrated below.



So the nagging question from developers is, why add this abstraction layer on top of the gobject.idle_add() function? Simply put, the GIdleThread class is used to assemble queues when the GTK main loop isn't busy. The obvious benefit here being that queues of arbitrary size can be assembled without sacrificing responsiveness to the end user.

An example use of this class is to read and parse data files. The generator function that yields data is passed, along with the queue that will eventually contain all the parsed data to the GIdleThread constructor. This abstraction also provides the thread-like feeling for developers that use it. Although not a real thread, it looks and behaves like one and is ideal for constructing queues.

Saturday, September 19, 2009

Injecting Gaphor Services

The Gaphor UML modeling tool is more than just a simple diagram editor.  It is also a powerful application architecture, capable of being used outside of the UML context.  What makes it so powerful is that the elements that make up Gaphor are clearly separated into services, components, and adapters.  The Gaphor architecture is important in how it glues all these pieces together.

Gaphor is built on top of several services that support the application as a whole.  There are many required services that are distributed along with Gaphor.  For example, there is an element factory service which is responsible for creating and managing the various UML elements.  These services are then loaded during the Gaphor startup process by iterating through entry points and instantiating the service classes.  This, in fact, is how other Python packages would define Gaphor services.

These services also work the other way around;  existing services can be used by other Python applications instead of defining the service for Gaphor to use.  The services can be used by other applications by invoking the Gaphor injection mechanism.  There are a few precautions to take when using this mechanism and they are illustrated in the example below.

#Example; Gaphor service injection.

#Do the Gaphor imports.
from gaphor.core import Application, inject
from gaphor.UML import Class

#A class is required in order to store the injected service
#as a class attribute.
class Gaphor(object):
    
    #Inject the element factory service.
    element_factory = inject('element_factory')
    
    #Initialize the application which will,
    #in turn, initialize the services.
    def __init__(self):
        Application.init()

#Main
if __name__=="__main__":
    
    #This will not work.  It serves as an illustration as to
    #why a class attribute is necessary.
    try:
        print inject('element_factory').create(Class)
    except:
        pass
    
    #This will work.  First, create and initialize the
    #Gaphor application singleton.  Next, interact with
    #the element factory service.
    app=Gaphor()
    print app.element_factory.create(Class)

Thursday, July 23, 2009

Gaphor 0.14.0 Element Editor

The 0.14.0 Gaphor release has a new element editor widget. This element editor is displayed as a separate window instead of being displayed at the bottom of the modeling canvas. This allows for more space when working with larger models. Some people are not big fans of desktop applications with multiple windows. In most cases, it shouldn't be necessary. However, any application that requires a type of canvas interface such as UML modeling tools and image manipulation applications, the more space in the primary window, the better.

Also new in the 0.14.0 Gaphor release is the notion of abstract classes and static attributes. I myself have been waiting a while for this feature and am pleased to finally see it. Both of these features are illustrated below.

Friday, May 1, 2009

How Gaphor Checks Association Ends.

With the Unified Modeling Language, comes a well defined meta model. It is this meta model that defines the semantics of the modeling elements available within the UML. An important feature of this meta model is consistency enforcement. The semantic rules defined in the UML meta model not only supply the UML modeling element but also govern how those elements may be used in relation to one another. If these rules, specified by the meta model could be verified for any given UML model, it could provide a means of ensuring a consistent model. As an example UML element that has the potential to be validated for consistency, consider the two ends of an association. One end could be a subset of the opposite end. There are a couple ways that this arrangement could go wrong. There could be missing names or there could multiplicity inconsistencies. The Gaphor UML modeling tool provides a checkmetamodel plugin that is capable of validating the association ends, as well as other potential meta model issues. This plugin can be viewed by selecting "Tools", "Check UML model". Illustrated below is the dialog that will be displayed. Only errors will be displayed here so if there is no content, the current Gaphor UML model is consistent with the Gaphor UML meta model.



When the checkmetamodel plugin validates the UML model, there are three functions involved. These functions are check_associations(), check_association_ends(), and check_association_end_subsets(). The check_association_end_subsets() function is important when validating association ends. It is the only validation that actually takes place on associations. The check_associations() and check_association_ends() functions exist for infrastructure purposes. If new functionality were to be added to Gaphor association or Gaphor association end checking, it would be placed in one of these functions. As the same suggests, the check_association_end_subsets() function will make sure that any association ends that are subsets of the opposite association end are consistent with one another. There are two basic tests to make this happen. First, the plugin will make sure that a given association end that is a subset of the opposite association end, contains names that actually exist in the opposite set. There can't be a subset property which contains elements that do not exist in the referenced set. Next, all multiplicity upper bounds in the subset need to be consistent with the upper bounds of the opposite set. This will ensure a multiplicity consistency amongst association end subsets.

With Gaphor, these meta model consistency checks are especially important because the meta model is loaded into Gaphor as any other UML model would be. If the core Gaphor UML meta model fails, there isn't much hope for any models created by users. The checkmetamodel plugin also offers potential for adding additional checking functionality.

Monday, March 30, 2009

Gaphor editor adapters

The Gaphor UML modeling tool, which is written in Python, uses a pop-up style editor widget which allows in-line editing of certain diagram elements. The widget itself isn't overly-interesting. It makes trivial changes to modeling elements quicker which is always helpful in any software solution. What we are interested in here is the method used to display the widget based on the element type. Gaphor relies heavily on the Zope interface and component frameworks. The Zope interface framework is utilized by Gaphor to define various interfaces that are provided by classes throughout the application. The component framework is utilized for the purpose of registering components and adapters. What exactly are adapters? Adapters are a type of component, automatically created by Zope when using the interface and component framework in conjunction with one another. This doesn't happen by itself; there are some carefully placed rules involved with defining adapters. When used right, Zope adapters are a very powerful tool that provide maximum usage of an interface. Gaphor defines an extensive set of Zope adapters. Here we are interested in the editor adaptor.

There are actually several adapters created for the IEditor interface, one for each diagram element that supports the editor widget. The Gaphor adapter approach is an alternative design to providing behavior that varies by type. A more traditional approach may have been to create a class hierarchy for the editor widget. Each class in the hierarchy would correspond to a different diagram element type. The differing behavior would then be implemented in each class in the hierarchy while similar behavior remains untouched and varying behavior gets replaced in a polymorphic manor. This is similar to how the editor adapters in Gaphor are defined and registered. One key difference in the design is how each class, or adapter, is instantiated when the need arises. With the class hierarchy approach, we would need extra logic to ensure that the correct instance type is created to use in conjunction with the diagram element widget. With Zope adapters, we simply instantiate the IEditor interface providing the object we are adapting to as a parameter. In the Gaphor case, the IEditor interface is instantiated with the diagram element widget as a parameter. The correct adapter instance is then returned by the Zope component framework, complete with the alternate functionality specific to that diagram element type. A similar effect can be achieved with the class hierarchy design. The class that is instantiated would accept the widget that is being adapted.

The adapter approach is a solid one because it emphasizes the importance of the interface contract provided by classes and the modularity offered by creating components. Being able to directly instantiate an interface speaks loudly in terms of what can be used in that context.

Monday, March 9, 2009

Gaphor element factory

The Gaphor UML modeling tool, written in Python, defines a UML element factory. The factory, given an instance of the Gaphor Application class, can construct UML element instances as Python objects. These Gaphor components may be used from within Gaphor plugins or independently of Gaphor entirely.

Consider the following example.
#Example; Gaphor factory.

from gaphor.application import Application
from gaphor.UML.elementfactory import ElementFactory
from gaphor.UML.uml2 import Class

if __name__=="__main__":
factory_obj=ElementFactory()
factory_obj.init(Application)
class_obj=factory_obj.create(Class)
class_obj.name="MyClass"
print class_obj.name
print class_obj.id
class_obj.unlink()
factory_obj.shutdown()
Here, we construct an element factory and pass it the Gaphor Application instance. Next, we create a Class UML element. Finally, we set an attribute of the element, destroy the element, and shutdown the factory.

We can construct any UML element from the Gaphor uml2 module which is automatically generated. Very neat stuff.

Saturday, March 7, 2009

Gaphor 0.13.1

Been a while since the last Gaphor release but, 0.13.1 has bee released. I'm glad to see that the Python and UML relationship continues to grow.

ArgoUML doesn't support abstraction dependencies.

In the UML, an abstraction relationship shows that one element is an abstraction on another. This is rendered as a dependency relationship stereotyped as abstraction. This is not an available stereotype for dependency elements in ArgoUML 2.6. The abstraction dependency doesn't necessarily need to be attached to the dependency directly.

The UML defines three predefined stereotypes in which the abstraction stereotype is attached to. These are derive, refine, and trace. However, when modeling dependencies, these stereotypes aren't available either.

So, if you have a need to specify these types of dependencies in your models, I wouldn't recommend ArgoUML (although I would recommend it for other UML modeling purposes). In fact, I don't even think Umbrello or Gaphor will get this right.

Tuesday, January 27, 2009

Gaphor plugin example.

The Gaphor UML modeling application provides an example hello world plugin. Obviously this plugin doesn't serve any useful purpose in the real world but it does give a good example of how Gaphor can be extended. The general layout for Gaphor plugins is similar to most Python packages. It has a setup.py module which enables the plugin to be installed independently of Gaphor.

Gaphor discovers new plugins through entry-points. The plugin must declare an entry-point that is available in the application. In this case, the hello world plugin wants to insert itself into gaphor.services.

The overall goal of the hello world plugin is to alter the menu in Gaphor and display a simple dialog. The actual plugin logic is contained in a single class called HelloWorldPlugin as illustrated below.



Here, the HelloWorldPlugin class provides both the IService and IActionProvider interfaces. The import items of interest are the menu_xml attribute and the helloworld_action() method.

The menu_xml attribute is an XML string that specifies where the new menu item for the plugin is placed within Gaphor.

The helloworld_action() method is responsible for implementing the action. In the case of the hello world plugin, it will display a dialog. Although not illustrated in the diagram, this method is actually decorated as an action. The decorator provides the action id, label, and tooltip.

Monday, December 22, 2008

Gaphor services

The Gaphor UML modeling tool offers a simple service framework under the covers. The Gaphor application itself defines some core services that fit within this framework. For example, it defines an ActionManager service that is used to handle various actions within the application.

All services that are defined within Gaphor (or as extensions to Gaphor), implement the IService interface. This interface is defined in the interfaces module. Here is a simple illustration of what this interface looks like.



As you can see, this straight-forward interfaces requires that any Gaphor services implement an init and a shutdown method.

The ActionManager service is a good example of a Gaphor service. This service is responsible for maintaining actions in the application. It is also a service that is responsible for loading other services. For example, the FileManager service is also an action provider since it implements the IActionProvider interface. The ActionManager service loads all components that provide the IActionProvider interface and registers them as action providers within the application.

Thursday, December 18, 2008

PyXMI

A few years back, I had a failed attempt at creating an open-source UML activity diagram runner called PyXMI. As the name implies, it was a Python program that attempted to load UML modules that were saved in the XMI format, and execute activity diagrams.

I think this project failed mostly because of my lack of understanding in the UML specification area as well as my lack of any use cases for such a project. I still do think it would be quite useful for such a library to exist. Having the ability to draw work-flow visually and have it directly executed (as opposed to generating the source code, and executing that), is a powerful tool. Maybe not in production use but as far as testing new ideas goes, this could offer insight that is not available by other means. Besides, that is why the UML was created, to visualize systems.

What if, besides generating the XMI document and executing that, we were able to simulate the model that is held in memory by the modeling tool? I know of no open-source project that can do this but the existing projects offer the components necessary to realize this functionality. Ideally, this would be fairly trivial to do if the modeling language is written in a dynamic language such as Python. Gaphor is written in Python and the code is of high quality and easy to grasp.

One feature Gaphor that is missing is colour support in the diagram canvas. Umbrello does offer colour support and makes for a good example of simulating a running activity diagram. For example, consider the following activity diagram.



This diagram is extremely straight-forward so I'm not going to bother explaining what it represents. Next, if we were running a simulation of this diagram, the modeling software could step through the activities and change the colour of the currently executing activity. Once an activity transition is reached, however, the model would need to pause for at least half a second so as to not fly through the execution. The reader should have the opportunity to view the execution as is illustrated below.



Now we process the input.




Finally, we send the output.




Hopefully, Gaphor will soon implement colour support so I can start experimenting with a plugin that will make another attempt at realizing executable/simulatable activity diagrams.

Tuesday, December 9, 2008

Transactions in Gaphor

The Gaphor UML modeling tool has support for transactions. There is a decorator called transactional that wraps the specified function in a transaction. If an exception is raised, the entire transaction is rolled-back.

The transaction.py module also defines the Transaction class as well as a TransactionError exception.



Here we can see that the Transaction class provides the ITransaction interface and also depends on the TransactionError exception. This exception is raised by the Transaction._close() method if there are no transactions on the transaction stack or if the only transaction on the stack is not the current transaction being closed.

There are also three events that are initiated by the Transaction class; TransactionBegin, TransactionCommit, and TransactionRollback.

Here is an example using the transactional decorator.
#Gaphor transaction decorator.

from gaphor.transaction import transactional

class MyDB:
@transactional
def update(self, data):
"""Update my hypothetical DB with data."""
print "Updating..."

if __name__=="__main__":
db_obj=MyDB()
db_obj.update(123)
An important note about the example and the transactional decorator. There are no return values from the transactional-decorated functions or methods. This makes sense since the return value may no longer be valid if the transaction was rolled-back.

Monday, November 24, 2008

Interfaces in Gaphor

I wrote earlier about Python interfaces and the Gaphor UML modeling tool demonstrates the use of Python interfaces quite nicely. Here, we show the interfaces that several classes in Gaphor implement. What is notable here is the simplistic design. There is not an entire plethora of interfaces to choose from. Only those that are important for accomplishing the applications' goals.

Friday, October 31, 2008

Using the Gaphor UML model

The Gaphor UML modeling tool is is written in Python and has has an easily accessible UML model API. This API can be used by other applications as well. The source code for the current Gaphor release can be found here.

Here is an example of how we can initialize an ElementFactory instance.

from gaphor.UML.elementfactory import ElementFactory
from gaphor.UML import Class

if __name__=='__main__':
factory_obj=ElementFactory()
print 'Factory initialized with %s elements.'%(factory_obj.size())

We can then use this ElementFactory instance to create new UML elements as illustrated below.

    class_obj=factory_obj.create(Class)
print 'Class object created with ID: %s'%(class_obj.id)

In the future, I'll go into more detail about the ElementFactory class in future posts because it is a useful tool for Python applications.

Wednesday, July 23, 2008

Gaphor as a sketching tool

Gaphor is a little UML sketching tool written in Python. It is small, but powerful. While it doesn't support all the fancy enterprise UML modeling features you will find in commercial products (which you would hardly ever use in the open source world), it provides one of the more flexible drawing canvases available.

It is the perfect tool for quickly sketching some object-oriented concepts without concerning yourself with UML "correctness". I think many software people avoid modeling so much because of the common notion that the UML is this big, ugly, complicated mess. It really isn't. Gaphor is not only useful for every day sketches in conjunction with producing production-ready software. It is useful as a primer for getting used to the act of modeling ideas. Not playing around with Gaphor before learning the UML is like writing an operating system before doing "hello.c".

Here is some Gaphor output. Nothing fancy, just easy, readable, sketches.