KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > SOFA > SOFAnet > Repository > Contract


1 /*
2  * Contract.java
3  *
4  * Created on 3. prosinec 2003, 17:19
5  */

6
7 package SOFA.SOFAnet.Repository;
8
9 import java.io.*;
10 import java.util.*;
11 import java.text.*;
12 import SOFA.Util.XML;
13 import org.w3c.dom.*;
14 import org.xml.sax.SAXException JavaDoc;
15
16 /**
17  * Representation of the contract.
18  * One item of persistent storage.
19  * <p>
20  * The contract contains:
21  * <ul>
22  * <li>ID of the contract (randomly generated string)
23  * <li>text description of the contract
24  * <li>time validity of contract
25  * <li>default specifications of thing that needn't be that repeated in every contract rule:
26  * <ul>
27  * <li>filter of "pushing" nodes (contract is taken only if the bundle arrives from such node)
28  * <li>destination nodes (and number of licences) for push operations
29  * <li>filter of nodes that can pull
30  * <li>licence text
31  * </ul>
32  * <li>list of contract rules (see ContractRule)
33  * </ul>
34  * <p>
35  * Contracts creates licences (licence files).
36  * "Push/Pull" actions of contracts are realized by input and output triggers connected with the contract.
37  * These triggers are generated from contract (manually).
38  *
39  * @author Ladislav Sobr
40  */

41 public class Contract extends XMLStorageItem implements StorageItem, Serializable
42 {
43   private String JavaDoc contractID;
44   private String JavaDoc description;
45   private Date validFrom; //can be null
46
private Date validTo; //can be null
47
private boolean autoDelete;
48   private NodeNameLicList defaultPushDestinationNodes;
49   private NodeNameFilter defaultPushNodeFilter;
50   private NodeNameFilter defaultPullNodeFilter;
51   private String JavaDoc defaultLicenceText;
52   private Map rules;
53   
54   /** Creates a new instance of Contract */
55   public Contract(String JavaDoc name, File file)
56   {
57     super(name, file, "contract");
58     reset();
59   }
60   
61   public Contract()
62   {
63     super("", null, "contract");
64     reset();
65   }
66   
67   /**
68    * Resets content of the item.
69    */

70   protected void reset()
71   {
72     contractID = "";
73     description = "";
74     validFrom = null;
75     validTo = null;
76     autoDelete = false;
77     defaultPushDestinationNodes = null;
78     defaultPushNodeFilter = null;
79     defaultPullNodeFilter = null;
80     defaultLicenceText = "";
81     rules = Collections.synchronizedMap(new HashMap());
82   }
83   
84   public boolean toBeDeleted()
85   {
86     Iterator it = rules.values().iterator();
87     while (it.hasNext())
88     {
89       ContractRule rule = (ContractRule)it.next();
90       if (rule.toBeDeleted()) it.remove();
91     }
92     
93     return autoDelete && (
94        validTo != null && validTo.before(Calendar.getInstance().getTime()) ||
95        rules.isEmpty());
96   }
97   
98   /**
99    * Loads the item from the XML DOM tree.
100    * <p>
101    * XML format of storage item:
102    * <p>
103    * <pre>
104    * &lt;contract&gt;
105    * Contract XML format
106    * &lt;/contract&gt;
107    * </pre>
108    * <p>
109    * WARNING!!! Name of storage item must be identical to "id" (contractID)!!!
110    * <p>
111    * XML format:
112    * <p>
113    * <pre>
114    * &lt;id&gt;string&lt;/id&gt;
115    * ?&lt;descripton&gt;string&lt;/description&gt;
116    * ?&lt;validity ?from="date" ?to="date" ?autodelete="boolean"/&gt;
117    *
118    * ?&lt;defaults&gt;
119    * ?&lt;push_node_filter&gt;
120    * NodeNameFilter XML format
121    * &lt;/push_node_filter&gt;
122    * ?&lt;push_destination_nodes&gt;
123    * NodeNameLicList XML format (presence of "number_of_licences" overrides "number_of_copies" in licence of rule)
124    * &lt;/push_destination_nodes&gt;
125    * ?&lt;pull_node_filter&gt;
126    * NodeNameFilter XML format
127    * &lt;/pull_node_filter&gt;
128    * ?&lt;licence_text&gt;string&lt;/licence_text&gt;
129    * &lt;/defaults&gt;
130    *
131    * &lt;rules&gt;
132    * *&lt;rule name="string"&gt;
133    * ContractRule XML format
134    * &lt;/rule&gt;
135    * &lt;/rules&gt;
136    * </pre>
137    *
138    */

139   public void loadFromXML(Element element) throws SAXException JavaDoc
140   {
141     reset();
142     NodeList nl = element.getChildNodes();
143     for (int i = 0; i < nl.getLength(); i++)
144     {
145       Node node = nl.item(i);
146       if (node.getNodeType() == Node.ELEMENT_NODE)
147       {
148         Element el = (Element)node;
149         String JavaDoc nodeName = node.getNodeName();
150         
151         if (nodeName.compareTo("id") == 0)
152         {
153           contractID = XML.getTextContent(el);
154         }
155         else
156         if (nodeName.compareTo("description") == 0)
157         {
158           description = XML.getTextContent(el);
159         }
160         else
161         if (nodeName.compareTo("validity") == 0)
162         {
163           String JavaDoc from = el.getAttribute("from");
164           String JavaDoc to = el.getAttribute("to");
165           String JavaDoc ad = el.getAttribute("autodelete");
166           DateFormat dateFormat = DateFormat.getInstance();
167           if (from.length() > 0)
168           {
169             try
170             {
171               validFrom = dateFormat.parse(from);
172             }
173             catch (ParseException e)
174             {
175               throw new SAXException JavaDoc("Cannot parse date/time format of 'from' attribute of 'validity' tag", e);
176             }
177           }
178           
179           if (to.length() > 0)
180           {
181             try
182             {
183               validTo = dateFormat.parse(to);
184             }
185             catch (ParseException e)
186             {
187               throw new SAXException JavaDoc("Cannot parse date/time format of 'to' attribute of 'validity' tag", e);
188             }
189           }
190
191           if (ad.length() > 0)
192           {
193             ad = ad.trim().toLowerCase();
194             if (ad.compareTo("1") == 0 || ad.compareTo("true") == 0) autoDelete = true;
195           }
196         }
197         else
198         if (nodeName.compareTo("defaults") == 0)
199         {
200           NodeList nl2 = el.getChildNodes();
201           for (int i2 = 0; i2 < nl2.getLength(); i2++)
202           {
203             Node node2 = nl2.item(i2);
204             if (node2.getNodeType() == Node.ELEMENT_NODE)
205             {
206               Element el2 = (Element)node2;
207               String JavaDoc nodeName2 = node2.getNodeName();
208
209               if (nodeName2.compareTo("push_node_filter") == 0)
210               {
211                 defaultPushNodeFilter = new NodeNameFilter();
212                 defaultPushNodeFilter.loadFromXML(el2);
213               }
214               else
215               if (nodeName2.compareTo("push_destination_nodes") == 0)
216               {
217                 defaultPushDestinationNodes = new NodeNameLicList();
218                 defaultPushDestinationNodes.loadFromXML(el2);
219               }
220               else
221               if (nodeName2.compareTo("pull_node_filter") == 0)
222               {
223                 defaultPullNodeFilter = new NodeNameFilter();
224                 defaultPullNodeFilter.loadFromXML(el2);
225               }
226               else
227               if (nodeName2.compareTo("licence_text") == 0)
228               {
229                 defaultLicenceText = XML.getTextContent(el2);
230               }
231             }
232           }
233         }
234         else
235         if (nodeName.compareTo("rules") == 0)
236         {
237           NodeList nl2 = el.getChildNodes();
238           for (int i2 = 0; i2 < nl2.getLength(); i2++)
239           {
240             Node node2 = nl2.item(i2);
241             if (node2.getNodeType() == Node.ELEMENT_NODE)
242             {
243               Element el2 = (Element)node2;
244               String JavaDoc nodeName2 = node2.getNodeName();
245
246               if (nodeName2.compareTo("rule") == 0)
247               {
248                 String JavaDoc ruleName = el2.getAttribute("name");
249                 if (ruleName.length() == 0)
250                 {
251                   throw new SAXException JavaDoc("Missing or empty attribute 'name' in 'rule' tag");
252                 }
253                 
254                 if (rules.containsKey(ruleName))
255                 {
256                   throw new SAXException JavaDoc("Duplicate rule '" + ruleName + "' in contract");
257                 }
258                 
259                 ContractRule rule = new ContractRule(ruleName, this);
260                 rule.loadFromXML(el2);
261                 rules.put(ruleName, rule);
262               }
263             }
264           }
265         } //rules tag
266
}
267     }
268     
269     if (contractID.length() == 0)
270     {
271       throw new SAXException JavaDoc("Unspecified contractID - tag 'id' is missing or has empty content");
272     }
273   }
274   
275   /**
276    * Saves the item to XML DOM tree.
277    */

278   public void saveToXML(Element element)
279   {
280     Document doc = element.getOwnerDocument();
281     Element el;
282   
283     XML.newTextElement(element, "id", contractID);
284     if (description.length() != 0) XML.newTextElement(element, "description", description);
285     
286     if (validFrom != null || validTo != null || autoDelete)
287     {
288       DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
289       el = doc.createElement("validity");
290       if (validFrom != null) el.setAttribute("from", dateFormat.format(validFrom));
291       if (validTo != null) el.setAttribute("to", dateFormat.format(validTo));
292       if (autoDelete) el.setAttribute("autodelete", "true");
293       element.appendChild(el);
294     }
295
296     if (defaultPushDestinationNodes != null ||
297         defaultPullNodeFilter != null ||
298         defaultLicenceText.length() != 0)
299     {
300       el = doc.createElement("defaults");
301
302       if (defaultPushNodeFilter != null)
303       {
304         Element el2 = doc.createElement("push_node_filter");
305         defaultPushNodeFilter.saveToXML(el2);
306         el.appendChild(el2);
307       }
308       
309       if (defaultPushDestinationNodes != null)
310       {
311         Element el2 = doc.createElement("push_destination_nodes");
312         defaultPushDestinationNodes.saveToXML(el2);
313         el.appendChild(el2);
314       }
315       
316       if (defaultPullNodeFilter != null)
317       {
318         Element el2 = doc.createElement("pull_node_filter");
319         defaultPullNodeFilter.saveToXML(el2);
320         el.appendChild(el2);
321       }
322       
323       if (defaultLicenceText.length() != 0)
324       {
325         XML.newTextElement(el, "licence_text", defaultLicenceText);
326       }
327       
328       element.appendChild(el);
329     }
330     
331     el = doc.createElement("rules");
332     
333     Iterator it = rules.values().iterator();
334     while (it.hasNext())
335     {
336       ContractRule rule = (ContractRule)it.next();
337       Element el2 = doc.createElement("rule");
338       el2.setAttribute("name", rule.getName());
339       rule.saveToXML(el2);
340       el.appendChild(el2);
341     }
342       
343     element.appendChild(el);
344   }
345   
346   
347   public String JavaDoc getContractID()
348   {
349     return contractID;
350   }
351   
352   public String JavaDoc getDescription()
353   {
354     return description;
355   }
356
357   public boolean getAutoDelete()
358   {
359     return autoDelete;
360   }
361   
362   public Date getValidFrom() //can be null
363
{
364     return validFrom;
365   }
366   
367   public Date getValidTo() //can be null
368
{
369     return validTo;
370   }
371   
372   public boolean isValid()
373   {
374     Date now = Calendar.getInstance().getTime();
375     return (validFrom == null || !validFrom.after(now)) && (validTo == null || !validTo.before(now));
376   }
377
378   public NodeNameLicList getDefaultPushDestinationNodes()
379   {
380     return defaultPushDestinationNodes;
381   }
382   
383   public NodeNameFilter getDefaultPushNodeFilter()
384   {
385     return defaultPushNodeFilter;
386   }
387   
388   public NodeNameFilter getDefaultPullNodeFilter()
389   {
390     return defaultPullNodeFilter;
391   }
392   
393   public String JavaDoc getDefaultLicenceText()
394   {
395     return defaultLicenceText;
396   }
397   
398   public Map getRules()
399   {
400     return rules;
401   }
402
403   public void setContractID(String JavaDoc contractID)
404   {
405     this.contractID = contractID;
406   }
407   
408   public void setDescription(String JavaDoc description)
409   {
410     this.description = description;
411   }
412
413   public void setAutoDelete(boolean autoDelete)
414   {
415     this.autoDelete = autoDelete;
416   }
417   
418   public void setValidFrom(Date validFrom) //can be null
419
{
420     this.validFrom = validFrom;
421   }
422   
423   public void setValidTo(Date validTo) //can be null
424
{
425     this.validTo = validTo;
426   }
427   
428   public void setDefaultPushDestinationNodes(NodeNameLicList defaultPushDestinationNodes) //can be null
429
{
430     this.defaultPushDestinationNodes = defaultPushDestinationNodes;
431   }
432   
433   public void setDefaultPushNodeFilter(NodeNameFilter defaultPushNodeFilter)
434   {
435     this.defaultPushNodeFilter = defaultPushNodeFilter;
436   }
437   
438   public void setDefaultPullNodeFilter(NodeNameFilter defaultPullNodeFilter) // can be null
439
{
440     this.defaultPullNodeFilter = defaultPullNodeFilter;
441   }
442   
443   public void setDefaultLicenceText(String JavaDoc defaultLicenceText)
444   {
445     this.defaultLicenceText = defaultLicenceText;
446   }
447
448   public void addRule(ContractRule rule)
449   {
450     rules.put(rule.getName(), rule);
451   }
452
453   /**
454    * Can contract accept "pull" and if so by which rule?
455    *
456    * @param bundleInfo "name of bundle"
457    * @param nodeInfo node, which requests the bundle
458    * @return ContractRule that can accept "pull" or null if no such rule exists
459    */

460   public ContractRule passPull(BundleInfo bundleInfo, NodeInfo nodeInfo)
461   {
462     synchronized (rules)
463     {
464       if (!isValid()) return null;
465       
466       boolean areDefaultsPresent = false;
467       boolean nodePassedInDefaults = false;
468       if (defaultPullNodeFilter != null)
469       {
470         areDefaultsPresent = true;
471         nodePassedInDefaults = defaultPullNodeFilter.pass(nodeInfo);
472       }
473       
474       Iterator it = rules.values().iterator();
475       while (it.hasNext())
476       {
477         ContractRule contractRule = (ContractRule)it.next();
478         if (contractRule.passPull(bundleInfo, nodeInfo, areDefaultsPresent, nodePassedInDefaults)) return contractRule;
479       }
480     }
481     
482     return null;
483   }
484
485   /**
486    * Can contract accept "pull" by specified rule?
487    *
488    * @param bundleInfo "name of bundle"
489    * @param nodeInfo node, which requests the bundle
490    * @param contractRule name of rule in the contract
491    * @return ContractRule if it can accept "pull" or null if it can't
492    */

493   public ContractRule passPull(BundleInfo bundleInfo, NodeInfo nodeInfo, String JavaDoc contractRule)
494   {
495     synchronized (rules)
496     {
497       if (!isValid()) return null;
498       
499       boolean areDefaultsPresent = false;
500       boolean nodePassedInDefaults = false;
501       if (defaultPullNodeFilter != null)
502       {
503         areDefaultsPresent = true;
504         nodePassedInDefaults = defaultPullNodeFilter.pass(nodeInfo);
505       }
506       
507       ContractRule rule = (ContractRule)rules.get(contractRule);
508       if (rule == null) return null;
509       if (rule.passPull(bundleInfo, nodeInfo, areDefaultsPresent, nodePassedInDefaults)) return rule;
510     }
511     
512     return null;
513   }
514
515   /**
516    * Can contract accept "push" and if so, by which rule?
517    *
518    * @param bundleInfo describes bundle that should be "pushed"
519    * @param nodeInfo destination node
520    * @return ContractRule that can accept "push" or null if no such rule exists
521    */

522   public ContractRule passPush(BundleInfo bundleInfo, NodeInfo nodeInfo)
523   {
524     synchronized (rules)
525     {
526       if (!isValid()) return null;
527       
528       boolean nodePassedInDefaults = false;
529       if (defaultPullNodeFilter != null) nodePassedInDefaults = defaultPushDestinationNodes.pass(nodeInfo) != null;
530       
531       Iterator it = rules.values().iterator();
532       while (it.hasNext())
533       {
534         ContractRule contractRule = (ContractRule)it.next();
535         if (contractRule.passPush(bundleInfo, nodeInfo, nodePassedInDefaults)) return contractRule;
536       }
537     }
538     
539     return null;
540   }
541
542   /**
543    * Can contract accept "push" by specified rule?
544    *
545    * @param bundleInfo describes bundle that should be "pushed"
546    * @param nodeInfo destination node
547    * @param contractRule name of rule in the contract
548    * @return ContractRule if it can accept "push" or null if it can't
549    */

550   public ContractRule passPush(BundleInfo bundleInfo, NodeInfo nodeInfo, String JavaDoc contractRule)
551   {
552     synchronized (rules)
553     {
554       if (!isValid()) return null;
555       
556       boolean nodePassedInDefaults = false;
557       if (defaultPullNodeFilter != null) nodePassedInDefaults = defaultPushDestinationNodes.pass(nodeInfo) != null;
558       
559       ContractRule rule = (ContractRule)rules.get(contractRule);
560       if (rule == null) return null;
561       if (rule.passPush(bundleInfo, nodeInfo, nodePassedInDefaults)) return rule;
562     }
563     
564     return null;
565   }
566
567   
568   /**
569    * Generates input and output triggers that performs the rules introduced by the contract
570    *
571    * @param firstDelete if true all input and output triggers that belongs to the contract are deleted first
572    * @param inputTriggers storage of Input Triggers
573    * @param outputTriggers storage of Output Triggers
574    */

575   public void generateTriggers(boolean firstDelete, InputTriggers inputTriggers, OutputTriggers outputTriggers)
576   {
577     if (firstDelete) deleteTriggers(inputTriggers, outputTriggers);
578
579     synchronized (rules)
580     {
581       Iterator it = rules.values().iterator();
582       while (it.hasNext())
583       {
584         ContractRule rule = (ContractRule)it.next();
585         
586         Date valFrom = rule.getValidFrom();
587         if (valFrom == null) valFrom = validFrom;
588         if (valFrom != null) valFrom = (Date)valFrom.clone();
589
590         Date valTo = rule.getValidTo();
591         if (valTo == null) valTo = validTo;
592         if (valTo != null) valTo = (Date)valTo.clone();
593         
594         
595         if (rule.isPush())
596         {
597           NodeNameFilter pushNodeFilter = rule.getPushNodeFilter();
598           if (pushNodeFilter == null) pushNodeFilter = defaultPushNodeFilter;
599           if (pushNodeFilter != null) pushNodeFilter = (NodeNameFilter)pushNodeFilter.clone();
600           
601           NodeNameLicList pushDestinationNodes = rule.getPushDestinationNodes();
602           if (pushDestinationNodes == null) pushDestinationNodes = defaultPushDestinationNodes;
603           if (pushDestinationNodes != null) pushDestinationNodes = (NodeNameLicList)pushDestinationNodes.clone();
604           
605           if (pushDestinationNodes != null)
606           {
607             inputTriggers.addInputTrigger(
608                   contractID,
609                   true,
610                   InputTrigger.SOURCE_PUSH | InputTrigger.SOURCE_PULL | InputTrigger.SOURCE_MADE,
611                   InputTrigger.BUNDLETYPE_FULL,
612                   "Generated from Contract (ID:'" + contractID +"'; Rule:'" + rule.getName() + "')",
613                   rule.getAutoDelete(),
614                   (BundleNameFilter)rule.getSoftware().clone(),
615                   pushNodeFilter,
616                   valFrom,
617                   valTo,
618                   contractID,
619                   rule.getName(),
620                   InputTrigger.ACTION_PUSH,
621                   0,
622                   null,
623                   null,
624                   false,
625                   null,
626                   pushDestinationNodes,
627                   null);
628           }
629         }
630         
631         if (rule.isPull())
632         {
633           NodeNameFilter pullNodeFilter = rule.getPullNodeFilter();
634           if (pullNodeFilter == null) pullNodeFilter = defaultPullNodeFilter;
635           if (pullNodeFilter != null) pullNodeFilter = (NodeNameFilter)pullNodeFilter.clone();
636           
637           outputTriggers.addOutputTrigger(
638                 contractID,
639                 true,
640                 "Generated from Contract (ID:'" + contractID +"'; Rule:'" + rule.getName() + "')",
641                 rule.getAutoDelete(),
642                 (BundleNameFilter)rule.getSoftware().clone(),
643                 pullNodeFilter,
644                 valFrom,
645                 valTo,
646                 contractID,
647                 rule.getName());
648         }
649       }
650     }
651   }
652   
653   /**
654    * Deletes input and output triggers belongs to the contract
655    *
656    * @param inputTriggers storage of Input Triggers
657    * @param outputTriggers storage of Output Triggers
658    */

659   public void deleteTriggers(InputTriggers inputTriggers, OutputTriggers outputTriggers)
660   {
661     synchronized (inputTriggers) {
662     synchronized (inputTriggers.map)
663     {
664       Iterator it = inputTriggers.map.values().iterator();
665       while (it.hasNext())
666       {
667         InputTrigger inputTrigger = (InputTrigger)it.next();
668         if (inputTrigger.isContract() && contractID.compareTo(inputTrigger.getContractID()) == 0)
669         {
670           inputTrigger.deleteFromStorage();
671           it.remove();
672         }
673       }
674     }
675     } //inputTriggers
676

677     synchronized (outputTriggers) {
678     synchronized (outputTriggers.map)
679     {
680       Iterator it = outputTriggers.map.values().iterator();
681       while (it.hasNext())
682       {
683         OutputTrigger outputTrigger = (OutputTrigger)it.next();
684         if (outputTrigger.isContract() && contractID.compareTo(outputTrigger.getContractID()) == 0)
685         {
686           outputTrigger.deleteFromStorage();
687           it.remove();
688         }
689       }
690     }
691     } //outputTriggers
692
}
693 }
694
Popular Tags