<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>IP-Tech's Blog</title>
	
	<link>http://www.iptech-offshore.net/blog</link>
	<description>Le blog officiel de IP-Tech</description>
	<pubDate>Sat, 13 Feb 2010 12:04:16 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ip-tech-blog" /><feedburner:info uri="ip-tech-blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Apache Pivot : l’alternative à JavaFX ?</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/DqfSEbpYPWA/</link>
		<comments>http://www.iptech-offshore.net/blog/2010/02/07/apache-pivot-lalternative-a-javafx/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 07:42:00 +0000</pubDate>
		<dc:creator>Hamdi DOUSS</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[Apache Pivot]]></category>

		<category><![CDATA[RIA]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=72</guid>
		<description><![CDATA[
Apache Pivot est un framework de développement d&#8217;applications Internet riches (RIA). Du buzz autour de ce framework est en train de se produire sur la toile. Bien qu&#8217;entamé en 2007, Apache Pivot est mentionné de plus en plus ces derniers jours grâce à sa promotion au rang de &#8220;Top Level Project&#8221; par la fondation Apache [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="float: left; margin-right: 15px;margin-bottom: 10px;" src="http://pivot.apache.org/images/logo.png" alt="Apache Pivot Logo" width="132" height="140" /></p>
<p><a href="http://pivot.apache.org" target="_blank">Apache Pivot</a> est un framework de développement d&#8217;applications Internet riches (RIA). Du buzz autour de ce framework est en train de se produire sur la toile. Bien qu&#8217;entamé en 2007, Apache Pivot est mentionné de plus en plus ces derniers jours grâce à sa promotion au rang de &#8220;Top Level Project&#8221; par la fondation Apache en Décembre 2009.</p>
<p><span id="more-72"></span></p>
<p>En théorie, cela veut dire que les développeurs du framework, qui a rejoint <a href="http://incubator.apache.org" target="_blank">Apache Incubator</a> en Janvier 2009, respecte les principes et les process de la fondation, se basant sur <a href="http://www.apache.org/foundation/how-it-works.html#meritocracy" target="_blank">la méritocratie</a>. En pratique, cela signifie que le projet devient plus visible, et une certaine communauté de développeurs se formera autour du projet. On verra certainement plus de billets de blog, des exemples, de la documentation et des critiques autour du framework. La quantité et la qualité dépendra certainement du succès de celui-ci.</p>
<p>Tout développeur Java peut se demander comment se positionne Apache Pivot par rapport à JavaFX. Sur la page <a href="http://cwiki.apache.org/PIVOT/frequently-asked-questions-faq.html" target="_blank">FAQ du projet</a>, les développeurs présentent Pivot et JavaFX comme répondant à des besoins &#8220;légèrement&#8221; différents avant d&#8217;admettre que les deux technologies ne sont pas pour autant exclusives et que -je cite- &#8220;Pivot represents what we think Sun should have done instead of JavaFX.&#8221; (traduction: Pivot représente, à notre avis, ce qui aurait du être fait par Sun au lieu de JavaFX.)</p>
<p>A mon avis, Pivot se positionne comme une alternative sérieuse à JavaFX pour tout développeur Java travaillant sur un projet RIA. Les raisons sont assez claires:</p>
<ul>
<li> Le code est en Java (et non un langage de script à apprendre);</li>
<li> Le développeur a l&#8217;option de programmer son interface graphique déclarativement (en XML);</li>
<li> L&#8217;intégration avec les composants serveur est plus souple.</li>
</ul>
<p>Dans la page de la proposition de projet à <a href="http://wiki.apache.org/incubator/PivotProposal" target="_blank">Apache Incubator</a>, quelques comparaisons existent (formulées par les développeurs de Pivot) avec Swing, GWT et JavaFX.</p>
<p>Mon intention n&#8217;est pas de dire que Pivot est le framework de développement RIA par excellence, loin de là. A mon sens, ce n&#8217;est qu&#8217;un projet qui débute, mais qui reste prometteur.</p>
<p>Je vous invite à aller découvrir <a href="http://pivot.apache.org/demos" target="_blank">les démos</a> et <a href="http://pivot.apache.org/tutorials" target="_blank">les tutoriaux</a>, qui peuvent, je pense, être complétés par un exemple intégrant un traitement coté serveur avec Pivot. Un exemple que nous allons essayer de vous le proposer dans un prochain billet.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/DqfSEbpYPWA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2010/02/07/apache-pivot-lalternative-a-javafx/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2010/02/07/apache-pivot-lalternative-a-javafx/</feedburner:origLink></item>
		<item>
		<title>L’interopérabilité de Microsoft SharePoint propulsée par CMIS</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/InHX652t6vQ/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/11/20/cmis4sharepoint/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 14:29:04 +0000</pubDate>
		<dc:creator>achaabouni</dc:creator>
		
		<category><![CDATA[Microsoft]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[CMIS]]></category>

		<category><![CDATA[ECM]]></category>

		<category><![CDATA[OASIS]]></category>

		<category><![CDATA[SharePoint]]></category>

		<category><![CDATA[SOA]]></category>

		<category><![CDATA[WCF]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=69</guid>
		<description><![CDATA[
L&#8217;usage des documents électroniques dans les processus de collaboration, de communication et de prise de décision ne cesse de s&#8217;intensifier: Les décisions stratégiques se basent, entre autres, sur des analyses documentées. La communication intra et inter-entreprise, qui se base sur les messages électroniques et les sites web, se doit de cibler une large audience et [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="border: 0pt none; float: left;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/CMIS.PNG" alt="" /></p>
<p><img class="alignleft" style="border: 0pt none; float: left;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/moss2007.PNG" alt="" width="224" height="68" />L&#8217;usage des documents électroniques dans les processus de collaboration, de communication et de prise de décision ne cesse de s&#8217;intensifier: Les décisions stratégiques se basent, entre autres, sur des analyses documentées. La communication intra et inter-entreprise, qui se base sur les messages électroniques et les sites web, se doit de cibler une large audience et représente un media de choix pour communiquer avec les partenaires et les clients.</p>
<p><span id="more-69"></span></p>
<p>Les éditeurs logiciels se sont très tôt intéressés au domaine de la gestion des contenus de l&#8217;entreprise ou Entreprise Content Management (ECM). Au fil des années la pile logicielle (l&#8217;ensemble des logiciels inter opérant au sein d&#8217;une entreprise pour compléter un processus métier) s&#8217;est complexifiée et a vu une multitude d&#8217;intervenants opérants entre eux. Cette interopérabilité est essentielle et même stratégique dans certains cas. Elle est aussi couteuse car les éditeurs sont peu enclins à dévoiler leurs protocoles et leurs interfaces, ceci venant s&#8217;ajouter à une hétérogénéité des langages informatiques.</p>
<p>A défaut de pile ECM intégrée, les entreprises se sont donc tournées vers le développement de solution ad-hoc. Tâche qui peut s&#8217;avérer ardue et qui aboutit, généralement, à un produit non réutilisable et difficile à maintenir.</p>
<p>Ceci n&#8217;est pas sans rappeler les problèmes auxquels furent confrontés les développeurs dans les années 80 avec les systèmes de gestion des bases de données (SGBD). Ce problème a été résolu par l&#8217;adoption de standards (ODBC, SQL &#8230;) par l&#8217;ensemble des fournisseurs de SGBD. Cette solution ayant fait ses preuves, les principaux protagonistes du monde ECM, c&#8217;est-à-dire Microsoft, EMC et IBM ont élaborés un nouveau standard nommé CMIS (Content Management Interoperability Services) pour mettre fin à cette véritable tour de Babel des ECM.</p>
<p>La première version de a été soumise fin 2008, et très vite elle a suscité l&#8217;intérêt de plusieurs acteurs du marché logiciel tel Alfresco, SAP et Drupal &#8230;</p>
<p>Suite à cet engouement, l&#8217;organisme de standardisation OASIS adopta le projet pour en faire une norme de l&#8217;industrie des ECM. Dès lors, les implémentations de CMIS ont commencés à apparaitre et le premier à en proposer une fût Alfresco suivi par ECM et IBM. Mais Microsoft ne proposa aucune solution pour son produit SharePoint et ce n&#8217;est que vers février 2009, que l&#8217;on voit apparaitre un article sur MSDN traitant du sujet.</p>
<h3>Microsoft SharePoint : une success story</h3>
<p>SharePoint est devenu au fil des années un des produits phares de Microsoft (plus de 1 milliards de dollars (US$) en licences vendues durant l&#8217;année 2008). Cette large implémentation en entreprise a favorisé l&#8217;éclosion d&#8217;une communauté très active autour de SharePoint notamment à travers le programme MVP de Microsoft, Codeplex et les clubs SharePoint un peu partout dans le monde.</p>
<p>La part du marché des ECM qu&#8217;occupe Microsoft est tellement importante que plusieurs entreprises se sont spécialisées dans l&#8217;édition de connecteurs spécifiques pour des logiciels tiers interagissant avec SharePoint. Microsoft devant cet engouement pour le développement sous SharePoint a fait preuve de bonne volonté; en intégrant les protocoles de communication SharePoint dans ses initiatives Open Protocol et Open specification. Ceci a conduit à l&#8217;apparition de plusieurs produits compatibles comme par exemple l&#8217;intégration de SharePoint dans OpenOffice.org.</p>
<p>La norme CMIS est dans la droite lignée de cette ouverture de Microsoft et sa participation à l&#8217;élaboration des standards. Mais malgré ses bonnes intentions, Microsoft reste en retard par rapport à ses concurrents en ce qui concerne l&#8217;implémentation des services CMIS, menaçant ainsi son adoption en tel que standard de l&#8217;industrie.</p>
<h3>CMIS4SharePoint :</h3>
<p>S&#8217;inscrivant dans un objectif de veille technologique, CMIS4SharePoint est avant tout une étude de faisabilité. L&#8217;objectif initial était de démontrer qu&#8217;une implémentation de CMIS en utilisant uniquement le modèle objet SharePoint était possible.</p>
<p>Au fil des développements, et après quelques concessions dues à la structure même de SharePoint. Il s&#8217;est avéré que cette implémentation était opérationnelle. La décision fût alors prise de faire profiter la communauté de ce développement, c&#8217;est ainsi que IP-Tech propose la première implémentation du standard CMIS pour la plateforme SharePoint.</p>
<p style="150px" align="center"><img style="middle" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/ArchiCMIS4MSSP.png" alt="Architecture deCMIS4SharePoint" width="406" height="523" /></p>
<p>L&#8217;architecture nécessite plusieurs aménagement du serveur SharePoint car il se base sur le .NET Framework 2.0 or nous utilisons WCF pour exposer les web services SOAP et REST. Ceci ne peut se faire qu&#8217;avec le .NET Framework 3.5 et un « tweak » de SharePoint pour rajouter le support de WCF.</p>
<p>Un scenario simple illustrant l&#8217;utilisation de CMIS, peut être la mise en place d&#8217;un outil pour l&#8217;utilisation offline de SharePoint. Cet outil peut s&#8217;avérer très utile pour fournir une meilleure expérience utilisateur dans l&#8217;utilisation de SharePoint, car il bénéficie de la puissance de calcul des clients lourds. Aussi on peut envisager sa réutilisation pour d&#8217;autres ECM, tel Alfresco ou FileNet. Ainsi, si l&#8217;entreprise procède à une migration elle sera presque transparente pour l&#8217;utilisateur final. Il conservera la même interface graphique et les mêmes habitudes de travail évitant le réapprentissage imposé par chaque changement d&#8217;ECM.</p>
<p align="center"><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/clientCMIS.jpg" alt="Image d'un client utilisant CMIS4SharePoint" width="435" height="276" /></p>
<p>Pour illustrer la facilité qu&#8217;apporte l&#8217;abstraction CMIS à la création des outils, nous avons développé un client qui liste le nom et l&#8217;URL de l&#8217;ensemble des bibliothèques de documents disponible dans un site SharePoint.<br />
Pour tester CMIS4SharePoint il faut commencer par créer sur une machine cliente (autre que le serveur SharePoint) un nouveau projet Console sous Visual Studio 2008. On appellera ce projet &#8220;ClientTestCMIS&#8221;.<br />
Après la création de ce projet, faites un clique droit sur le projet dans explorateur de solution, et sélectionnez &#8220;Ajouter référence de services&#8221; (Add Service Refrence).</p>
<p align="center"><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/addService.png" alt="Ajout d'une réference de services sous visual studio 2008" width="204" height="448" /></p>
<p>Dans la boite de dialogue qui s&#8217;est ouverte, saisissez l&#8217;adresse de votre service, appuyez sur &#8220;Go&#8221; puis sélectionnez le service retrouvé, comme l&#8217;illustre cette capture :</p>
<p align="center"><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/addService2.png" alt="" width="389" height="301" /></p>
<p>Renommez le Namespace du service puis validez.<br />
Maintenant Visual Studio a généré un proxy qui reprend tout les services exposé, il ne reste plus qu&#8217;a implémenter le programme dont voici le code source:</p>
<pre name="code" class="c#">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClientTestCMIS.CMISReference;

namespace ClientTestCMIS
{
    class Program
    {
        static void Main(string[] args)
        {
            //création du proxy qui va nous permettre de consommer les services
            RepositoryServiceClient repositoryClient = new RepositoryServiceClient();

            //ouverture de la liaison
            repositoryClient.Open();

            //envoi de la requête pour l&#8217;obtention de
            //la liste des repositories (des bibliothèque de documents)disponible dans le site SharePoint
            cmisRepositoryEntryType[] repositories = repositoryClient.GetRepositories();

            //fermeture de la liaison
            repositoryClient.Close();

            //affichage du nom et de l&#8217;url de chaque bibliothèque de document
            foreach (cmisRepositoryEntryType item in repositories)
            {

                Console.WriteLine(&#8221;Name={0}\nURL={1}\n&#8221;, item.repositoryName, item.repositoryURI);

            }
        }
    }
}</pre>
<h3>Perspectives</h3>
<p>L&#8217;avenir de CMIS4SharePoint est totalement lié à l&#8217;intérêt qu&#8217;il suscitera auprès de la communauté. Du chemin reste à faire avant de pouvoir proposer une implémentation totalement opérationnelle mais ceci ne saurait tarder.</p>
<p>CMIS4SharePoint peut être utilisé comme une base pour de applications plus élaborée afin de promouvoir l&#8217;utilisation de CMIS. Car un standard qu&#8217;on n&#8217;exploite pas est un standard qui ne sert à rien. CMIS ne subira pas le même sort que les autres tentatives de standardisation des ECM et tout comme JCR il ne sera pas classé comme « une norme de plus ! » (Just another standard !).</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/InHX652t6vQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/11/20/cmis4sharepoint/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/11/20/cmis4sharepoint/</feedburner:origLink></item>
		<item>
		<title>Building a custom silverlight control (with sample code)</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/AyUPqMQ3T7s/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/11/16/building-a-custom-silverlight-control/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 10:17:36 +0000</pubDate>
		<dc:creator>maouinti</dc:creator>
		
		<category><![CDATA[C++]]></category>

		<category><![CDATA[Microsoft]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[Événements]]></category>

		<category><![CDATA[.NET]]></category>

		<category><![CDATA[control]]></category>

		<category><![CDATA[custom control]]></category>

		<category><![CDATA[Dependecy properties]]></category>

		<category><![CDATA[Silverlight]]></category>

		<category><![CDATA[XAML]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=71</guid>
		<description><![CDATA[
First time I had to build my own silverlight control, I asked myself a simple question from where I should start.
Usually, I start by defining the control specific properties that I will implement as a dependency property, after that I specify the default look for this control.
Through this tutorial, we will build a round button [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="float: left;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/06/silverlight_logo.jpg" alt="" width="160" height="177" /></p>
<p>First time I had to build my own silverlight control, I asked myself a simple question from where I should start.</p>
<p>Usually, I start by defining the control specific properties that I will implement as a dependency property, after that I specify the default look for this control.</p>
<p>Through this tutorial, we will build a round button control that could be easily personalized.</p>
<p><span id="more-71"></span></p>
<p>Now, let&#8217;s open Visual Studio select NewProject choose <em>silverlightApplication </em>follow the wizard and you will get two projects a webApplication and a silverlightProject.</p>
<p>The Next step is to create a silverlight library to do this, select the solution explorer right click and choose add NewProject. This time choose silverlightLibary and follow the wizard.</p>
<p>You will end up with something like this:</p>
<p style="center;"><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/explorer.png" alt="" /></p>
<p><strong></strong></p>
<p><strong></strong></p>
<p><strong>Dependency Property:</strong></p>
<p>To make our button round, we will use an ellipse. Its width, Height, fill color <em>and</em> stroke color will be specified by the user of our control.</p>
<p>To make that happen we have to add a class in the silverlight class library and make it inherit from Control.</p>
<p>In order to make this class useful we have to.</p>
<ul class="unIndentedList">
<li>Write a constructor</li>
<li>Write the specific properties as Dependency properties</li>
</ul>
<p>Achieving these two tasks is pretty straightforward all that we have to do for constructor is to write a line like shown below:</p>
<pre name="code" class="c#">#region Constructor
   public RoundButton()
    : base()
      {
         DefaultStyleKey = typeof(RoundButton);
      }
#endregion</pre>
<p>For <em>dependency property</em>, all we have to do is to register the dependency property and implement a <em>setter</em> and a <em>getter</em> for it like the example below:</p>
<p>This code may look cryptic the first time; however don&#8217;t worries we will go through it step by step. First this line of code</p>
<pre name="code" class="c#">public static readonly DependencyProperty CircleWidthProperty =
DependencyProperty.Register("CircleWidth", typeof(double), typeof(RoundButton), null);</pre>
<p>All that we are doing is registring CircleWidth as a dependency property, this name CircleWidth is very important because it&#8217;s the name that will appear in the xaml file when we will use our control in silverlight application, so pick a meanful name.</p>
<p>The first typeof is the type of our dependencyProperty.</p>
<p>The second typeof is the type of our Control if our class was ShinyButton for example the typeof will be ShinyButton instead of RoundButton here.</p>
<p>For the last parameter the one set at null it&#8217;s a <em>PropertyChangedCallBack</em> that in case we want to enable our control to change it&#8217;s dependency properties values after that it has been seted we have to implemented,we don&#8217;t really need it for our Control so we pass null.</p>
<p>The  rest of the dependency property is this:</p>
<pre name="code" class="c#">public double CircleWidth{

get { return (double)GetValue(CircleWidthProperty); }

set { SetValue(CircleWidthProperty, value); }

}</pre>
<p>This implementation is prety simple :</p>
<p>For the getter, we have to cast the return to the Property type, <em>double</em> in our case and we have to use the GetValue method that take as parameter CircleWidthProperty that is the DependencyProperty var name.</p>
<p>For the setter we have to use the SetValue method with the appropriate DependencyProperty name as is shown in the picture.</p>
<p>We have to do the same thing for the rest of Dependency Properties and we are done with the control class.</p>
<p><strong>Default Look:</strong></p>
<p>The edition of the default look of our control is done in the <em>generic.xaml </em>file. This file has to be placed under the Themes folder that is created on the silverlight class library. The generic.xaml file has to be a resource file. The generic.xaml.cs file has to be deleted.</p>
<p>Inside the generic.xaml file we have to change UserControl to ResourceDictionary and to import the control namespace.</p>
<p>After that we can start to describe the look of our control.</p>
<p>The generic.xaml has to look something like that:</p>
<pre name="code" class="xml">
<ResourceDictionary    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                       xmlns:blogExample="clr-namespace:RoundButtonControl">
    <Style TargetType="blogExample:RoundButton">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="blogExample:RoundButton">
                    <Canvas>
                    <Grid x:Name="RootElement">
                            <Ellipse x:Name="EllipseElement" Width="{TemplateBinding CircleWidth }"
                              Height="{TemplateBinding CircleHeight}"
                              Fill="{TemplateBinding CircleFillingColor}"
                              Stroke="{TemplateBinding CircleStrokeColor}" RenderTransformOrigin="0.5,0.5" >
                                <Ellipse.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform/>
                                        <SkewTransform/>
                                        <RotateTransform/>
                                        <TranslateTransform/>
                                    </TransformGroup>
                                </Ellipse.RenderTransform>
                            </Ellipse>
                            <TextBlock x:Name="TextElement" Text="{TemplateBinding ButtonText}" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" >
                                <TextBlock.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform/>
                                        <SkewTransform/>
                                        <RotateTransform/>
                                        <TranslateTransform/>
                                    </TransformGroup>
                                </TextBlock.RenderTransform>
                            </TextBlock>

                    </Grid>
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
</pre>
<p><strong>Conclusion:</strong></p>
<p>We are done with our simple Silverlight control. It&#8217;s definitely not the most useful control in the world, but it&#8217;s a good starting point for developing your own.</p>
<p>Keep tuned for part 2 of this Silverlight series.</p>
<p><strong>Download source code:</strong> <a href="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/SilverlightBlogExample.rar">SilverlightBlogExample.rar</a>.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/AyUPqMQ3T7s" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/11/16/building-a-custom-silverlight-control/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/11/16/building-a-custom-silverlight-control/</feedburner:origLink></item>
		<item>
		<title>JQuakrs est né chez IP-Tech !</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/JIG0i7C25kk/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/11/10/jquakrs-un-gestionnaire-de-quiz-pour-joomla/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 15:39:15 +0000</pubDate>
		<dc:creator>mtougorti</dc:creator>
		
		<category><![CDATA[Communication]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[Événements]]></category>

		<category><![CDATA[free]]></category>

		<category><![CDATA[JQuarks]]></category>

		<category><![CDATA[Php]]></category>

		<category><![CDATA[Quiz]]></category>

		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=70</guid>
		<description><![CDATA[Quand on est en phase de croissance rapide et qu&#8217;on doit recruter plusieurs profils dans un temps assez court, on est obligé d&#8217;adapter son processus de recrutement. Chez IP-Tech on a vite senti le besoin d&#8217;avoir un outil de mesure des compétences logiques et de programmation. Donc on a fait des tests pour les candidats [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal">Quand on est en phase de croissance rapide et qu&#8217;on doit recruter plusieurs profils dans un temps assez court, on est obligé d&#8217;adapter son processus de recrutement. Chez IP-Tech on a vite senti le besoin d&#8217;avoir un outil de mesure des compétences logiques et de programmation. Donc on a fait des tests pour les candidats dont les CVs ont passé la première sélection. Mais il fallait corriger à la main les tests et idéalement garder les résultats des candidats attachés à leurs dossiers. Gérer du papier, ça se fait. Mais il y a mieux.</p>
<p class="MsoNormal" style="text-align: center;"><a href="http://www.jquarks.org" target="_blank"><img style="border: 0pt none;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/11/jquarks-banner.png" alt="" width="441" height="122" /></a></p>
<p><span id="more-70"></span><br />
Donc on a cherché un outil qui permettrait aux candidats de passer les tests à distance ou dans nos locaux, de garder leurs résultats, de recomposer les quizzes pour les faciliter ou les compliquer en fonction des résultats des premiers tests, etc&#8230;</p>
<p>On voulait que cet outil gère les quizzes chronométrés, les questions ouvertes, les questions à plusieurs bonnes réponses, les quizzes à session uniques, etc&#8230;</p>
<p>Notre site institutionnel est sous joomla. Très classique. Mais on n&#8217;a trouvé aucun composant gratuit joomla qui répond à notre besoin. Donc on l&#8217;a créé !</p>
<p>D&#8217;où <a href="http://www.jquarks.org" target="_blank">JQuarks</a></p>
<p class="MsoNormal">JQuarks est un composant libre et gratuit de gestion de quiz s’intégrant nativement à la version 1.5 du Content Management System Joomla! La version actuelle est la 0.2.2 et elle permet notamment :</p>
<ul>
<li>La gestion des questions, ensembles de questions et quizzes.</li>
<li>L’affectation des utilisateurs enregistrés Joomla! aux quizzes et leur notification par e-mail.</li>
<li>Le support de trois types de questions (réponse libre, question à choix unique, question à choix multiple).</li>
<li>Quiz paginés et chronométrés.</li>
<li>Quiz privé et publique.</li>
<li>Export des réponses des utilisateurs en format csv (exploitable sous OOSpreadsheets et MSExcel).</li>
</ul>
<p class="MsoNormal">JQuarks est le moyen idéal de tester facilement et rapidement les acquis d’étudiants suite à un cours ou de leur proposer des tests blancs, d’effectuer une présélection lors de l’embauche de nouveaux employés etc…</p>
<p class="MsoNormal">Depuis le site officiel <a href="http://www.jquarks.org" target="_blank">JQuarks.org</a> vous pourrez <a href="http://www.iptechinside.com/labs/projects/list_files/jquarks" target="_blank">télécharger</a> JQuarks, avoir accès au <a href="http://www.iptechinside.com/labs/wiki/jquarks" target="_blank">guide d&#8217;utilisation</a> et même tester JQuarks via notre site de <a href="http://www.jquarks.com/demo/" target="_blank">démo</a>.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/JIG0i7C25kk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/11/10/jquakrs-un-gestionnaire-de-quiz-pour-joomla/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/11/10/jquakrs-un-gestionnaire-de-quiz-pour-joomla/</feedburner:origLink></item>
		<item>
		<title>Intégration de OSWorkflow avec les frameworks Spring IoC et Acegi</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/G4-hTU8m_NM/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/10/06/integration-de-osworkflow-avec-les-frameworks-spring-ioc-et-acegi/#comments</comments>
		<pubDate>Tue, 06 Oct 2009 07:58:01 +0000</pubDate>
		<dc:creator>Hamdi DOUSS</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Publications]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[Acegi]]></category>

		<category><![CDATA[IoC]]></category>

		<category><![CDATA[J2EE]]></category>

		<category><![CDATA[JEE]]></category>

		<category><![CDATA[OSWorkflow]]></category>

		<category><![CDATA[Spring]]></category>

		<category><![CDATA[Workflow]]></category>

		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=68</guid>
		<description><![CDATA[OSWorkflow se propose comme l’un des choix les plus importants de systèmes de workflow pour les développeurs Java. Offrant une flexibilité importante, le framework peut s’intégrer facilement aussi bien avec un code existant, qu’avec d’autres frameworks Java. Facilement…à condition d’en connaitre les rouages, parce que s’il y a un point faible à OSWorkflow, c’est bien [...]]]></description>
			<content:encoded><![CDATA[<p>OSWorkflow se propose comme l’un des choix les plus importants de systèmes de workflow pour les développeurs Java. Offrant une flexibilité importante, le framework peut s’intégrer facilement aussi bien avec un code existant, qu’a<a href="http://www.iptech-offshore.net/index.php?option=com_chronocontact&amp;chronoformname=extrait_programmez_123" target="_blank"><img class="alignleft" style="border: 0pt none; margin: 10px; float: left;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/10/programmez123.jpg" alt="" width="95" height="129" /></a>vec d’autres frameworks Java. Facilement…à condition d’en connaitre les rouages, parce que s’il y a un point faible à OSWorkflow, c’est bien la documentation ! L’objectif de cet article est de montrer l’integration de OSWorkflow avec Spring IoC et Acegi (Spring Security).</p>
<p><span style="background-color: #ffffcc;">Cet article a été publié dans le numéro actuel (Octobre 2009) du magazine<a href="http://programmez.com/magazine_articles.php?titre=Integration-de-OSWorkflow-avec-les-frameworks-Spring-IoC-et-Acegi&amp;id_article=1278&amp;magazine=123" target="_blank"> « PROgrammez »</a>. La version PDF de l&#8217;article est mise à votre disposition en <strong><a href="http://www.iptech-offshore.net/index.php?option=com_chronocontact&amp;chronoformname=extrait_programmez_123" target="_blank">téléchargement gratuit</a></strong></span>.</p>
<p><span id="more-68"></span></p>
<p><strong>La configuration basique de OSWorkflow</strong></p>
<p>La configuration par défaut de OSWorkflow repose sur un fichier xml nommé osworkflow.xml (et qui devrait être présent sous la racine du projet ou sous le répertoire META-INF). La structure de celui-ci devra comprendre deux choses essentielles : la classe de persistance et la classe de la factory. La classe de persistance est la classe qui gère la persistance des instances de workflows, des actions, des étapes…alors que la factory gère les descripteurs qui modélisent le workflow. Ci-dessous un exemple de fichier de configuration où la persistance se fait en mémoire (qui n’est bien entendu utile qu’en cas de tests) et où la factory lit (et éventuellement écrit) les modèles à partir de descriptions dans des fichiers XML.</p>
<pre name="code" class="xml">&lt;osworkflow&gt;
   &lt;persistence class="com.opensymphony.workflow.spi.memory.MemoryWorkflowStore"/&gt;
   &lt;factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory"&gt;
      &lt;property key="resource" value="workflows.xml" /&gt;
   &lt;/factory&gt;
&lt;/osworkflow&gt;</pre>
<p>En partant de ce type de configuration, le point d’entrée dont on dispose pour utiliser OSWorkflow depuis notre code, est d’instancier une classe qui implémente l’interface com.opensymphony.workflow.Workflow et qui, généralement, hérite de com.opensymphony.workflow.AbstractWorkflow. La classe fournie la plus basique (comme son nom l’indique) est BasicWorkflow, qu’on peut utiliser ainsi :</p>
<pre name="code" class="java">Workflow workflow = new BasicWorkflow("UtilisateurCourant");
DefaultConfiguration config = new DefaultConfiguration();
workflow.setConfiguration(config);</pre>
<p><strong>Inconvénients de la configuration basique</strong></p>
<p>Les inconvénients d’une telle utilisation sont assez clairs. En effet, l’instance du workflow qu’on a créé est associé à l’utilisateur « UtilisateurCourant ». Et comme toute application de workflow « sérieuse » fait intervenir plusieurs utilisateurs, on aura au moins une instance par utilisateur. Le deuxième inconvénient se rapporte au fait qu’il sera « lourd » de gérer un point unique et global depuis lequel on invoque les instances du workflow pour lancer des requêtes ou effectuer des actions. C’est pour cela qu’on propose de définir un bean Spring unique dans l’application, qu’on pourra injecter dans les services qui en auront besoin et dont la récupération de l’utilisateur en cours (connecté) se fait de manière transparente à partir du contexte Acegi.</p>
<p><strong>Implémentation Acegi du contexte workflow</strong></p>
<p>Pour mieux appréhender le problème d&#8217;integration de Acegi, une compréhension du mécanisme interne de récupération de l&#8217;utilisateur (nommé &#8220;Caller&#8221; dans le vocabulaire de OSWorkflow) s&#8217;impose. En fait, la classe AbstractWorkflow récupère le caller à partir d&#8217;un service implémentant l&#8217;interface com.opensymphony.workflow.WorkflowContext en invoquant la méthode getCaller de celui-ci. Nous allons donc développer notre propre classe de contexte (qui implémente com.opensymphony.workflow.WorkflowContext) et qui renvoie le caller à partir d&#8217;un IUserService (un service utilisateur de base), et notre propre classe de workflow (qui hérite de AbstractWorkflow) qui supporte l&#8217;injection d&#8217;un contexte de façon dynamique.</p>
<pre name="code" class="java">public class IPTechWorkflow extends AbstractWorkflow {

public IPTechWorkflow() {
}

public void setContext(WorkflowContext wfctx)
{
   super.context = wfctx;
}

}</pre>
<pre name="code" class="java">public class ConnectedUserWorkflowContext implements WorkflowContext{

private IUserService userService = null;

public ConnectedUserWorkflowContext() {
}
public String getCaller() {
   return userService.getConnectedUserInfo().getUsername();
}
public void setRollbackOnly() {
   // Gestion de Rollback non couverte dans cet article
}
}</pre>
<p>Nous avons, dans ce code, supposé que l&#8217;interface IUserService dispose d&#8217;une méthode getConnectedUserInfo() et qui renvoie une instance d&#8217;une classe &#8220;User&#8221;.</p>
<p>Une des avantages de ce type d&#8217;integration est qu&#8217;il est complétement décorrélé du système d&#8217;authentification (remarquez qu&#8217;on n&#8217;a pas encore évoqué Acegi). Il nous suffit donc, à présent, de fournir une implémentation de l&#8217;interface IUserService et qui interroge le contexte Acegi pour récupérer l&#8217;utilisateur connecté :</p>
<pre name="code" class="java">public User getConnectedUserInfo() {

   Object objt = org.acegisecurity.context.SecurityContextHolder.
getContext().getAuthentication().getPrincipal();

   return (User)objt;

}</pre>
<p><strong>Définition des beans de configurations</strong></p>
<p>Définissons à présent, les beans Spring qu&#8217;on injectera :<br />
- Le bean du service utilisateur qui récupère l&#8217;utilisateur à partir de Acegi (implémenté par une classe qu&#8217;on appellera AcegiUserServiceImpl)</p>
<pre name="code" class="xml">&lt;bean id="userService"
class="com.iptech.programmez.authentication.AcegiUserServiceImpl"&gt;

&lt;/bean&gt;</pre>
<p>- Le bean du contexte workflow qui renvoie un caller à partir du service utilisateur</p>
<pre name="code" class="xml">&lt;bean id="workflowContext"
class="com.iptech.programmez.workflow.ConnectedUserWorkflowContext"&gt;
   &lt;property name="userService" ref="userService"/&gt;
&lt;/bean&gt;</pre>
<p>- Le bean du workflow qui permettra l&#8217;injection d&#8217;un contexte</p>
<pre name="code" class="xml">&lt;bean id="workflow"
class="com.iptech.programmez.workflow.IPTechWorkflow"&gt;
   &lt;property name="context" ref="workflowContext"/&gt;
&lt;/bean&gt;</pre>
<p>Nous allons, maintenant, traiter la configuration de la factory et de la persistance avec Spring. Rien ne nous empêche, bien entendu, de laisser les choses comme elles le sont, et définir cette configuration dans notre osworkflow.xml, mais on aurait dans ce cas deux fichiers de configuration distincts. Le but étant de définir un bean pour la factory et un bean pour la persistance et de les injecter directement dans notre bean de workflow.<br />
La distribution de OSWorkflow vient avec la classe com.opensymphony.workflow.config.SpringConfiguration qui est une classe de définition de configuration, qui ne lit pas à partir de osworkflow.xml (comme la configuration par défaut), mais qui nous permet d’injecter directement des beans (elle expose des setteurs pour ceux-ci). L’injection de la configuration devient alors directe.</p>
<pre name="code" class="xml">&lt;bean id="workflow"
class="com.iptech.programmez.workflow.IPTechWorkflow"&gt;
   &lt;property name="context" ref="workflowContext"/&gt;
   &lt;property name="configuration"&gt;
      &lt;ref local="osworkflowConfiguration"/&gt;
   &lt;/property&gt;
&lt;/bean&gt;

&lt;bean id="osworkflowConfiguration"
class="com.opensymphony.workflow.config.SpringConfiguration"&gt;
   &lt;property name="store"&gt;
      &lt;ref local="idBeanDePersistance"/&gt;
   &lt;/property&gt;
   &lt;property name="factory"&gt;
      &lt;ref local="idBeanDeFactory"/&gt;
   &lt;/property&gt;
&lt;/bean&gt;</pre>
<p><strong>Déclaration du resolver permettant l&#8217;utilisation de beans Spring</strong></p>
<p>Nous allons à présent aborder un autre aspect de l’integration de OSWorkflow avec Spring, et qui porte sur l’utilisation de beans Spring comme des pré-fonctions, des post-fonctions et des conditions sur les actions du workflow. En effet, lorsque nous modélisons les étapes et les actions de notre workflow, nous avons la possibilité d’indiquer au moteur de workflow qu’une condition, ou une fonction est implémenté dans un bean Spring plutôt que de lui indiquer directement le nom de la classe. Ceci se fait en injectant au bean du workflow ce qu’on appelle un « resolver ». Le resolver est utilisé par le moteur de workflow pour résoudre les types des conditions et fonctions. Dans notre cas, on s’intéresse à un resolver qui sait interpréter le type « bean spring » et qui récupère celui-ci pour l’invoquer. Un tel resolver est inclus dans la distribution de OSWorkflow, il s’agit de com.opensymphony.workflow.util.SpringTypeResolver qui reconnait les conditions et les fonctions de type « spring » (en minuscule) et invoque le bean dont l’id est indiqué comme valeur de l’argument « bean.name ». On pourra donc, dans notre modélisation, utiliser le bout suivant :</p>
<pre name="code" class="xml">&lt;restrict-to&gt;
   &lt;conditions&gt;
      &lt;condition type="spring"&gt;
         &lt;arg name="bean.name"&gt;allowOwner&lt;/arg&gt;
      &lt;/condition&gt;
   &lt;/conditions&gt;
&lt;/restrict-to&gt;</pre>
<p>Et il ne nous reste que d’indiquer au moteur d’utiliser le resolver approprié :</p>
<pre name="code" class="xml">&lt;bean id="workflow"
class="com.iptech.programmez.workflow.IPTechWorkflow"&gt;
   &lt;property name="context" ref="workflowContext"/&gt;
   &lt;property name="configuration"&gt;
      &lt;ref local="osworkflowConfiguration"/&gt;
   &lt;/property&gt;
   &lt;property name="resolver" ref="workflowTypeResolver"/&gt;
&lt;/bean&gt;

&lt;bean id="workflowTypeResolver"
class="com.opensymphony.workflow.util.SpringTypeResolver" /&gt;</pre>
<p>Nous arrivons à la fin de cet article où on a pu mettre en place un bean Spring de workflow qu&#8217;on pourra injecter dans nos classes de services, où la récupération de l&#8217;utilisateur connecté se fait de manière transparente à partir du contexte Acegi.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/G4-hTU8m_NM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/10/06/integration-de-osworkflow-avec-les-frameworks-spring-ioc-et-acegi/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/10/06/integration-de-osworkflow-avec-les-frameworks-spring-ioc-et-acegi/</feedburner:origLink></item>
		<item>
		<title>Boostez votre Visual Studio</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/GO3uwl9EPqU/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/09/23/ameliorer-lenvironnement-de-developpement-visual-studio/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 10:48:54 +0000</pubDate>
		<dc:creator>Ahmed Charfeddine</dc:creator>
		
		<category><![CDATA[Microsoft]]></category>

		<category><![CDATA[Process]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[Développement]]></category>

		<category><![CDATA[DevExpress]]></category>

		<category><![CDATA[DxCore]]></category>

		<category><![CDATA[Editor]]></category>

		<category><![CDATA[IDE]]></category>

		<category><![CDATA[Productivity]]></category>

		<category><![CDATA[Refactoring]]></category>

		<category><![CDATA[Visual Sudio]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=33</guid>
		<description><![CDATA[Utilisateurs de Visual Studio, Avez vous déjà pensé à augmenter votre productivité ? N&#8217;écoutez plus Bob et Randie et lisez cet article!


Améliorer son IDE en installant des plugins ou en créer est pour le développeur une activité qui va en parallèle avec le cours normal de son travail de développement.
On ne parle pas des améliorations [...]]]></description>
			<content:encoded><![CDATA[<p>Utilisateurs de Visual Studio, Avez vous déjà pensé à augmenter votre productivité ? N&#8217;écoutez plus <a href="http://www.geekherocomic.com/2008/10/17/how-to-improve-productivity/" target="_blank">Bob et Randie</a> et lisez cet article!</p>
<p><img class="alignnone" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/09/productivity.png" alt="Cliquez pour la suite!" /></p>
<p><span id="more-33"></span></p>
<p>Améliorer son IDE en installant des plugins ou en créer est pour le développeur une activité qui va en parallèle avec le cours normal de son travail de développement.</p>
<p>On ne parle pas des améliorations à l&#8217;infrastructure utilisée (JEE, .NET Framework, MFC, etc.), dont l&#8217;effet va se voir sur le programme développé et ses dépendances : cela est le cas par exemple d&#8217;une bibliothèque d&#8217;extension à MFC, ou une bibliothèque .NET qui apporte un nouveau controle avec la palette RAD servant à le manipuler via le designer.</p>
<p>Il s&#8217;agit plutôt d&#8217;améliorations touchant le processus du développement :</p>
<ul>
<li>Le refactoring : par exemple, envoyer automatiquement l&#8217;implémentation d&#8217;une méthode C++ écrite dans le .h, vers le .cpp.</li>
<li>L&#8217;édition:  cela comprend l&#8217;<a href="http://en.wikipedia.org/wiki/IntelliSense" target="_blank">intellisense</a>, la façon dont le code est visuellement présenté (coloriage) et la navigation intelligente entre les blocs de code.</li>
<li>La compilation : certains plugins permettent de la compilation distribuées de projets (exp. <a href="http://www.xoreax.com/" target="_blank">Incredibuild</a>)</li>
<li>La gestion du code : &#8220;versionning&#8221;, annotation, etc.</li>
</ul>
<p>L&#8217;intérêt de certaines fonctionnalités peut ne pas se justifier facilement, surtout quand il s&#8217;agit de besoins spécifiques à une même personne ou un même projet. Dans le cas contraire, où l&#8217;amélioration concerne une population plus large, il est opportun d&#8217;automatiser cette amélioration et la partager avec la communauté des développeurs.</p>
<p>En revanche, pour passer à la concrétisation, il n&#8217;est pas évident de se donner le temps de comprendre l&#8217;architecture d&#8217;extensibilité d&#8217;un IDE donné : comment implémenter une fonctionnalité particulière qui s&#8217;installe dans son interface et comment il communique avec ses composants en interceptant et réagissant aux évènements d&#8217;intérêt</p>
<p>Visual Studio (VS) n&#8217;est pas exception. Par contre, <a href="http://www.devexpress.com/Downloads/Visual_Studio_Add-in/index.xml" target="_blank">DxCore</a>, publié gratuitement par <a href="http://www.devexpress.com/" target="_blank">Devexpress</a>, offre énormément de possibilités pour créer ce type de plugin pour VS.</p>
<p style="30px;"><strong>Mise à jour: </strong>Après l&#8217;écriture de cet article, DevExpress a rendu public une version légère de son produit CodeRush baptisée CodeRush Express. Cette distribution est fournie avec le noyau DxCore ainsi que plusieurs plugins.</p>
<p>La création d&#8217;un plugin est en elle même assistée par des outils RAD. Le développeur n&#8217;a qu&#8217;à faire des drag-and-drop  du composant de son choix à partir de la toolbox. Ensuite, il a accès à toutes ses propriétés, à la surcharge de ses méthode virtuelles, etc,</p>
<p>Encore plus intéressant : l&#8217;accès au résultat du parseur de code DxCore. Dans une override de type  <em>OnEditorPaintLangageElement</em> par exemple, qui est appelée par le DxCore lorsque l&#8217;éditeur est en train de dessiner un morceau de code particulier, le dévelopeur peut accéder à l&#8217;elément en cours, tester son type, accéder à son étendu dans l&#8217;éditeur et puis agir sur les propriétés du dessin en modifiant une structure <em>PaintArgs </em>passée en paramètre.</p>
<p>Le sujet est assez intéressant et à la porté de tous les développeurs. Je vous invite à consulter ces liens pour créer vos propres plugins qui vous éviterons les tâches les plus fastidieuses:</p>
<ul>
<li><a href="http://www.devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/Training.xml" target="_blank">Screencasts officiels</a></li>
<li><a href="http://code.google.com/p/dxcorecommunityplugins/" target="_blank">Plusieurs plugins sur Google Code</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/GO3uwl9EPqU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/09/23/ameliorer-lenvironnement-de-developpement-visual-studio/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/09/23/ameliorer-lenvironnement-de-developpement-visual-studio/</feedburner:origLink></item>
		<item>
		<title>Bug OSWorkflow : un NullPointerException causé par AbstractWorkflow.canInitialize</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/5RsKj8eDr2M/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/09/21/a-propos-dun-bug-osworkflow-un-nullpointerexception-cause-par-abstractworkflowcaninitialize/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 11:31:57 +0000</pubDate>
		<dc:creator>Hamdi DOUSS</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[bug]]></category>

		<category><![CDATA[canInitialize]]></category>

		<category><![CDATA[exception]]></category>

		<category><![CDATA[NullPointerException]]></category>

		<category><![CDATA[OSWorkflow]]></category>

		<category><![CDATA[PropertySet]]></category>

		<category><![CDATA[PropertySetManager.getInstance]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=66</guid>
		<description><![CDATA[Développant avec OSWorkflow dans plusieurs projets, j’ai affronté, un jour, une exception étrange. Ce n’était pas le genre d’exceptions dont on peut deviner la cause dès le premier coup d’œil.


This article is also available in English.

java.lang.NullPointerException
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:261)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at com.sun.appserv.server.util.ASURLClassLoader.loadClass(ASURLClassLoader.java:100)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at com.sun.enterprise.util.ConnectorClassLoader.loadClass(ConnectorClassLoader.java:176)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1405)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1292)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:51)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:31)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:395)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:364)
Mon premier réflexe était de la googler. [...]]]></description>
			<content:encoded><![CDATA[<p style="margin-left: 0pt; margin-right: 0pt;">Développant avec <a href="http://www.opensymphony.com/osworkflow/" target="_blank">OSWorkflow</a> dans plusieurs projets, j’ai affronté, un jour, une exception étrange. Ce n’était pas le genre d’exceptions dont on peut deviner la cause dès le premier coup d’œil.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">
<p><img class="size-full wp-image-49" style="border: 0pt none; " title="osw" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/01/osw.png" alt="Open Symphony - OS Workflow" width="288" height="74" /></p>
<p><em>This article is also available in <a href="http://www.iptech-offshore.net/blog/?p=65">English</a>.</em></p>
<p><span id="more-66"></span></p>
<pre name="code" class="java">java.lang.NullPointerException
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:261)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at com.sun.appserv.server.util.ASURLClassLoader.loadClass(ASURLClassLoader.java:100)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at com.sun.enterprise.util.ConnectorClassLoader.loadClass(ConnectorClassLoader.java:176)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1405)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1292)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:51)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:31)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:395)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:364)</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">Mon premier réflexe était de la <a href="http://fr.wiktionary.org/wiki/googler" target="_blank">googler</a>. Suivre les quelques liens de résultats que j’ai trouvé (comme <a href="http://forums.opensymphony.com/thread.jspa?messageID=140595" target="_blank">ici</a>, <a href="http://marc.info/?l=opensymphony-workflow&amp;m=108447108609243&amp;w=2" target="_blank">là</a> et <a href="http://forums.opensymphony.com/thread.jspa?messageID=54536" target="_blank">là</a>) n’a pas résolu le problème. Des questions sont restées sans réponses, d’autres, ont eu le conseil de vérifier les jars et le packaging. Cela m’a poussé à aller de l’avant, et à analyser le code source pour le déboguer et retracer l’origine du problème.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">Ce que j’ai découvert, c’est que le problème réside dans la méthode <em>canInitialize </em>de la classe <em>AbstractWorkflow</em>. Comme tout Workflow (classe qui implémente l’interface Worklflow) hérite de <em>AbstractWorkflow </em>(même si vous développez vos propres implémentations, il est fortement recommandé d’hériter de <em>AbstractWorkflow</em>), vous pouvez avoir ce genre d’exceptions si vous appelez la méthode <em>canInitialize</em>. Il est évident que le fait d’appeler <em>canInitialize </em>existe dans toute application (ou presque) qui se base sur OSWorkflow, tout simplement parce que cette méthode indique si l’utilisateur courant est autorisé à démarrer une nouvelle instance d’un workflow donné.</p>
<p>Les lignes 394 et 395 sont les plus intéressantes (de la méthode <em>canInitialize</em>) :</p>
<pre name="code" class="java">// since no state change happens here, a memory instance is just fine
PropertySet ps = PropertySetManager.getInstance("memory", null);</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">Ce que ce bout de code signifie exactement c’est : demander au PropertySetManager d’instancier l’implémentation <a href="http://www.opensymphony.com/propertyset/" target="_blank">PropertySet</a> qui a été configuré avec le nom &#8220;memory&#8221; dans le fichier de configuration de PropertySet. Cela fonctionne à merveille avec la configuration par défaut de PropertySet. Mais qu’en est-il si le développeur choisis d’avoir une configuration PropertySet propre à lui (en ayant son propre propertyset.xml) qui ne définit pas une implémentation PropertySet avec le nom &#8220;memory&#8221; ?</p>
<p style="margin-left: 0pt; margin-right: 0pt;">C’était exactement le cas de tous ceux qui ont fait face à cette exception. A mon avis, une telle implémentation soumet le développeur à une forte contrainte qui n’est mentionné nulle part dans la documentation.</p>
<p style="margin-left: 0pt; margin-right: 0pt;"><strong>Première solution : Le contournement</strong></p>
<p style="margin-left: 0pt; margin-right: 0pt;">La première solution qui peut venir à l’esprit de chacun est celle de définir, tout simplement, une implémentation PropertySet avec le nom &#8220;memory&#8221;, en ajoutant :</p>
<pre name="code" class="java">&lt;propertyset name="memory" class="com.opensymphony.module.propertyset.memory.MemoryPropertySet" /&gt;</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">dans le fichier de configuration.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">Cette solution est rapide et facile à mettre en œuvre, mais fait introduire quelque chose que, personnellement, je déteste : du code et/ou de la configuration qui ne sert à rien, qui est juste là &#8220;pour que ça fonctionne&#8221; et que &#8220;de toute façon, ça ne mange pas de pain&#8221;.</p>
<p style="margin-left: 0pt; margin-right: 0pt;"><strong>Deuxième solution : Redéfinir la classe AbstractyWorkflow</strong></p>
<p style="margin-left: 0pt; margin-right: 0pt;">Une solution plus &#8220;clean&#8221;, serait de réécrire la classe <em>AbstractWorkflow </em>(i.e. : corriger le bug). Ce qu’on devrait modifier est évidemment la 395<sup>ème</sup> ligne.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">Commençons par comprendre l’utilité de cette instance de PropertySet (stocké dans la variable <em>ps</em>). Si nous essayons d’examiner les lignes de code suivantes, nous nous apercevrons facilement que cette instance est utilisée pour…rien du tout !</p>
<p style="margin-left: 0pt; margin-right: 0pt;">Elle est là, juste parce que la méthode de l’interface <em>Condition</em> prend une instance de PropertySet comme l’un de ses paramètres. Et c’est pour cela qu’on peut lire dans la ligne de commentaire &#8220;a memory instance is just fine&#8221;, qui veut dire : &#8220;une instance mémoire est amplement suffisante&#8221;. Puisque une instance PropertySet est toujours associé à une instance de workflow, et qu’il ne s’agit <strong>ici</strong> d’aucune instance de workflow (rappelez-vous, on essaie juste de savoir si l’utilisateur courant a le droit d’en instancier), cela n’a pas vraiment beaucoup de sens de parler ici d’une instance PropertySet.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">C’est une raison pour laquelle affecter &#8216;null&#8217; à la variable <em>ps</em> peut être suffisant. Mais, si votre (propre) condition dépend du PropertySet passé en paramètre comme ci-dessous :</p>
<pre name="code" class="java">public boolean passesCondition(Map transientVars, Map args, PropertySet ps) throws StoreException {

String some = ps.getString("param");</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">Ce qui est, d’ailleurs, bizarre pour une condition d’initialisation de workflow (sauf si c’est une classe réutilisée pour d’autres conditions), vous aurez surement un <em>NullPointerException</em> (à moins que vous ne testiez sur la variable <em>ps</em>).</p>
<p style="margin-left: 0pt; margin-right: 0pt;">Bref, je vous suggère un substitut plus sure à notre 395<sup>ème</sup> ligne :</p>
<pre name="code" class="java">//directly instantiate the memory propertyset implementation
//no longer rely on the way the developer configuration

PropertySet ps = new MemoryPropertySet();</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">Ou aussi, vous pouvez affectez une instance de classe anonyme :</p>
<pre name="code" class="java">PropertySet ps = new PropertySet(){

    public boolean exists(String arg0) throws PropertyException {
        return false;
    }

    public Object getAsActualType(String arg0) throws PropertyException {
        return null;
    }

    public boolean getBoolean(String arg0) throws PropertyException {
        return false;
    }

    ...
    ...
    ...

    public int getInt(String arg0) throws PropertyException {
        return 0;
    }

    public Collection getKeys() throws PropertyException {
        return Collections.EMPTY_LIST;
    }

    ...
    ...

    public boolean supportsTypes() {
        return false;
    }

};</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">J’espère que ce billet aidera certaines personnes. Je voulais, juste, ajouter que la deuxième solution proposée peut causer des problèmes ou des comportements inattendus, si vous mettez à jour votre version de OSWorkflow et que vous oubliez de réajustez vos modifications.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/5RsKj8eDr2M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/09/21/a-propos-dun-bug-osworkflow-un-nullpointerexception-cause-par-abstractworkflowcaninitialize/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/09/21/a-propos-dun-bug-osworkflow-un-nullpointerexception-cause-par-abstractworkflowcaninitialize/</feedburner:origLink></item>
		<item>
		<title>OSWorkflow bug: a NullPointerException caused by AbstractWorkflow.canInitialize</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/t3-y-HMmoxM/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/09/21/about-an-osworkflow-bug-a-nullpointerexception-caused-by-abstractworkflowcaninitialize/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 11:23:07 +0000</pubDate>
		<dc:creator>Hamdi DOUSS</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[bug]]></category>

		<category><![CDATA[canInitialize]]></category>

		<category><![CDATA[exception]]></category>

		<category><![CDATA[NullPointerException]]></category>

		<category><![CDATA[OSWorkflow]]></category>

		<category><![CDATA[PropertySet]]></category>

		<category><![CDATA[PropertySetManager.getInstance]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=65</guid>
		<description><![CDATA[Using OSWorkflow in several projects, I faced one day a strange exception. That was the kind of ones that you can&#8217;t find out its cause at a glance.


Cet article est disponible aussi en Français

java.lang.NullPointerException
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:261)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at com.sun.appserv.server.util.ASURLClassLoader.loadClass(ASURLClassLoader.java:100)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at com.sun.enterprise.util.ConnectorClassLoader.loadClass(ConnectorClassLoader.java:176)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1405)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1292)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:51)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:31)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:395)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:364)
My first reflex was obviously googling it. Browsing the [...]]]></description>
			<content:encoded><![CDATA[<p style="margin-left: 0pt; margin-right: 0pt;">Using <a href="http://www.opensymphony.com/osworkflow/" target="_blank">OSWorkflow</a> in several projects, I faced one day a strange exception. That was the kind of ones that you can&#8217;t find out its cause at a glance.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">
<p><img class="size-full wp-image-49" style="border: 0pt none; " title="osw" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/01/osw.png" alt="Open Symphony - OS Workflow" width="288" height="74" /></p>
<p><em>Cet article est disponible aussi en <a href="http://www.iptech-offshore.net/blog/?p=66">Français</a></em></p>
<p><span id="more-65"></span></p>
<pre name="code" class="java">java.lang.NullPointerException
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:261)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at com.sun.appserv.server.util.ASURLClassLoader.loadClass(ASURLClassLoader.java:100)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at com.sun.enterprise.util.ConnectorClassLoader.loadClass(ConnectorClassLoader.java:176)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1405)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1292)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:51)
at com.opensymphony.module.propertyset.PropertySetManager.getInstance(PropertySetManager.java:31)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:395)
at com.opensymphony.workflow.AbstractWorkflow.canInitialize(AbstractWorkflow.java:364)</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">My first reflex was obviously googling it. Browsing the few results I found (like <a href="http://forums.opensymphony.com/thread.jspa?messageID=140595" target="_blank">here</a>, <a href="http://marc.info/?l=opensymphony-workflow&amp;m=108447108609243&amp;w=2" target="_blank">here </a>and <a href="http://forums.opensymphony.com/thread.jspa?messageID=54536" target="_blank">here</a>), didn&#8217;t brought any solution. Some questions remain responseless, the others suggest verifying the jars or the application packaging. That pushed me to have a look at the source code and to debug it in order to track the problem&#8217;s origin. What I found, is that the problem resides in the <em>canInitialize</em> method of the <em>AbstractWorkflow </em>class. As every Workflow (by &#8216;Workflow&#8217;, I mean the classes implementing the <em>Workflow </em>interface) inherits from <em>AbstractWorkflow </em>(even if you develop your own implementation, you are highly encouraged to inherits from <em>AbstractWorkflow</em>), you can have this kind of exception thrown when you call <em>canInitialize</em>. It&#8217;s clear that calling <em>canInitialize </em>is present in almost every OSWorkflow based application, as this method is responsible for telling the caller where the current user have the ability to start a new instance of a given workflow.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">The 394 and the 395 lines are the most intersting part of the code (of the <em>canInitialize</em> method).</p>
<pre name="code" class="java">// since no state change happens here, a memory instance is just fine

PropertySet ps = PropertySetManager.getInstance("memory", null);</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">What this piece of code exactly means is : Tell the PropertySetManager to instantiate the <a href="http://www.opensymphony.com/propertyset/" target="_blank">PropertySet</a> implementation that was configured with the name &#8220;memory&#8221; in the PropertySet configuration file. That can works fine with the default configuration of PropertySet.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">But, what if the developer chooses to have a custom PropertySet configuration (by having its own propertyset.xml) that does not define a PropertySet with the &#8220;memory&#8221; name ?</p>
<p style="margin-left: 0pt; margin-right: 0pt;">That was exactly my case and of many others. In my opinion, such implementation makes a tight constraint which is not mentioned anywhere in the documentation.</p>
<p><strong>First solution : The workaround</strong></p>
<p style="margin-left: 0pt; margin-right: 0pt;">The first solution that comes to someone&#8217;s mind is the workaround of defining a &#8220;memory&#8221; PropertySet, by adding :</p>
<pre name="code" class="java">&lt;propertyset name="memory" class="com.opensymphony.module.propertyset.memory.MemoryPropertySet" /&gt;</pre>
<p style="margin-left: 0pt; margin-right: 0pt;">
<p style="margin-left: 0pt; margin-right: 0pt;">
<p style="margin-left: 0pt; margin-right: 0pt;">in the custom configuration file.</p>
<p style="margin-left: 0pt; margin-right: 0pt;">This is the kind of solutions that are fast, and very easy to implement, but also, the kind of ones that I personally hate, simply because I hate that unused and useless piece of code or piece of configuration, that is here just &#8220;to make it work&#8221; and that anyway &#8220;doesn&#8217;t hurt&#8221; !</p>
<p style="margin-left: 0pt; margin-right: 0pt;">
<p><strong>Second solution : Redefining the AbstractyWorkflow class</strong></p>
<p>A cleaner solution would be to rewrite the <em>AbstractWorkflow </em>class (i.e : correct the bug). What have to be changed is obviously the 395<sup>th</sup> line.</p>
<p>Let&#8217;s begin by understanding what the PropertySet instance (stored in <em>ps </em>variable) is used for. If we try to examine the following lines of code, we easily notice that it is just used for nothing !</p>
<p>It&#8217;s there just because the passing conditions methods require a PropertySet instance as one of their parameters. And that&#8217;s why, the comment line says &#8220;a memory instance is just fine&#8221;. And since a PropertySet is always associated with a workflow instance, and we are not dealing with any workflow instance here (remember, we just want to know if the current user can start a workflow), it has no sense to talk about a PropertySet instance here.</p>
<p>That&#8217;s why, storing &#8216;null&#8217; in the <em>ps </em>variable can be enough. But, if your (custom) condition classes rely on the PropertySet passed parameter as below :</p>
<pre name="code" class="java">public boolean passesCondition(Map transientVars, Map args, PropertySet ps) throws StoreException {

String some = ps.getString("param");</pre>
<p>which, by the way, is really weird for a starting workflow condition (only if it&#8217;s a reused class for other conditions), you&#8217;ll have a NullPointerException thrown (if you&#8217;re not testing in the <em>ps </em>variable). So, I suggest a safer replacement for our famous 395<sup>th</sup> line :</p>
<pre name="code" class="java">//directly instantiate the memory propertyset implementation
//no longer rely on the way the developer configuration

PropertySet ps = new MemoryPropertySet();</pre>
<p>Or you can also store an anonymous class instance :</p>
<pre name="code" class="java">PropertySet ps = new PropertySet(){

    public boolean exists(String arg0) throws PropertyException {
        return false;
    }

    public Object getAsActualType(String arg0) throws PropertyException {
        return null;
    }

    public boolean getBoolean(String arg0) throws PropertyException {
        return false;
    }

    ...
    ...
    ...

    public int getInt(String arg0) throws PropertyException {
        return 0;
    }

    public Collection getKeys() throws PropertyException {
        return Collections.EMPTY_LIST;
    }

    ...
    ...

    public boolean supportsTypes() {
        return false;
    }

};</pre>
<p>I hope this post could help some people, I want just to add finally that the second solution can cause problems or unexpected behaviour if you make an update of your OSWorkflow jars, and decide to rely on a newer version of the framework, and besides, forget to merge your modifications with the newer class.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/t3-y-HMmoxM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/09/21/about-an-osworkflow-bug-a-nullpointerexception-caused-by-abstractworkflowcaninitialize/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/09/21/about-an-osworkflow-bug-a-nullpointerexception-caused-by-abstractworkflowcaninitialize/</feedburner:origLink></item>
		<item>
		<title>Office Fluent UI en C++ natif</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/5IwVN1LV4Q4/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/07/17/office-fluent-ui-en-c-natif/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 15:42:22 +0000</pubDate>
		<dc:creator>Ahmed Charfeddine</dc:creator>
		
		<category><![CDATA[C++]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[2007 theme look]]></category>

		<category><![CDATA[C++ natif]]></category>

		<category><![CDATA[dockable pane]]></category>

		<category><![CDATA[docking control bar]]></category>

		<category><![CDATA[Floaty Toolbar]]></category>

		<category><![CDATA[MFC]]></category>

		<category><![CDATA[MFC Feature Pack]]></category>

		<category><![CDATA[Office 2007 Look and Feel]]></category>

		<category><![CDATA[Office Fluent UI]]></category>

		<category><![CDATA[Ribbon]]></category>

		<category><![CDATA[Ribbon button]]></category>

		<category><![CDATA[Ribbon main button]]></category>

		<category><![CDATA[Ribbon UI]]></category>

		<category><![CDATA[unmanaged C++]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=57</guid>
		<description><![CDATA[
Vous avez probablement lu cet article rédigé par mon collègue et dont un extrait a paru dans le magazine français PROgrammez (Version PDF). Savez vous par contre qu&#8217;on peut produire des interfaces aussi charmantes en C++ natif ?
Même si l&#8217;orientation des éditeurs vers des architectures basées sur les frameworks Java ou Micorosft .NET s&#8217;explique essentiellement [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="border: 0pt none; margin: 10px; float: left;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/FluentUIs.png" alt="Fluent Interfaces - C++" /></p>
<p>Vous avez probablement lu <a href="http://www.iptech-offshore.net/blog/?p=50">cet article</a> rédigé par mon collègue et dont un extrait a paru dans le magazine français <a href="http://www.iptech-offshore.net/index.php?option=com_chronocontact&amp;chronoformname=extrait_programmez_116" target="blank">PROgrammez</a> (Version PDF). Savez vous par contre qu&#8217;on peut produire des interfaces aussi charmantes en C++ natif ?</p>
<p>Même si l&#8217;orientation des éditeurs vers des architectures basées sur les frameworks Java ou Micorosft .NET s&#8217;explique essentiellement par la facilité apportée par ces derniers en termes de gestion de complexité, on ne peut nier les effets de mode et les efforts marketing des éditeurs et des communautés de ces produits.</p>
<p><span id="more-57"></span></p>
<p>J’estime par ailleurs qu’il est judicieux d&#8217;inclure le langage C++ comme une des alternatives pour le développement des nouveaux produits. On ne peut pas imaginer par exemple, un système qui devra interagir avec du hardware ou bien effectuer de gros volumes de calcul algorithmique sans que l&#8217;on pense à envisager C++ comme langage de programmation.</p>
<p>Une autre approche consiste à considérer ce langage pour le développement de quelques briques logicielles et les intégrer par la suite à des modules développés sous Java, MS.NET ou autre. Cependant, l&#8217;effort de bridging dépensé peut s’avérer parfois beaucoup plus important que tout faire en C++.</p>
<p>Je ne suis pas le seul à promouvoir C++ comme architecture logicielle pour les applicatifs de bureau : il vous suffit de considérer ces deux produits:</p>
<ul>
<li><a href="http://www.nefsis.com/" target="_blank">Nefsis</a> : Application de vidéoconférences entourée d&#8217;une architecture distribuée pour le streaming et le codage adaptatif.</li>
<li><a href="http://www.mindjet.com/" target="_blank">Mindmanager</a> : Application de mind-mapping et de brainstorming. Je la connais depuis deux ans mais ce n&#8217;est que récemment que j&#8217;ai découvert que tout était basé sur C++.</li>
</ul>
<p>Ces deux applications implémentent <a href="http://msdn.microsoft.com/en-us/office/aa905530.aspx" target="_blank">Office Fluent UI</a> dans leurs interfaces. Vous pouvez les tester pour croire vos yeux !</p>
<p>Plusieurs éditeurs travaillent aujourd’hui sur l’implémentent de ce type d’interfaces pour les offrir sous formes de classes C++ (<a href="http://codejoke.com/" target="_blank">codejoke.com</a>, <a href="http://bcgsoft.com/" target="_blank">bcgsoft.com</a>, <a href="http://www.prof-uis.com/default.aspx" target="_blank">prof-uis.com</a>, etc.). D’autre part, une implémentation C++ en tant qu’extension à MFC a été aussi rendue publique par Microsoft.</p>
<p>Pour illustrer l’implémentation des FUI en C++, on reprendra des bouts de code de « <a href="http://www.iptechinside.com/labs/projects/show/easyprofiler" target="_blank">Easy Profiler</a> ». Easy Profiler est un profiler C/C++ composé d’un Collector et d’un Observer. Le collector est une bibliothèque de routines qui sert à générer un fichier XML que l’Observer permet d’illustrer d’une manière intuitive. Ces deux composants ainsi que leur documentation sont téléchargeables sur <a href="http://www.iptechinside.com/labs/" target="_blank">notre portail Labs</a>.</p>
<p>L’Observer est développé avec MFC 9.0 et fait appel aux nouvelles classes implémentant Office 2007 Fluent UI. L’application permet le changement de thème :</p>
<p><a href="http://www.iptechinside.com/labs/projects/show/easyprofiler">Easy Profiler, disponible sous l&#8217;espace LABS</a>, lui, est développé en utilisant MFC 9.0 et les nouvelles classes implémentant Office 2007 Fluent UI :</p>
<p>Ainsi l&#8217;application supporte le changement de thème :</p>
<p><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/image1.png" alt="Fluent Interfaces - C++" /></p>
<p>En utilisant le thème Office 2007 Blue Luna, l&#8217;effet est :</p>
<p><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/image2.png" alt="Fluent Interfaces - C++" /></p>
<p>Avec l&#8217;effet Aqua :</p>
<p><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/image3.png" alt="Fluent Interfaces - C++" /></p>
<p>Plus techniquement, cette fonctionnalité est pilotée par une instance dérivée de <em>CMFCVisualManager</em>. Ainsi, les classes visuelles de MFC délèguent la pluparty de leur code de dessin, à l&#8217;instance active en cours. L&#8217;appel à <em>CMFCVisualManager::SetDefaultManager</em> permet de sélectionner cette instance.</p>
<p>Le bouton-menu affiché dans l&#8217;image 1 est attaché à un menu avec des items dont les ID se trouvent dans l&#8217;intervalle <em>[ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA]</em>.</p>
<p>Un handler acceptant un UINT est déclaré dans le Message_MAP de la fenêtre principale dont le bouton-menu est un fils, pour gérer cette liste d&#8217;ID: <em>ON_COMMAND_RANGE(ID_VIEW_APPLOOK_WIN_2000, ID_VIEW_APPLOOK_OFF_2007_AQUA, &amp;CMainFrame::OnApplicationLook)</em>.</p>
<p>Dans le corps de la fonction <em>OnApplicationLook </em>on n&#8217;a qu&#8217;à sélectionner le VisulaManager en passant une instance dérivée de <em>CMFCVisualManager </em>:</p>
<pre name="code" class="cpp">void CMainFrame::OnApplicationLook(UINT id)
{
	CWaitCursor wait;  

	theApp.m_nAppLook = id;  

	switch (theApp.m_nAppLook)
	{
	case ID_VIEW_APPLOOK_WIN_2000:
		CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
		break;  

	case ID_VIEW_APPLOOK_OFF_XP:
		CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
		break;  

	case ID_VIEW_APPLOOK_WIN_XP:
		CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
		CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
		break;  

	case ID_VIEW_APPLOOK_OFF_2003:
		CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
		CDockingManager::SetDockingMode(DT_SMART);
		break;  

...</pre>
<p>Avant de retourner (<em>return </em>!), il est nécessaire de diffuser un message aux fenêtres filles pour mettre à jour leurs surfaces.</p>
<pre name="code" class="cpp">RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);</pre>
<p>Vous voyez que finalement, avec C++ on peut imaginer des interfaces moins sombres que celle sous l’invite de commandes et plus conviviales que celles développées avec les anciennes versions de MFC.</p>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/5IwVN1LV4Q4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/07/17/office-fluent-ui-en-c-natif/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/07/17/office-fluent-ui-en-c-natif/</feedburner:origLink></item>
		<item>
		<title>C++ et Poco peuvent sauver des bureaux! (1/2)</title>
		<link>http://feedproxy.google.com/~r/ip-tech-blog/~3/AtysdnCn4aA/</link>
		<comments>http://www.iptech-offshore.net/blog/2009/07/17/secourir-le-bureau-de-mahmoud-12/#comments</comments>
		<pubDate>Thu, 16 Jul 2009 22:17:29 +0000</pubDate>
		<dc:creator>Ahmed Charfeddine</dc:creator>
		
		<category><![CDATA[C++]]></category>

		<category><![CDATA[Technique]]></category>

		<category><![CDATA[DirectoryIterator]]></category>

		<category><![CDATA[icone Tray]]></category>

		<category><![CDATA[MFC]]></category>

		<category><![CDATA[Poco C++]]></category>

		<category><![CDATA[threading]]></category>

		<guid isPermaLink="false">http://www.iptech-offshore.net/blog/?p=58</guid>
		<description><![CDATA[Il m&#8217;est très difficile de voir des bureaux pleins d&#8217;icônes sans même pas un petit coin pour accueillir un nouveau raccourcis.
Devant l&#8217;insuffisance des outils proposés par les systèmes d&#8217;exploitation, en particulier celui proposé par Windows, je me suis dit qu&#8217;il serait intéressant d&#8217;en faire un! ça sera à la fois pour avoir des bureaux plus [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="float: left; margin-left: 10px; margin-right: 10px;" src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/crowded-desktop.png" alt="" />Il m&#8217;est très difficile de voir des bureaux pleins d&#8217;icônes sans même pas un petit coin pour accueillir un nouveau raccourcis.</p>
<p>Devant l&#8217;insuffisance des outils proposés par les systèmes d&#8217;exploitation, en particulier <a href="http://support.microsoft.com/kb/306542/fr" target="_blank">celui proposé par Windows</a>, je me suis dit qu&#8217;il serait intéressant d&#8217;en faire un! ça sera à la fois pour avoir des bureaux plus spacieux mais aussi pour introduire <a href="http://pocoproject.org/" target="_blank">Poco</a>, qui est une excellente bibliothèque C++.</p>
<p>A travers cet article et un autre qui le suivra, on proposera une approche qui n&#8217;exige aucun changement de comportement de la part des propriétaires de tels bureaux. On va cependant leurs offrir un outil qui automatisera l&#8217;opération de rangement selon leurs préférences prédéfinis.</p>
<p><span id="more-58"></span></p>
<p>On commencera par préparer un squelette applicativ <a href="http://en.wikipedia.org/wiki/Thread_%28computer_science%29" target="_blank">multithread</a> permettant d&#8217;interagir avec l&#8217;utilisateur via une icône de la <a href="http://en.wikipedia.org/wiki/Taskbar" target="_blank">Taskbar</a>. Dans le second article, je vous présenterai une bibliothèque intéressante, <a href="http://pocoproject.org/" target="_blank">Poco C++</a>, qui grâce à l&#8217;exploitation de certaines de ses routines, notamment la <a href="http://pocoproject.org/docs/Poco.DirectoryIterator.html" target="_blank">DirectoryIterator</a>, on va pouvoir implémenter les fonctionnalités qu&#8217;on désire mettre en place.</p>
<p><center><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/OrganizeMyFilesMainWindow.PNG" alt="Main window" /></center></p>
<p>Notre squelette sera dérivée de celle d&#8217;une application MFC native à base de boite dialogue :</p>
<p>Le point d&#8217;entrée <em>InitInstance</em> de l&#8217;objet <em>CWinApp</em> crée et initialise une boite dialogue dont les composants sont batis à l&#8217;aide du designer.</p>
<pre name="code" class="cpp">CMainDlg dlg;
m_pMainWnd = &amp;dlg;
INT_PTR nResponse = dlg.DoModal();
</pre>
<p>La fonction <em>DoModal</em> déclenche la fonction virtuelle <em>CDialog::OnInitDialog</em> avant de rentrer dans une boucle implicite d&#8217;appel à <em>::PeekMessage</em> et <em>AfxPumpMessage </em>(regarder le code de <em>RunModalLoop</em>). C&#8217;est notre thread principal qui permet d&#8217;interagir avec l&#8217;utilisateur.</p>
<p>Au niveau de <em>CDialog::OnInitDialog</em> nous avons la main pour initialiser le menu Tray à travers lequel l&#8217;utilisateur pourra interagir avec l&#8217;application:</p>
<pre name="code" class="cpp">m_nid.hWnd = GetSafeHwnd ();
m_nid.uCallbackMessage = UM_TRAYNOTIFY;

// Set tray icon and tooltip:
m_nid.hIcon = m_hIcon;

CString strToolTip = _T("Organize my files..");
_tcsncpy_s (m_nid.szTip, strToolTip, strToolTip.GetLength ());

Shell_NotifyIcon (NIM_ADD, &amp;m_nid);</pre>
<p>C&#8217;est grâce au message <em>UM_TRAYNOTIFY</em> que nous pouvons insérer un callback qui intercepte l&#8217;évènement de clique droit sur l&#8217;icône tray et affiche un menu contextuel :</p>
<pre name="code" class="cpp">LRESULT CMainDlg::OnTrayNotify( WPARAM wp, LPARAM lp )
{
	UINT uiMsg = (UINT) lp;

	switch (uiMsg)
	{
	case WM_RBUTTONUP:
		{
			CPoint point;
			::GetCursorPos (&amp;point);

			CMenu menu;
			menu.LoadMenu (IDR_MENU1);

			CMFCPopupMenu::SetForceShadow (TRUE);

			HMENU hMenu = menu.GetSubMenu (0)-&gt;Detach ();
			CMFCPopupMenu* pMenu = theApp.GetContextMenuManager()-&gt;ShowPopupMenu(hMenu, point.x, point.y, this, TRUE);

			pMenu-&gt;SetForegroundWindow ();
		}

		return 1;
	}</pre>
<p>Pour le menu <em>IDR_MENU1</em>, on a construit quatre boutons simples : un bouton <em>Start </em>permettant de démarrer/arrêter un thread silencieux exécutant sa tâche en arrière plan, un bouton <em>About</em>, <em>Configuration</em> et <em>Exit</em>. Chaque bouton est relié à une méthode de la boite de dialogue.</p>
<p><center><img src="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/MenuTray.PNG" alt="Menu Tray" /></center></p>
<p>Particulièrement, nous voulons que le texte du bouton <em>start</em> change en fonction de l&#8217;état du thread (démarré ou arrêter). De même, on ne doit pas permettre l&#8217;accès au bouton <em>configuration</em> quand le thread est en cours d&#8217;exécution. Cela est possible en insérant des handlers <em>ON_UPDATE_COMMAND_UI</em> à nos deux commandes et exploitant les méthodes <em>Enable</em> et <em>SetText</em> du paramètre <em>CCmdUI</em> en input.</p>
<p>Le bouton configuration permettra d&#8217;afficher la boite de dialogue qu&#8217;on s&#8217;efforcera de cacher initialement. Là, l&#8217;utilisateur pourra spécifier les paramètres du programme qui affecteront l&#8217;algorithme exécuté par le thread silencieux.</p>
<p>Dans cette première partie, on se contentera du fonctionnement suivant: L&#8217;application s&#8217;exécute et se place dans le taskbar. A chaque commande <em>start</em> (exécutée à partir du menu tray), on lance un thread qui à l&#8217;échéance d&#8217;un durée configurable émet un simple beep. La boite de dialogue permettra de saisir quelques paramètres comme la durée de la période du thread background. La sauvegarde de ces paramètres se fait dans la base de registre.</p>
<p>Une classe abstraite pure <em>CBackgroundThread </em>contiendra la logique de l&#8217;exécution de la tâche de fond :</p>
<pre name="code" class="cpp">void CBackgroundThread::start()
{
	m_hAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	ResetEvent(m_hAbortEvent);
	AfxBeginThread(threadProc, this);
}

void CBackgroundThread::stop()
{
	SetEvent(m_hAbortEvent);
}</pre>
<p>L&#8217;évènement <em>m_hAbortEvent</em> permet de demander au thread lancé de s&#8217;arrêter. Ce qui suit est l&#8217;algorithme exécuté par le thread d&#8217;arrière plan :</p>
<pre name="code" class="cpp">void CBackgroundThread::sleepAndExecute()
{
	m_bRunning=true;

	m_hSleepEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	ResetEvent(m_hSleepEvent);
	//
	HANDLE            hWaits[2];
	hWaits[0]        = m_hSleepEvent;
	hWaits[1]        = m_hAbortEvent;

	UINT    sleepTimeMs=theApp.GetInt(_T(&#8221;Sleep Duration&#8221;),3)*1000;

	//
	while(true)
	{
		MMRESULT result = timeSetEvent(sleepTimeMs, 1,
		(LPTIMECALLBACK) m_hSleepEvent, 0, TIME_ONESHOT|TIME_CALLBACK_EVENT_SET);
		if (result==NULL)
		break;

		if(WaitForMultipleObjects(2, hWaits, FALSE, INFINITE)==(WAIT_OBJECT_0 + 0))
		{
			//
			executePeriodicJob();
			ResetEvent(m_hSleepEvent);
		}
		else
		break;
	}
	//
	CloseHandle(m_hAbortEvent);
	CloseHandle(m_hSleepEvent);
	m_bRunning=false;
}</pre>
<p>Quand le thread d&#8217;interface intercepte la command <em>Stop</em>, si le thread d&#8217;arrière plan est bloqué sur <em>WaitForMultipleObject</em>, celui-ci retourne immédiatement en retournant l&#8217;offset 1 par rapport à la constante <em>WAIT_OBJECT_0</em> indiquant que l&#8217;objet <em>m_hAbortEvent</em> a été signalé, ce qui nous mène à faire un <em>break</em>. Si le thread de travail est en cours d&#8217;exécution de <em>executePeriodicJob</em> alors il s&#8217;apercevra du signal de terminaison à la prochaine boucle.</p>
<p>Pour notre première version, on a dérivé une classe qui surcharge <em>executePeriodicJob</em> pour exécuter un Beep avant de collecter les paramètres nécessaires, déjà saisis par l&#8217;utilisateur.</p>
<p>L&#8217;article suivant modifiera cette logique pour boucler sur les fichiers se trouvant dans le répertoire du bureau pour les transférer dans d&#8217;autres répertoires selon des règles prédéfinis.</p>
<p><strong>Téléchargements</strong></p>
<ul>
<li><strong>Codes sources :</strong> <a href="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/OrganizeMyFiles_SourcesC++MFC.zip">OrganizeMyFiles_SourcesC++MFC.zip</a></li>
</ul>
<p>Si vous préférez tester l&#8217;exemple sans avoir à compiler les sources, vous pouvez téléchearger l&#8217;exécutable Windows (.exe):</p>
<ul>
<li><strong>Executable :</strong> <a href="http://www.iptech-offshore.net/blog/wp-content/uploads/2009/07/OrganizeMyFilesEXE.zip">OrganizeMyFilesEXE.zip</a><br />
CheckSum de l&#8217;exécutable (à calculer après décompression du ZIP)</p>
<p style="padding-left: 30px;"><small> <strong>CRC32:</strong> 3E4CF456<br />
<strong>MD5:</strong> 3C26191224AC4667CBD69AF1344C072F<br />
<strong>SHA-1:</strong> 290220D84FBEBEEBE33E9CA7395B2199997E387F</small></p>
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/ip-tech-blog/~4/AtysdnCn4aA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.iptech-offshore.net/blog/2009/07/17/secourir-le-bureau-de-mahmoud-12/feed/</wfw:commentRss>
		<feedburner:origLink>http://www.iptech-offshore.net/blog/2009/07/17/secourir-le-bureau-de-mahmoud-12/</feedburner:origLink></item>
	</channel>
</rss>
