Cilia/Workshop/TP5/Application Pervasive

From Wiki Adele Team
< Cilia‎ | Workshop‎ | TP5
Jump to: navigation, search

Objectif du TP

L’objectif de ce TP est de présenter une application de remontée de données récoltées par des dispositifs RFID. Dans cette application, la plupart de composants sont spécifiques au projet, à l'exception des schedulers et dispatchers.

Description de l'application

L’application produit de façon périodique un ou plusieurs rapports (documents généralement en XML) qui contiennent les étiquettes qui ont été lues par un ensemble de lecteurs (des dispositifs RFID). Chaque cycle de production des rapports est connu comme Event Cycle (EC). Les étiquettes lues par les lecteurs pendant un EC doivent être traitées avant de produire les rapports. Le traitement consiste en :

  • Agrégation des étiquettes lues par les différents lecteurs.
  • Élimination de doublons (par exemple la même étiquette a été lue par deux lecteurs différents pendant le même EC)
  • Calcul de l’ensemble à inclure dans le rapport. Il existe trois types de calcul, le CURRENT_SET qui ajoute les étiquettes lues par un EC. L’ADDITION_SET qui ajoute au rapport les nouvelles étiquettes par rapport à la lecture du EC précédant. Finalement, le DELETION_SET qui correspond aux étiquettes qui ont « disparu » par rapport à la lecture du EC précédant.
  • Filtrage des étiquettes. On peut spécifier des filtres par rapport aux étiquettes à ajouter dans le rapport.
  • Génération du document qui normalement se fait dans un format XML. Cependant, des applications clientes peuvent choisir des autres formats de codage pour le rapport.
  • Envoi des documents aux clients intéressés

Spécification de la chaîne

Aspire-cilia.png

Download.png Le projet complet de ce TP (y compris la passerelle) TP5b-project


Composants spécifiques au projet

LogicalReader

Code du Processor

public class LogicalReader implements IProcessor {

   /**
    * A reader adaptor OSGi service
    */
   private ReaderAdaptor adaptor;

   /*
    * (non-Javadoc)
    * 
    * @see fr.liglab.adele.cilia.framework.IProcessor#process(java.util.List)
    */
   public List process(List dataSet) {
      final List<Data> temp = new ArrayList<Data>(1);

      if (adaptor != null) {
         List<Tag> list = adaptor.getTags();
         Data data = new Data(list);
         temp.add(data);
      } else {
         temp.add(new Data(new ArrayList<Tag>(0)));
      }
      return temp;
   }

}

Type du composant (iPOJO)

   <component name="aspire-logical-reader" classname="liglab.adele.aspire.reader.LogicalReader"
      immediate="true" architecture="true">
      <requires field="adaptor" id="reader-id"/>
      <cilia:periodic-scheduler />
      <cilia:multicast-dispatcher />
   </component>

EventCycle

Code du Processor

public class EventCycle implements IProcessor {

   /**
    * The current event cycle consecutive
    */
   private Integer round = Integer.valueOf(1);

   /*
    * (non-Javadoc)
    * 
    * @see fr.liglab.adele.cilia.framework.IProcessor#process(java.util.List)
    */
   public final List<Data> process(List dataSet) {
      int localRound = 0;
      synchronized (round) {
         localRound = round;
         round++;
      }

      final Data data = new Data(aggregate(dataSet));
      data.setProperty("round", localRound);
      final List<Data> temp = new ArrayList<Data>(1);
      temp.add(data);
      return temp;
   }

   /**
    * Merge tags lits comming from different readers
    * 
    * @param list the set of tags list
    * @return a new list containing all tags
    */
   public List<Tag> aggregate(List<Data> list) {
      List<Tag> temp = new ArrayList<Tag>();
      for (Data data : list) {
         List<Tag> subList = (List<Tag>) data.getContent();
         temp.addAll(subList);
      }
      return temp;
   }

Type du composant (iPOJO)
   <component name="aspire-event-cycle" classname="liglab.adele.aspire.ec.EventCycle"
      immediate="true" architecture="true">
      <cilia:periodic-scheduler />
      <cilia:multicast-dispatcher />
   </component>

Duplicate

Code du Processor

public class Duplicate implements IProcessor {

   /*
    * (non-Javadoc)
    * 
    * @see fr.liglab.adele.cilia.framework.IProcessor#process(java.util.List)
    */
   public List<Data> process(final List dataSet) {
      assert dataSet != null;
      List<Data> temp = new ArrayList<Data>(1);
      Data data = (Data) dataSet.get(0);
      if (data != null) {
         List<Tag> original = (List<Tag>) data.getContent();
         List<Tag> newList = applyFilter(original);
         Data newData = new Data(newList);
         newData.setProperty("round", data.getProperty("round"));
         temp.add(newData);
      } else {
         temp.add(new Data(new ArrayList<Tag>(0)));
      }
      return temp;
   }

   /**
    * Internal method eliminating the duplicates by creating a new list.
    * 
    * @param original The original list
    * @return The new list without duplicates
    */
   protected List<Tag> applyFilter(final List<Tag> original) {
      List<Tag> temp = new ArrayList<Tag>(original.size());

      for (Tag tag : original) {
         if (!temp.contains(tag)) {
            temp.add(tag);
         }
      }
      return temp;
   }
}

Type du composant (iPOJO)

   <component name="aspire-duplicate" classname="liglab.adele.aspire.duplicate.Duplicate"
      immediate="true" architecture="true">
      <cilia:immediate-scheduler />
      <cilia:multicast-dispatcher />
   </component>


Filter

Code du Processor

public class Filter implements IProcessor {

   /**
    * The include filter list
    */
   private List<String> includeList;

   /**
    * The exclude filter list
    */
   private List<String> excludeList;

   /**
    * iPOJO callback to get the includeList configuration parameter
    * @param tokenizedList
    */
   public void setIncludeList(String tokenizedList) {
      String[] temp = tokenizedList.split(",");
      includeList = Arrays.asList(temp);
   }

   /**
    * iPOJO callback to get the excludeList configuration parameter
    * @param tokenizedList
    */
   public void setExcludeList(String tokenizedList) {
      String[] temp = tokenizedList.split(",");
      excludeList = Arrays.asList(temp);
   }


   /*
    * (non-Javadoc) 
    * @see fr.liglab.adele.cilia.framework.IProcessor#process(java.util.List)
    */
   public final List<Data> process(final List dataSet) {

      final List<Data> temp = new ArrayList<Data>(1);
      final Data data = (Data) dataSet.get(0);
      if (data != null) {
         final List<Tag> original = (List<Tag>) data.getContent();
         Data newData = new Data(applyFilter(original));
         newData.setProperty("round", data.getProperty("round"));
         temp.add(newData);
      } else {
         temp.add(new Data(new ArrayList<Tag>(0)));
      }
      return temp;
   }
   
   /**
    * Applicate the two filters.
    * 
    * @param includes The inclusion filter
    * @param excludes The exclusion filter
    * @param original The original list
    * 
    * @return The final list
    */
   private List<Tag> applyFilter(final List<Tag> original) {
      List<Tag> temp = new ArrayList<Tag>(original);
      if (includeList != null) {
         temp = applyIncludes(temp);
      }
      if (excludeList != null) {
         temp = applyExcludes(temp);
      }
      return temp;
   }

   /**
    * it applies the inclusion filter.
    * 
    * @param original The original list
    * @return The new filtered list with includes
    */
   private List<Tag> applyIncludes(final Collection<Tag> original) {
      final List<Tag> temp = new ArrayList<Tag>(original.size());
      for (final String patternStr : includeList) {
         Pattern pattern = Pattern.compile(patternStr);
         for (final Tag tag : original) {
            Matcher matcher = pattern.matcher(tag.getId());
            if (matcher.matches()) {
               temp.add(tag);
            }
         }
      }
      return temp;
   }

   /**
    * It applies the exclusion filter.
    * 
    * @param original The original list
    * @return The new filtered list without excludes
    */
   private List<Tag> applyExcludes(final List<Tag> original) {
      List<Tag> temp = new ArrayList<Tag>(original.size());
      temp.addAll(original);
      for (final String patternStr : excludeList) {
         Pattern pattern = Pattern.compile(patternStr);
         for (final Tag tag : original) {
            Matcher matcher = pattern.matcher(tag.getId());
            if (matcher.matches()) {
               temp.remove(tag);
            }
         }
      }
      return temp;
   }

}

Type du composant (iPOJO)

   <component name="aspire-filter" classname="liglab.adele.aspire.filter.Filter"
      immediate="true" architecture="true">
      <properties>
         <property name="includeList" method="setIncludeList" />
         <property name="excludeList" method="setExcludeList" />
      </properties>
      <cilia:immediate-scheduler />
      <cilia:multicast-dispatcher />
   </component>

XMLGenerator

Code du Processor

public class XMLGenerator implements IProcessor {

   /*
    * (non-Javadoc)
    * 
    * @see fr.liglab.adele.cilia.framework.IProcessor#process(java.util.List)
    */
   public List<Data> process(final List dataSet) {

      final Data data = (Data) dataSet.get(0);
      final List<Data> temp = new ArrayList<Data>(1);
      if (data != null) {
         final List<Tag> original = (List<Tag>) data.getContent();
         final int round = (Integer) data.getProperty("round");
         String report = generateReport(original, round);
         temp.add(new Data(report));
      } else {
         temp.add(new Data(""));
      }
      return temp;
   }

   /**
    * Generate a XML report.
    * 
    * 
    * @param tags The list of tags
    * @param round The current round
    * @return The report in XML (String)
    */
   private static String generateReport(final Collection<Tag> tags, final int round) {
      final StringBuilder buf = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tag-list round=\""
            + round + "\">\n");
      buf.append("\t<count>").append(tags.size()).append("</count>\n");
      for (final Tag tag : tags) {
         buf.append("\t<tag>").append(tag.getId()).append("</tag>\n");

      }
      return buf.append("</tag-list>\n").toString();
   }

}

Type du composant (iPOJO)

   <component name="aspire-xml-generator" classname="liglab.adele.aspire.generator.XMLGenerator"
      immediate="true" architecture="true">
      <cilia:immediate-scheduler />
      <cilia:multicast-dispatcher>
      </cilia:multicast-dispatcher>
   </component>

Description de la chaîne de médiation

Contenu du fichier AspireChain.dscilia décrivant les instances de médiateur et les liaison entre elles.

<cilia>

   <chain id="AspireDemoChain" type="AspireChain">

      <mediators>

         <mediator-instance type="aspire-logical-reader" id="logical-reader-1">
            <scheduler>
               <property name="period" value="2000" />
            </scheduler>
            <property name="requires.from">
               <item key="reader-id" value="simulator-reader-1" />
            </property>
         </mediator-instance>

         <mediator-instance type="aspire-logical-reader" id="logical-reader-2">
            <scheduler>
               <property name="delay" value="1000" />
               <property name="period" value="2000" />
            </scheduler>
            <property name="requires.from">
               <item key="reader-id" value="simulator-reader-1" />
            </property>
         </mediator-instance>

         <mediator-instance type="aspire-event-cycle" id="event-cycle">
            <scheduler>
               <property name="delay" value="500" />
               <property name="period" value="5000" />
            </scheduler>
         </mediator-instance>

         <mediator-instance type="aspire-duplicate" id="duplicate">

         </mediator-instance>

         <mediator-instance type="aspire-filter" id="filter">
            <property name="includeList" value="urn:epc:pat:gid-96:145.56.*" />
         </mediator-instance>

         <mediator-instance type="aspire-xml-generator" id="xml-generator">
            <scheduler>
               <property name="correlation" value="($round)" />
            </scheduler>
         </mediator-instance>

         <mediator-instance type="aspire-notifier" id="notifier">
         </mediator-instance>

      </mediators>


      <bindings>

         <binding from="logical-reader-1:end" to="event-cycle:begin1" />
         <binding from="logical-reader-2:end" to="event-cycle:begin2" />
         <binding from="event-cycle:end" to="duplicate:begin" />
         <binding from="duplicate:end" to="filter:begin" />
         <binding from="filter:end" to="xml-generator:begin" />
         <binding from="xml-generator:end" to="notifier:begin" />

      </bindings>

   </chain>

</cilia>