Archives mensuelles : novembre 2010

Installer Java sur un NAS Synology DS210+

UPDATE: 25/09/2011 – Corrections des paths

WARNING: On the right side, you can translate this article with « Google Translate »,
BE CAREFUL, Google modify paths and names. For good scripts, thank you for using the French original.

But:

Installer Java sur un NAS Synology DS210+ et équivalent avec processeur PowerPC SPE également connu sous le nom de « e500″/ »MPC8500 » et « e200″/ »MPC5xx ».

Problèmes:

  • Synology ne fourni pas de package java compatible ou fonctionnel.
  • Toucher le moins possible à la configuration du nas.

Solution possible:

Trouver une distribution linux compatible PowerPC SPE avec par exemple OpenJDK et l’installer en chroot sur le nas.

Prérequis:

  • Un NAS à base de PowerPC SPE
  • une connexion ssh configurer vers le NAS.

Version rapide:

Télécharger l’ archive du répertoire préconfiguré avec OpenJdk d’une distribution linux Debian pour architecture PowerPC SPE:

[download id= »1″]

ou

[download id= »2″]

Décompresser cette archive sur votre nas sous le répertoire /volume1/@local/debian et créer les points de montages correspondant:

NAS> mkdir -p /volume1/@debian
NAS> cp chrootgnuspe_OpenJDKPublic.tgz /volume1/@debian
NAS> cd /volume1/@local/debian
NAS> tar xzvf chrootgnuspe_OpenJDKPublic.tgz
NAS> mkdir -p /opt/debian

vous devez donc avoir /volume1/@debian/chrootgnuspe/bin, /volume1/@debian/chrootgnuspe/boot, …etc.
le ‘@’ évite que ce répertoire soit visible dans des partages réseaux.

il ne nous reste plus qu’à monter ce répertoire en chroot…

Pour nous simplifier la tâche, 2 scripts.
initDebChroot.sh sert à initialiser cette nouvelle installation au démarrage.

#!/bin/ash
mount -o bind /volume1/@debian /opt/debian
mount -o bind /dev /opt/debian/chrootgnuspe/dev
mount -o bind /proc /opt/debian/chrootgnuspe/proc
chroot /opt/debian/chrootgnuspe /bin/bash

loadDebChroot.sh permettant de se reconnecter en chroot, on aurait pu faire un alias, mais un des buts est de ne pas modifier le nas.

#!/bin/ash

chroot /opt/debian/chrootgnuspe /bin/bash

Nous allons maintenant tester notre plateforme.

Commençons par monter tout le nécessaire et changer de répertoire racine (chroot):

Nas>./initDebChroot.sh

Nous voici dans notre environnement debian.
Dans l’archive précédemment téléchargée se trouve un hello world en java, testons-le.

#cd /root
~# ll
total 12
-rw-r--r-- 1 root root  421 Nov 11 22:13 FirstApp.class
-rw-r--r-- 1 root root  109 Oct 19 22:06 FirstApp.java
~# javac FirstApp.java
~# java FirstApp
Hello World
~#

Voilà, vous avez un kit de développement java fonctionnel sur votre nas !!

Etant basé sur une distribution debian, vous pouvez utiliser toutes les commandes de gestion de paquet, apt-*. Vous pourrez ainsi en faire un serveur web avec jetty, tomcat, installez svn, git, un serveur dns, et que sais-je.

Amusez-vous bien.

Remerciements:
Rien n’aurait été possible sans le travail de Sebastian Andrzej Siewior pour son portage vers PowerPC SPE et de ces posts sur http://lists.debian.org/debian-powerpc/2009/02/msg00128.html . Il m’a permis de bénéficier d’une distribution complète sur ce nas et d’en faire une plateforme de dev utilisable.

Références:
http://wiki.debian.org/PowerPCSPEPort

A venir, une version plus détaillée de ce tutorial expliquant comment générer soit-même ce répertoire.

SortableCollectionView avec ICollectionView

But:

  • Avec pour source une liste d’objet de type T, obtenir une vue de cette liste pouvant être triée dynamiquement suivant les propriétés du type T.
  • Chaque modification de la source ou d’une propriété d’un élément de la source doit être reflétée dans la vue.
  • Pouvoir lier (par binding) cette vue à une DataGrid sans que celle-ci l’en-capsule dans sa propre implémentation de ICollectionView.

Problème:
ObservableCollection ne gère pas les updates des propriétés des éléments.

Solution:
Implémenter sa propre vue ICollectionView 🙂
Nous allons nous limiter au sort et laisser le filtre pour une prochaine fois.

Commençons par créer une classe nommée SortableCollectionView :

    public class SortableCollectionView<T> :
        ICollectionView,
        IEnumerable<T>,
        INotifyPropertyChanged
        where T : class, INotifyPropertyChanged
    {
    }

Nous autorisons seulement le filtre donc CanSort = true et CanFilter = false.

Nous avons besoins de stocker notre liste triée donc ajoutons une ObservableCollection qui nous d’avoir une ICollectionChanged rapidement.
private ObservableCollection _sortedCollection = new ObservableCollection();

La source de donnée sera accessible par :

        public IEnumerable SourceCollection
        {
            get { return _sourceCollection; }
            set
            {
                ChangeDataSource(value as IEnumerable<T>);
            }
        }

ChangeDataSource initialise la vue en fonction des capacités de la source. Suivant les interfaces implémentées, nous allons pouvoir plus ou moins bien refléter les changement de la source sur la vue.

      private void ChangeDataSource(IEnumerable<T> src)
        {
            lock (_refreshObjectSync)
            {
                _isInitializing = true;
                if (null == src)
                {
                    src = new List<T>();
                }

                // supprime les liens vers les anciens éléments
                foreach (var item in _sortedCollection)
                {
                    item.PropertyChanged -= OnItemPropertyChanged;
                }

                INotifyCollectionChanged collectionChanged = _sourceCollection as INotifyCollectionChanged;
                if (collectionChanged != null)
                {
                    collectionChanged.CollectionChanged -= OnDataSourceCollectionChanged;
                }

                _sourceCollection = src;

                // Copie de la source vers vue (_sortedCollection)
                BuildLocalCollection();
                collectionChanged = _sourceCollection as INotifyCollectionChanged;
                if (collectionChanged != null)
                {
                    collectionChanged.CollectionChanged += OnDataSourceCollectionChanged;
                }
                _isInitializing = false;
                ApplySort();
                SetCurrentToPosition(this.CurrentPosition);
            }
        }

Chaque modification d’une propriété sur laquelle est appliquée un tri doit regénérer la vue triée et modifier la position de l’élément courant sélectionné.

        private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            T item = (T)sender;
            if (_sortDescriptions.Count > 0)
            {
                if (IsAffectingSorting(e.PropertyName))
                {
                    lock (_refreshObjectSync)
                    {
                        Sort();
                        UpdateCurrentItemPosition(item);
                    }
                }
            }
        }

Le tri se fait par l’appel à la méthode Sort(), pour cette version nous n’avons pas besoins de beaucoup de performance donc nous pouvons utiliser Linq et son OrderBy.
Par contre OrderBy nécessite soit une fonction avec un tri prédéfini soit un comparateur. Nous voulons trier de manière générique avec Linq, il nous faut donc un comparateur … générique.

Pour le comparateur nous allons utiliser le code de la classe FilteredSortComparer issu du projet « Autofiltering Support for Silverlight DataGrid » sur codeproject
http://www.codeproject.com/KB/silverlight/autofiltering_silverlight.aspx?msg=3654291

avec quelque chose comme cela:

        private IComparer<T> _comparer;
        ...
        private void OnSortDescriptionCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {
                //   return;
            }
            if (_sortDescriptions.Count > 0)
            {
                _comparer = new FilteredSortComparer<T>(_sortDescriptions);
            }
            else
            {
                _comparer = null;
            }
        }

Si il n’y a rien à trier arrêtons nous.

        private void Sort()
        {
            if (_isInitializing) return;
            if (_comparer == null) return;
            if (_sortedCollection.Count < 2) return;
            var sortedItemsList = _sortedCollection.OrderBy(x => x, _comparer).ToList();
            _sortedCollection.Clear();
            _sortedCollection.AddRange(sortedItemsList);
        }

Vous avez maintenant les clefs pour faire une version fonctionnelle de ICollectionView implémentant le sort, le reste du code étant simple.

Comment l’utiliser?

 private ICollectionView _collectionView;
 ...
 _collectionView = new SortableCollectionView<YourObject>() {SourceCollection = src};
 gridControl.ItemsSource = _collectionView;

le sort est rempli automatiquement par la grille.

Pourquoi ne pas utiliser la classe FilteredCollectionView du projet Stepi « Autofiltering Support for Silverlight DataGrid » ?
Malgré les avantages de cette lib, plusieurs points m’ont fait écrire cette SortableCollectionView:
_un besoins limité au sort
_pas envie d’inclure X fichiers + une lib de collection « juste » pour ça
_le plus important, cette FilteredCollectionView est instable et n’est pas thread safe.
_pas de test unitaire

Dans un futur article, nous verrons comment améliorer cette ébauche de vue, pour être thread safe, et éviter de retrier à chaque modification.

N’hésitez pas à poser vos questions, vos remarques.