Timer Job

Partie 4 : SPAllSitesJobDefinition

03/04/2011 1 154 lectures Xavier  Vanneste Sébastien Sougnez

La structure interne ainsi que le design d'AreaProg ont récemment été modifiés.
Suite à cela, le format de certains articles a été perturbé. Le problème est connu et en cours de résolution. Merci de votre compréhension.

Introduction


Cet article conclut l'ensemble des parties concernant la création de « Timer Job » dans SharePoint 2010. Cette partie montre un cas concret qui fait suite à une série d'article et une présentation de « Fabrice Romelard » concernant l'optimisation de site intranet. Dans une de ces présentation au club SharePoint France, Fabrice a expliqué que les « content manager » uploadent des photos prisent avec leur « reflex style canon » ou « nikon » sans les retravailler. Or, tout le monde sait qu'une photo faite avec ce genre d'appareil est juste impossible à mettre sur le web en raison de sa haute résolution prévue pour de l'impression papier haute définition. Le but du « timer job » est donc de créer une automatisation qui va scruter toutes les bibliothèques de documents à la recherche d'image de haute définition et les redimensionner.
 

Job Definition


Comme dans les autres parties on va hériter d'une classe enfant de « SPJobDefinition ». Cette classe, idéalement, devrait nous permettre de « crawler » un site à la recherche d'image. Pour cela « SPAllSitesJobDefinition » recherche toutes les « sites collection » d'une « web application » et expose la méthode « ProcessSite » qui est appelée à chaque fois qu'une « site collection » est trouvée. On en profite aussi pour appeler le constructeur qui prend en paramètre la « webapplication » sans quoi il y aurait une « null reference exception ».
 

public class OptimzedImage : SPAllSitesJobDefinition
{

    StringCollection strCol = new StringCollection();

    public OptimzedImage()
        : base()
    {
        FillExtCol();
    }

    private void FillExtCol()
    {

        strCol.Add(".jpg");
        strCol.Add(".jpeg");
        strCol.Add(".png");
        strCol.Add(".bmp");
        strCol.Add(".gif");

    }

    public OptimzedImage(SPWebApplication app)
        : base(jobName, app)
    {
        FillExtCol();
    }

    public override void ProcessSite(Microsoft.SharePoint.SPSite site, SPJobState jobState)
    {

        SPWebCollection colWeb = site.AllWebs;

        foreach (SPWeb web in colWeb)
        {
            ProcessWeb(web, jobState);
        }

    }

}


Seule la méthode « ProcessSite » de « SPAllSitesDefinition » sera utilisée, la méthode « Execute » (comme avec les « work items ») s'occupe d'ouvrir la base de données, de rechercher toutes les sites collections et de la progression du job. Ainsi on est tranquille pour se concentrer sur le code. Ici, il est simple. Sur chaque site collection, on inspecte les sites, puis les listes et enfin les « items ». Si ceux-ci sont des images, alors on redimensionne si nécessaire. Voici le code au complet :
 

public class OptimzedImage : SPAllSitesJobDefinition
{

    StringCollection strCol = new StringCollection();

    public OptimzedImage()
        : base()
    {
        FillExtCol();
    }

    private void FillExtCol()
    {

        strCol.Add(".jpg");
        strCol.Add(".jpeg");
        strCol.Add(".png");
        strCol.Add(".bmp");
        strCol.Add(".gif");

    }

    public OptimzedImage(SPWebApplication app)
        : base(jobName, app)
    {
        FillExtCol();
    }

    public override void ProcessSite(Microsoft.SharePoint.SPSite site, SPJobState jobState)
    {

        SPWebCollection colWeb = site.AllWebs;

        foreach (SPWeb web in colWeb)
        {
            ProcessWeb(web, jobState);
        }

    }

    private void ProcessWeb(SPWeb web, SPJobState jobState)
    {

        SPListCollection list = web.Lists;

        foreach (SPList lst in list)
        {
            if (lst is SPDocumentLibrary)
            {
                ProcessDocumentLibrary(lst, jobState);
            }
        }

    }

    private void ProcessDocumentLibrary(SPList lst, SPJobState jobState)
    {

        SPListItemCollection itemCol = lst.Items;

        for (int miind = 0; miind < itemCol.Count; miind++)
        {

            SPListItem item = itemCol[miind];

            if (item.File == null || item.File.CheckOutType != SPFile.SPCheckOutType.None)
                continue;

            FileInfo fi = new FileInfo(item.Url);

            if (strCol.Contains(fi.Extension.ToLower()))
            {
                ProcessFile(item, jobState);
            }

        }

    }

    private void ProcessFile(SPListItem item, SPJobState jobState)
    {

        Image img = Image.FromStream(item.File.OpenBinaryStream());
        FileInfo fi = new FileInfo(item.Url);
        ImageFormat imgFormat;

        SetRawFormat(fi.Extension, out imgFormat);

        if (imgFormat == null)
            return;

        Image imgOut = null;

        if (img.Width > 1024 || img.Height > 800)
        {

            if (item.File.RequiresCheckout)
                item.File.CheckOut();

            MemoryStream strmImage = new MemoryStream();

            ResizeImage(img, out imgOut, 1024, 800, true);

            imgOut.Save(strmImage, imgFormat);

            item.File.SaveBinary(strmImage);
            item.File.Update();

            if (item.File.RequiresCheckout)
                item.File.CheckIn("");

        }

    }

    private void SetRawFormat(string Extension, out ImageFormat imgFormat)
    {

        switch (Extension.ToLower())
        {

            case ".jpg":
            case ".jpeg":

                imgFormat = ImageFormat.Jpeg;

                break;

            case ".png":

                imgFormat = ImageFormat.Png;

                break;

            case ".gif":

                imgFormat = ImageFormat.Gif;

                break;

            case ".bmp":

                imgFormat = ImageFormat.Bmp;

                break;

            default:

                imgFormat = null;

                break;

        }

    }

    public void ResizeImage(Image OriginalFile, out Image NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
    {

        // Prevent using images internal thumbnail

        OriginalFile.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
        OriginalFile.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

        if (OnlyResizeIfWider)
        {
            if (OriginalFile.Width <= NewWidth)
            {
                NewWidth = OriginalFile.Width;
            }
        }

        int NewHeight = OriginalFile.Height * NewWidth / OriginalFile.Width;

        if (NewHeight > MaxHeight)
        {

            // Resize with height instead

            NewWidth = OriginalFile.Width * MaxHeight / OriginalFile.Height;
            NewHeight = MaxHeight;

        }

        NewFile = OriginalFile.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);

        // Clear handle to original file so that we can overwrite it if necessary

        OriginalFile.Dispose();

    }



    public static string jobName
    {
        get
        {
            return "OptimzedImage";
        }
    }

}


Attention ce code est à but de démonstration, pas pour de la production. Une fois fait, il suffit de faire la « Feature » avec le « Scheduler » comme dans les autres parties et voilà le résultat après une première exécution.
 

Image


Comme on peut le voir, les images font 800 de haut maximum et 1024 de large, l'image a été changée par « System Account » qui est le compte de SharePoint utilisé par le « timer job ».
 

Conclusion


L'écriture d'un « timer job » n'est pas juste l'implémentation de la classe « SPJobDefinition » en surchargeant « Execute ». Il y a plein de classes enfants qui sont très utiles, voir plus utiles, suivant le contexte de développement de notre « timer job ». La première chose à faire est donc d'étudier la bonne classe qui fera une grosse partie du travail et ne pas se concentrer sur la mécanique interne mais juste sur ce qu'on veut faire.

Télécharger les sources de l'exemple

Noter

Veuillez vous identifier ou vous inscrire pour donner une note à cet article.

Commentaires / Questions

Aucun commentaire.

Veuillez vous identifier ou vous inscrire pour réagir à cet article.

Avatar

Xavier  Vanneste

Envoyer un mail Site web Windows live messenger LinkedIn Twitter Facebook MVP Rédacteur

250 points

Avatar

Sébastien Sougnez

Envoyer un mail Site web Windows live messenger LinkedIn Twitter Facebook MVP Administrateur

25754 points