среда, 17 августа 2011 г.

"Soft" pencil down


Hi there,

Now, when became "soft pencil down" date, we have completely finished coding period on project and we are making final code review. So this review aggregates overall changesets which have been made by me, when coding on project. Notably, that during whole summer I have made a lot of changesets. Also, according to community's methodology, every two-three weeks I was making merging of active trunk into my project branch to keep my project up-to-date. This will greatly simplify merge of my project branch into trunk.

As for creating review, I used all possible revisions for code review, except those which are related to merge commits. Strangely, but when I was trying to add those revisions to review, Crucible did not allowed me to do this.

As reviewers for reviewers, I sent notification with invitation for all OpenMRS developers. By default I added to reviewers list four major devs including my mentor.

For now, half of them made about 15% of review. I suppose that review will be done till the ending of this week in the best case (or till the ending of the next week in other case). Next image shows dashboard of this review:



As for currect activity, I'm working on some trunk tickets related to HL7 service within OpenMRS. These are quite interesting tickets and I'm planning to tell you about that in my next post. Also, I'm planning to finish working on project documentation till to ending of this week.

With best regards, Taras Chorny!

воскресенье, 31 июля 2011 г.

Improving custom LocalizationTool class

Hi there,

During whole this week, I'm being worried with the best solution about using ResourceTool class (exactly our subclass of this - LocalizationTool). At first, let me tell you pre-history of this. At the beggining of this week me and my mentor were continuing review of code and were making testing of project. Notably, that we noticed one serious bug related to extending ResourceTool class. Even if this it worked, we weren't satisfied of such solution because it was not quite reusable. So, we were targeted on receiving more simple and more usable subclass of velocity resource tool at the same time.

As you can found out from the source code of ResourceTool (see the latest version on grepcode), guys, who has implemented ResourceTool class, has screwed up with design of that tool. But nevertheless, I did not believe, that they were so bleary-eyed  and, suspecting that something wrong with that "grepcode", I have downloaded source code of ResourceTool directly from repository. And, surprisingly, I found out that it quite differs from the "grepcode" version. Looking at that source code I noticed, that desired solution can be simply achieved by changing only one method that loads resource bundles. The only one method, it's great - I was thinking to myself!! And I've already done it and have tested. It works. See result version of code for localiztion tool class below:


/**
 * This class is intended for accessing {@link ResourceBundle} and formatting messages therein.
 */
@DefaultKey("l10n")
public class LocalizationTool extends ResourceTool {

/**
* Its need to override base class method to be able to change its locale property outside the
* class hierarchy
*/
@Override
public void setLocale(Locale locale) {
super.setLocale(locale);
}

/**
* To be able to load resource bundles outside the class path we need to override this method
*/
@Override
protected ResourceBundle getBundle(String baseName, Object loc) {
Locale locale = (loc == null) ? getLocale() : LocaleUtility.fromSpecification(String.valueOf(loc));
if (baseName == null || locale == null) {
return null;
}
return CustomResourseLoader.getInstance(null).getResourceBundle(locale);
}
}


This is truly very simple and much reusable then the one that was before. I think you'll like that solution because of its grace and simplicity. I've committed the appropriate changeset. Also I've merged trunk into my branch to keep  my project in accordance to current trunk code. I think, that received solution is much better that the one, that was before.

That is all for today, you can leave your opinion in the commants section below.

With best wishes, Taras Chorny!

воскресенье, 24 июля 2011 г.

Testing and bugs removing before merging into trunk

Hi there,

Suddenly, this summer came across its middle and brought me onto the straight way of project completion. And, you know, after midterm date, the time passes much more faster then before this. This week was a proof of that fact. May be, that is because I've had a lot of work, but regardless. What interesting happened with me and my project (or together) this week? In few words, I was working on rigorous testing of project functionality and bugs removing. So, let don't jumping ahead, and tell everything one-by-one.

The first and the most important fix within my project was related to changing the way how we are handling our custom localization tool within velocity's ToolContext. As you should have known, earlier ToolContext has been configuring once per session (or more, depends if user wanted to change his preferred language on first page during wizard running). But the main drawback of this was that fact that we shoul keep a map of tool contexts an clients sessions. This isn't appropriate taking into account that fact that in general, only one user will have an opportunity to run installation progress at the same time and others will be able only to review progress of installation. So, we decided to reject the idea of sessions and tool context with a session scope map and use single tool context with localization tool, that has request scope of sorts therein. Let me explain. In this case, tool context object will be one per application, but on receiving each next request, we'll change the locale property of our custom localization tool, which is contained inside corresponding toolbox object (ToolContext, in turn, contains that toolbox). So, I fixed it as told above and tested it. Notably, that result was succesfull, and performance left in appropriate level too.

The next thing, I changed the technical way how we are persisting user selected language. After code review with my mentor I was inclined to use pure JDBC to accomplish it. That is because we have decided, that using of OpenMRS Context object isn't a good practice in this case, specially, when OpenMRS application is not directly started till the moment, when we are saving user's preferred locale.So, I changed it, used raw Connection and PreparedStatement objects to persist user's selected language.

Also, during the code review, we found out that there are some of GUI messages, which aren't localized yet. So, I immediately started performing of corresponding translation and done this task in an hour.

Next, we decided to use chooselang.vm page as default page of installation wizard. And now, when some critical error occurs during wizard running, the user will be redirected to that page, instead of installmethod.vm template page.

May be, this isall that I'd like to tell you about work on my project this week, because rest things are mostly boring routine.

And as for work with community this week, in general I was working on ticket the main aim of which is to prevent multiple users to run installation wizard at the same time. I made couple of patches for that ticket. They should be applied to trunk and will be included into OpenMRS, which is coming soon. But, perhaps, this is a topic of my next week post.

With best regards, Taras Chorny!

суббота, 9 июля 2011 г.

Summing up before midterm

Hi there,

We are on the porch of the midterm and looking back on the way, that we have passed, I'm understanding that there were a lot of interesting moments and we have done truly important job. Making evaluation of our work, I'm sure, that we have done about 75% of work or even greater and all this due to having excellent time planning. Really, when we were planning our work we were inclined to put things with greater risk into beginning of the time line to be sure that they will be done as soon as possible. Also it looks very convenient to solve more difficult tasks when you are fresh and full of energy. And yes, our plan had worked and we have done integration of localization tool for velocity templates a week earlier than we had expected.

Generally, the complexity of that work was slightly more than medium (7 on a scale from 1 to 10). It requires a hard thought work, because you need think over a lot of aspects to make different things be able to work together. The complexity of  another tasks was slightly less than medium (4 on a scale from 1 to 10). But those tasks took really a lot of time.

Work on performing of translations consists of routine and routine once again. When you are doing this, you should try various variants of word-combinations to provide the most suitable translation which conveys the meaning as best as possible. You are changing sentence structure several times and finally, you are having translation that meets all your requirements. And this is really routine because you're repeating the same operations a lot of times. Regardless, such work have one great advantage that  overcomes all its drawbacks. You are opening a lot of truly useful knowlege about cultural and language features of other countries.

And due to this, now I know an answer to one of questions, which were interesting to me all time. How can man learn more than 20 foreign languages? And the answer, I believe, is that many languages ​​are very similar, since they belong to one ethnic group languages. For example, Romance languages group includes Italian, French, Spanish and Portuguese languages. All those languages descend from Vulgar Latin, the language of ancient Rome. And basically they are really similar, because they have a slightly similar alphabet, lexical and semantic sentence structure and etc. And the translations into these languages ​​have many common. The same thing can be said about British languages group.

So, all these kinds of work are really interesting because they can make you better as developer and help you more diversify as a person. And, if we add to this work within community, we will have truly useful pastime. Sometimes, when I'm returning to home little sad and tired I'm sitting at my computer, beginning to work with my community and sadness dissipate by itself. And this is one of the many plesant things that can happen with you, when you participate in this surprising program with such a cool community.

With best wishes, Taras Chorny!

суббота, 2 июля 2011 г.

Preparing first presentation and localizing pages for testing way of installation OpenMRS data base

Hi there,

Сoming an hour when I will have to show my first presentation about work that I've already done. Actually, it will be 14th of July, and till this date I should prepare it and rehearse with my mentor. But, I was not waiting too long, and immediately after the group B, I started working on my own presentation. At the beginning, truth, I was worried about it, because I did not do anything like that before. But, If you can't stand the heat, stay out of the kitchen. And being thinking about this proverb, I began to work on my presentation. First, that I did, I discussed idea of presentation and plan with my mentor, and after that I have had clear goal and the way how to achieve it. So, all that remained to be done, this is to be creative and try to present everything the more clear as possible. Although, there are some restrictions for presentation:
  1. it should take 10 min;
  2. since it will be closer to the midterm, it should be focused both on design startegy and on some demos;
  3. inter alia, it should be interesting and not boring, because I scheduled to show it at the end of the list and attendees, probably, can be bit tired.
Easier said than done. And soon after the day of creative work I have had complete draft version of my presentation. I was really happy, prepared draft speech and sent it to my mentor for checking. He reviewed it, made some comments and gave me his feedback. I fixed his comments and now, I do beleive that next week we will have complete version of presentation.  

Next interesting thing, that I have had this week, it was participating in development sprint. I was really impressed of how well managed sprints in our community last week and with great pleasure worked on tickets within sprint this week. Mostly, my work this week was related to unit testing, and I wrote a several tests and fixed some of already existing ones. The main aim for me, when I was writting tests, was to make them "green" and to cover most common test cases for different functionality. And due to good help that I received from sprint leader, I have done my work as soon as possible without any hustle.
And the last thing, that I'd like to tell you this week it's about my work on providing localization for new way of installation OpenMRS data base (this is testing installation). It work was closely related to installation wizard. You may ask me why I'm doing this work only now, I'm reaching out for you. Because it was added to the trunk quite recently. So, first, I merged active trunk into working copy of my branch, resolved all conflicts (this time, there were a lot of conflicts, and I had to work hard on them). After succesfull merging I noticed, that I should localize one new page, and add localization support for existing one. Also I had to handle additional error messages which are related to new way of OpenMRS data base installation. What turned out from that, you can see on figures below:

This figure shows updated page for selecting way of installation. Testing way of installation was added into the bootom of page. All messages related to that way were translated and added into web app's messages resources files. The next picture shows new one page for setting testing database installayion properties. All GUI messages for this page were localized too.

So, more than enough is too much. You can leave your opinion within comments below.

With best wishes, Taras Chorny!

воскресенье, 26 июня 2011 г.

Taking part in OpenMRS development sprint and everyday routine

Hi there,

Well, the first month of summer almost gone, there were a lot-lot of interesting things during first three weeks of this month, and last week wasn't exception of that. So, after I finished integration of localization tool into project and provided mechanism of handling error messages, I decided to integrate myself with current community activities. I thought to myself, that taking part in a development sprint would be the best in this case. 

Currently, there is a development sprint that is devoted to order entry. Order entry is a process of electronic entry of medical practitioner instructions for the treatment of patients (particularly hospitalized patients) under his or her care. The main goal of sprint is to create enterprise-quality support for order-entry within OpenMRS. 

So, I joined to that development sprint, choosed the first ticket and began to work. And it began to be very interesting for me, although even if that was introductory ticket of sorts, it was very plesantly to work with whole community, to saw how another tickets were clacked like nuts and how whole sprint work flow is organized. Also was plesantly to saw how well managed work. And, as soon as I closed the first my ticket I immediately took the next one, and then next one. And I was watching, how well was any of code reviews. After any review I was receiving feedbacks about quality of my code, was making follow up changes within code if it was necessary. 

And, you know, watching on all this process, I wanted to be better and more better to help community to make things even better. So, I began to work with twice inspiration. I got the ticket where was needed a lot of work, and done it. In fact, sprint leader praised me and offered to do a really big and interesting. I was very honored, and took that ticket without any doubts. Sprint leader has made some clarifications for me and I began to work on that ticket. And you know, the devil is not so black as he is painted, and I did that ticket. By that time I already have had partial acces to branch, on which is being all work of sprint. So, I was commiting more and more code, was receiving feedbacks, was making follow up changes and to the end of this week I'm about to completely close this ticket. Really, I'm satisfied of work shoulder to shoulder with whole community, it's really great, and I am grateful to them that they gave me such opportunity.

As for my project, this week I also made a lot of routine work. But, in general, probably, you can guess, that usually a lion's share of work consists of routine. Unfortunately, we have no way to getting away of that. So, according to my schedule, I had to perform some pages translation and to merge active trunk into my working branch. And I have done all this things. I can say that they also were useful for me because I improved my knowledges of foreign languages even more. As for merging active trunk into my branch, I did it without any hustle (inter alia, I had only one merging conflict and sucessfully resolved it). This is due to the way how distributed work on whole project and mostly due to that fact, that the component of whole system, on which is targeted my project, isn't frequently changing.

So, I guess that it's all for today, if you have any questions leave them in comments below.
 

With best regards, Taras Chorny!

воскресенье, 19 июня 2011 г.

Providing mechanism for localization of error messages

Hi there,


After succesfull integration of custom localization tool, I began testing how it works. And really, it worked like a charmed, and showed good performance, and I was really happy. But as soon as I missed field for new db name, when filled in form at 2nd step of advanced installation, I was unpleasantly surprised. Regardless, wizard was running in Italian, instead of error message "Base dati di nuova nome è richiesta" I saw "New database name is required" still in English. Cause, I simply forgot about localization of error messages. So, I decided to fix it as soon as possible.
First, that you should know about, that the nature of error messages quite differs from normal messages. The first difference, is that any error message, in comparison with normal GUI message,  won't be shown with 100% of probability. It can be shown, or it can't be shown, it depends. We can say that they are forming dynamicaly. But our localization tool can handle only static messages which are kept inside of messages properties files.So, as conclusion of that, we should have to teach our localization tool to handle such messages. 

So, how did I accomplish that? First, I decided that all error messages should be inside properties files, otherwise, the problem seems to be unsolveable. And as next step, I defined entire set of error messages, which ever can be displayed to user. Then, I completely localized them (it took most of my time). Jumping ahead, I should say that some error messages can be formed from dynamical parts, and it makes additional inconveniences. For representation of such messages I used compound messages. More about them you can read here.
So, after all messages were prepared, I should have find the way, how to point out localization tool, which translation of error message to use. Decision was really simple and graceful at the same time - in all places in code, where forming errors, I used error messages keys. For example, when user didn't fill new db name field, instead of "New database name is required" I put "install.error.dbNewName". Thereby, localization tool will accept such key and load corresponding translation of message fo this key. For handling compound error messages I'm also putting all dynamical part of message with their code together. For this I had to use map for keeping error messages. For this map I used the key of messages as entry's key, and an array of objects as entry's value. As result, in templates handling of error messages proceeds as follows:

        #foreach ($error in $errors.entrySet())
            #if (!$error.getValue())
                <li>$l10n.get($error.getKey())</li>
            #else
                <li>$l10n.get($error.getKey()).insert($error.getValue())</li>
            #end
        #end
where $errors - the map, mentioned above, $l10n - our custom localization tool.

So, described above feature really works, and results of its work is shown below:


As you can see, now for italian locale we can see correct translation of message about occured error.

This as all for today, you can leave your comment if you have some questions or suggestions.


With best wishes, Taras Chorny!

воскресенье, 12 июня 2011 г.

Finished integration of custom localization tool

Hi there,

The summer is already begun, and in both meanings of this word "it is very hot". Moreover, that the sun terribly bakes, so more and the work on a project, also so boils. The week, which is about to end, was also heavily rich within different events
First of all I'd like to tell you that I already passed the last exam in my student life. I got an excellent estimation, and I'm really happy of that fact that now I'm computer science engineer. And you know, that it's such ambiguous feeling - to come to the finish of your student life. From one hand, you are so happy that you've finally got the degree, but from other hand, you are just little sad, that the days of fun, days of careless life have been finished. But we should not be distressed, because GSOC is gaining speed, and more and get more interesting.
As for my project, this week I finished integration of already developed the custom localization tool. And it's all thanks to this hard work, which we've done with my mentor so far.
So, now I can tell you how it work in general. As you should have known, OpenMRS has two wizard. One for installation and another for database update.
First of them is running when application is starting first time after deploy. As soon as the wizard starts up the choise language page will be shown to user. Since we running wizard for first time and we do not have any db installed at this time, the localization tool should make a decision, which language to use for this page. It chooses the language as follow:

  1. it looks into http request object and gets client's system locale. If this locale is supported by OpenMRS it shows first page of initial setup wizard translated for this locale.
  2. if this locale isn't supported by application or, just not specified, localization tool makes a decision to use english translation for first page by default.
At first page user can select preferred language to use it further (within wizard) or leave everything as is. So, selected by user language will be used to show translation for pages during wizard running. User can also  specify that it's need to OpenMRS to remember his choise for further using (within application in general -e.g., for using it when db update wizard will be runned). In this case, after sucessfull finishing of installation wizard, localization tool will check if user turn on this feature, and if it's true, localization tool will store the user selected language into db:
  1.   first, as user property,
  2.   and next, as OpenMRS system default locale.
As for database upgrade wizard, there is one special thing. This wizard can only be runned by user, who has admin privileges. In fact, update wizard has extra page for user to log in. So, before user logged in, custom localization tool also makes a decision which translation to use for first page of update wizard. It makes this decision as follows:
  1. it looks into http request header and gets client's system locale. If this locale is supported by OpenMRS it shows first page of database update wizard translated for this locale.
  2. if this locale isn't supported by application or, just not specified, localization tool makes a decision to use OpenMRS system default locale (as you know, it could be specified  when initial setup wizard is running).
  3. and if system default locale is also not specified it uses english translation by default.
After user logged in into database update wizard, system already knows, who is this user (we know his username), localization tool looks into db for user locale property. And if it exists, it uses corresponding translation of update wizard pages. If not. it uses the language, which was choosen before log in. 
So, this week I was solving of some problem , which were as obstaclefor providing descripted above behaviour.
By and large, this week I was solving some problems, which were as obstacle for providing behaviour, mentioned above.  And now, we have first realy working version of custom localization tool. And yes, it should be strongly tested. But it's an issue to be solved on next  two weeks.

I guess, that this is all for this time, if you have any questions or suggestions, please, leave them within comments below.

With best regards, Taras Chorny!

суббота, 4 июня 2011 г.

Providing of some "yum-yum" features for project

Hi, everybody!
Without any doubts, I already began to believe strongly, that someone, who said that time passes very fast, was devilishly right. And today, I'm going to tell you, my dear reader, about what interesting I've done this week. Admittedly, I had some unsolved tasks at beginning of week. They, preferably, were related to inner components of my project.
The first of those tasks was creation of some kind of "cache" for loaded messages properties files. In a nutshell, I've created a java map with languages, mapped to the loaded properties files. First of all, it is very convinient to have such map, because it works like a cache and provides an opportunity to access translations without reloading resources, when current language is changing. I've assigned the task of creation such map to custom resources loader component. In fact, this map creates when creates an instance of resource loader component. After creation (we have a single instance of custom resource loader), that component will contain the map therein and other components will have a read-only access to him. And since an access don't mean any modification with the resources within cache, we should not do him (access) synchronized.. Basically, in case of using a single instance of resource loader we also won't use a lot of memory for such cache.
And now, I'm about to show you, how I'm loading the resources into map. Generally, I'm doing it within a single private method of custom resource loader class. Notably, that this method is called once at constructor of resource loader class. Also it is important to note that constructor of that class receives as parameter an absolute path to directory where resources are located. Next, location of that directory is passed in as parameter to method for creation map for resources. This method is shown below:
   
    private void loadResources(String basedir) {
        File propertiesDir = new File(basedir);
        for (File possibleFile : propertiesDir.listFiles()) {
            log.warn("filename : " + possibleFile.getAbsolutePath());
            if (possibleFile.getName().startsWith(FilterUtil.PREFIX) && possibleFile.getName().endsWith(FilterUtil.SUFFIX)) {
                Locale locale = parseLocaleFrom(possibleFile.getName(), FilterUtil.PREFIX);
                log.warn("locale : " + locale.toString());
                getResource().put(locale, getFileSystemResource(possibleFile.getAbsolutePath(), FilterUtil.PREFIX, locale));
                getAvailablelocales().add(locale);
            }
        }
        if (log.isWarnEnabled() && (getResource().size() == 0)) {
            log.warn("No properties files found.");
        }
    }



As you can see, at first I'm creating a file object for directory with resources to be able to iterate over the list of nested files and directories. And then, I'm iterating over all these nested files and checking if current file is messages properties file. If it's true, I'm trying to derive the locale from the file name (e.g. if file is named messages_it.properties the locale "it" will be derived). Next, I'm loading resource bundle for that locale and putting it resource bundle into caching map with derived locale as key.
The second task for this week was creation of the feature, which allows us to have one velocity toolbox per one http client's session. Before this week we had single velocity toolbox for all client's sessions. And, as you can guess,  it is awful, because we have locales overlaping when multiple users are running wizards at the same time. This problem causes because, from one hand, we configure one instance of velocity toolbox per one filter and, from the other hand, web container instantiates only one filter instance for <filter ..> tag per JVM for application. 
Desicion was to have map, that contains http session's id as key and configured toolbox context as value. And since toolbox context object can be merged with velocity context, we will get appropriate context object for current client's preferred locale and use it within velocity context when will rendering tempaltes. 
Also, during this week I done tasks related to navigation components appearence, made changes within stroing/retrieving locale parameters methods and continued integration of existing localization tool into database update wizard.
So, I guess it is enought for today. If you have any quesions or suggestions leave them in comments below,


With best regards, Taras Chorny.

суббота, 28 мая 2011 г.

How it was at the first week of coding

Hi there,

Finally, I began to write a code, and as funny sounds, but I really wanted to do it starting from the day, when I was accepted to GSoC! And now, I'm very happy, becuse I have a lot of work, interesting work!

So, what did I do during this week? There were two points on which I was working.
First one of my tasks was creating and testing custom localization tool for a project. In my previous post I sad that custom localization tool is a central (in both meaning of this word) component of the project structure. All magic will be around this component. It accesses resources bundles and obtains messages therein.
So, lets start from fact that I have created this tool. And it was very interesting, as for me, to accomplsih it. So, I'll tell you how to do it.
So, first, that we need, is to extend generic velocity's ResourceTool class. We are doing that to have an opportunity to load resources outside from class path (from /WEB-INF directory, for example). In generic class,  the Object get(Object k, String baseName, Object l) method is responsible for loading resources, and we simply should override him. And everything will be ok. But how to override it method, you can ask me? And I say you, that it's simply! We only should to take care about using of ourappropriate resource loader class instead of default. We just calling:

      getResourceLoader().getFileSystemResource(resourceLocation, baseName, locale);

and passing in the path, where our messages resource for specified locale is situated. It returns ResourceBundle with translated messages for that locale therein.
And, I guess, that it is all that i needed for writting our custom localization tool. All the rest behavior inherit from velocity Resource tool. But it's not enought for using such kind of velocity tool. As you know, for standalone using of any velocity tool we need to configure toolbox, that will contain all tools.
For configuring of such toolbox I used ToolManager and Factory configuration classes. The result of configurstion was velocity tool context, which can be used (merged) with standard velocity context. The code, which configures velocity toolbox is shown below:
        // creating of a manager and factory configuration
        ToolManager velocityToolManager = new ToolManager();
        FactoryConfiguration factoryConfig = new FactoryConfiguration();
       
        ToolboxConfiguration toolbox = new ToolboxConfiguration();

        // we are setting scope for this toolbox as application
        // because we wanna use it for each request
        toolbox.setScope(Scope.APPLICATION);
        // we should configure our custom tool before

        // setting it into toolbox
        ToolConfiguration localizationTool = new ToolConfiguration();
        localizationTool.setClassname(LocalizationTool.class.getName());
       
        localizationTool.setKey("l10n");
        localizationTool.setProperty("locale", new Locale(locale));
        localizationTool.setProperty("bundles", "messages");
        localizationTool.setProperty("resourceLocation", getResourceLocation(locale));
       
        toolbox.addTool(localizationTool);
        // and now we can configure toolbox
        factoryConfig.addToolbox(toolbox);
        velocityToolManager.configure(factoryConfig);
        toolContext = velocityToolManager.createContext();


And further, I've "merged" this toolConext with velocity context, which had allowed us to use configured tool directly within our templates:

        VelocityContext velocityContext = new VelocityContext(toolContext );

You can also to argue to me, "why aren't you using toolbox.xml file for configuring tool?" for example. Relax. Using of such approach in this case isn't acceptable, because we are targeted to the best performance, and using additional servlet and one more xml file on  file system isn't good for it. With using java code to configure toolbox we are pretty flexible and fast. Moreover, in our case (we are tied to servlet's filters) we can use only standalone variant of velocity toolbox (without VelocityViewServlet, which, nevertheless, great simplifies using of toolbox).
Well now, this is just enough for creating custom localization tool. What was the second of my tasks for this week? It was creating of new page for selecting preferred language as first step of setup wizard.


This page should be as much as simply. So, I added only few components onto it (i.e. selection list for choosing language, checkbox for indicationg that it's need to remeber user's choise and button for continue as next arrow).  But anyway it looks good and has enough functionality, as other suchlike pages.

I think, that is enough for this time, if anybody has a question, I'm ready to tell you what you want,

With best wishes, Taras Chorny!




воскресенье, 22 мая 2011 г.

Design review of project's structure

Hi all,
It was really hard-working week, so I'm writting my post not as usual. But, anyway, I'm going to tell you, my dear reader, about work on design of project's structural and behavioural aspects.
So, after I have made an overview of subject domain (i.e. localization tools) I started phase of project's design. On this pahase I was focused on developing robust and flexible model of project's structure. I tried to figure out the project's structure for few times, and each next time I was so far to right decision. But something was bugging me, each of next decision seemed to me frightfull, and I was starting everything over again. 


Nevertheless, I found the way, so I'm going to slightly open the curtain, wich is covered over this.

Initially, the project structure can be represented as a set of interrelated components. Links between these components may be different. Also, components themselves, might be devided on two groups: inner and outer.

Inner components, which is represents the core of project. They should be developed from scratch. Together, these components will work as some kind of localization tool. The main function of that tool will be obtaining  localized GUI messages, which is stored in resource files and providing an easy way for accessing them directly  from velocity templates. Also, it would be great to have such tool as flexible as possible, in fact, that tool should support an easy way of changing its configuration by other components.

And, in turn, outer components represents an existing servlets filters (into which will be integrated functionality of configuring inner localization tool) and message resource files (which will be accessed through localization tool). I can say, that project components structure was designed to provide the easiest way of integrating localization tool into initial setup and update wizards. Next figure shows as diagram which describes project structure:
Lets make a review of this diagram starting from outer components ('cause, I suggest that most of you have a questions about it). Outer components are:
  • UpdateFilter and InitializationFilter;
  •  messages.properties* files.
As we can see at picture above, UpdateFilter and InitializationFilter are the components which are representing an appropriate existing servlet filters. Basically, these filters are used for managing the general work flow of both wizards, they control navigation between pages within wizards, they create and render velocoty templates for wirads pages and do job of preparing installation/update process, execute these processes.

Next outer components are named as messages.properties*. These are text files which will contain localized messages for both wizards. Those files are located under /WEB-INF directory of OpenMRS web app (see Analyze of existing L10n tools for velocity templates). Example of their content is shown on related text notes on diagram above.
 So, I think that everything so far is clear. And I can begin description of such "lovely" thing as inner components, they are:
  • custom localization tool;
  • filter utility.

As you might guess from component's layout the key component of structure is custom localization tool. This is a central (in both meaning of this word) component of the project structure. All magic will be around this component. It accesses resources bundles and obtains messages therein.

Such component will be implemented as sub-class of velocity’s ResourceTool class. Creating of sub-class, instead of using standard tool can be explained with need to load resources outside the web-app classpath. For achieve this we will simply override get(Key) method, that is responsible for loading the resources. When we will implement this method ,we should take care about loading messages.properties* from file system by specified path.

Using of this approach will allow as to type $locale.install.method instead of $l10n.get(‘locale.install.method '), for showing localized content.

Also component will contain map with resources bundles for each locale. Moreover,  it should be configurable. This means that this component should provide opportunity to easily change its parameters in run-time.

 And the last important inner component is filter utility. This component should manage locales parameters. It will check whether need to save user’s selected language, will retrieve it locale from http session if need, and will store it into DB as admin’s user property. Also it will try to retrieve that persisted language in case of DB update wizard running.

Since we will use custom velocity resource tool we will need to configure appropriate toolbox.  Admittedly, this component will manage configuring of localization tool by using java API. For this we will use EasyFactoryConfiguration class from velocity framework. Filter utility will be implemented as java class (or set of classes under the same package). Access to localization tool component will be provided through this one.


That is all for now. I think, that we have reviewed all bottlenecks within project structure, 'cause it is very important to begin coding on projec, while investing as much as possible time to design.


With best wishes, Taras Chorny.


среда, 11 мая 2011 г.

Review of project requirements

Hi everyone! 

Today, after all discussions is over, I'd like to reveal the curtain over such very important aspect of my GSoC project as project requirements. Yes, we have discussed it hard with my mentor. I have made a lot of corrections, brought a lot of changes into initial version of corresponding document. But now, I expand all the project objectives and requirements on the clearly sort through.

So, the main aim of current project is to provide opportunity for users to run the setup and update wizards in their selected language. Yes, and this is very clear, I suppose that anybody doesn't have any questions about that. And we can continue. We won't going deep into details

Following to most commonly used practice, we have highlighted non functional and functional groups of requirements. I'd like to clarify that those requiremnts are described with the developer's perspective, and more closely reflect understanding of the technical details. Lets begin from functional requirements.

Functional requirements:
  •  Appropriate page should be shown for user at first step of the setup wizard (see fig. 1);
 Anyway, you must not be surprised. As the localization style of web app must be alike desktop's app, and if we wont have suchlike page, our project goal will be unreached fundamentally.

  • That page should contain selection list with all possible languages, checkbox for indicate that selected language should be persisted after wizard’s finish and navigation element (next arrow) for continue;
  • Selection list should be dynamically filled with languages basing on existing web app's message resource files;
  • The user should be able to move back and forth through the each wizard's pages by using appropriate navigation elements (arrows are preferred in case when the text displayed is in a language they don't understand so well or if they selected a wrong language by mistake);
  • When user is moving through the initial setup wizard's pages, language should not be changed until user will return to 1st page and change it;
  • Selected by user language should be saved into cookie (or as http session's attribute) during wizard’s work and (if user have marked checkbox), it should be persisted into DB as admin’s property;
  • When user is running the database update wizard, all pages should be displayed in previously persisted language or in English by default;
All functional requirements to the system can be formalized by using following use case diagram:
As you can see we have defined precisely such requirements, without which the project will not work at all or will work not as excepted. Next group is non-functional requirements.
Non-functional requirements:
  • Support for new languages should not require recompilation;
  • Access translated text with resource bundles;
  • Resource bundles should be loaded as fast as possible (on web app startup or at first request).
  • Textual elements, such as status messages and the GUI component labels of both wizards should be completely translated into most of supported languages (Italian, Spanish, French and Portuguese);
  • Employ the use of arrows as navigation elements instead of buttons with text;
  • Only Unicode encoding characters should be used for translation;
Admittedly, that without providing of these requirements, project won't be broken, but  a great usability damage will be made

So, I think that this is complete list of requirements and it will help me to do my further work as well as possible.

I will wait exactly for your comments! 

With best wishes, Taras Chorny!


 

вторник, 3 мая 2011 г.

My first steps on open source way


Hi, everyone!

At beginning of last week my proposal was accepted to GSoC 2011. I was so impressed, but today I`m not worrying so much now I see there are a lot of work, interesting work and I like this! So, now I`d like to tell you about beginning of my open source way.

Once my friend had showed me the post about announcement of GSoC program. I’ve read this post and began to move on open source way. I began to move step-by-step. I've read a lot of information about GSoC, met with guys who have participated in this program last years, asked them a lot of questions, they have answered and gave me a lot of useful advices.

I went through list of participating last year organizations. There were a lot of exciting communities and it were even greater number of interesting projects. So, I was waited impatiently for announcing this year list of participating organizations. And immediately after the announcement I began to find the most suitable community for me. Truth, there were a lot of really good candidates, and it was very difficult to me to make a decision. Eventually, I did my choice. It was OpenMRS community. And still I have no regrets about this, because it's really good community with great amount of clear documentation and excellent organization of work.

So, after choosing community and slightly later, after I’ve read introductory guides for developers and have familiarized with conventions, I found their trac with introductory tickets and began to work. And it`s great, because I began to understand what is open source!

When it was the time for sending proposal I knew, that I will make an application only exactly for one organization and for one project, and that organization will be only OpenMRS! So, I did it and was sure that I will be accepted. 

So, now I'm a participant of this program, I've already did "first" steps for accepted students and I'm beginning to speed up myself for coding.

With best wishes, Taras!