001package org.hl7.fhir.convertors.misc;
002
003
004
005
006
007/*
008  Copyright (c) 2011+, HL7, Inc.
009  All rights reserved.
010  
011  Redistribution and use in source and binary forms, with or without modification, 
012  are permitted provided that the following conditions are met:
013  
014   * Redistributions of source code must retain the above copyright notice, this 
015     list of conditions and the following disclaimer.
016   * Redistributions in binary form must reproduce the above copyright notice, 
017     this list of conditions and the following disclaimer in the documentation 
018     and/or other materials provided with the distribution.
019   * Neither the name of HL7 nor the names of its contributors may be used to 
020     endorse or promote products derived from this software without specific 
021     prior written permission.
022  
023  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
024  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
025  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
026  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
027  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
028  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
029  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
030  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
031  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
032  POSSIBILITY OF SUCH DAMAGE.
033  
034*/
035
036
037import org.fhir.ucum.UcumService;
038import org.hl7.fhir.dstu3.model.*;
039import org.hl7.fhir.dstu3.model.Address.AddressUse;
040import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem;
041import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointUse;
042import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
043import org.hl7.fhir.dstu3.model.HumanName.NameUse;
044import org.hl7.fhir.dstu3.model.Timing.EventTiming;
045import org.hl7.fhir.dstu3.model.Timing.TimingRepeatComponent;
046import org.hl7.fhir.dstu3.model.Timing.UnitsOfTime;
047import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
048import org.hl7.fhir.utilities.OIDUtils;
049import org.hl7.fhir.utilities.Utilities;
050import org.w3c.dom.Element;
051import org.w3c.dom.Node;
052
053import java.math.BigDecimal;
054import java.util.HashSet;
055import java.util.List;
056import java.util.Set;
057import java.util.UUID;
058
059public class Convert {
060
061  private final CDAUtilities cda;
062  private final UcumService ucumSvc;
063  private final Set<String> oids = new HashSet<String>();
064  private final String defaultTimezone;
065  private boolean generateMissingExtensions;
066
067  public Convert(CDAUtilities cda, UcumService ucumSvc, String defaultTimezone) {
068    super();
069    this.cda = cda;
070    this.ucumSvc = ucumSvc;
071    this.defaultTimezone = defaultTimezone;
072  }
073
074  public Identifier makeIdentifierFromII(Element e) throws Exception {
075    Identifier id = new Identifier();
076    String r = e.getAttribute("root");
077    String ex;
078    if (e.hasAttribute("extension") && Utilities.noString(e.getAttribute("extension"))) {
079      if (generateMissingExtensions)
080        ex = UUID.randomUUID().toString();
081      else
082        throw new Exception("Broken identifier - extension is blank");
083    } else
084      ex = e.getAttribute("extension");
085
086    if (Utilities.noString(ex)) {
087      id.setSystem("urn:ietf:rfc:3986");
088      if (isGuid(r))
089        id.setValue("urn:uuid:" + r);
090      else if (UriForOid(r) != null)
091        id.setValue(UriForOid(r));
092      else
093        id.setValue(UriForOid(r));
094    } else {
095      if (isGuid(r))
096        id.setSystem("urn:uuid:" + r);
097      else if (UriForOid(r) != null)
098        id.setSystem(UriForOid(r));
099      else
100        id.setSystem("urn:oid:" + r);
101      id.setValue(ex);
102    }
103    return id;
104  }
105
106  public String makeURIfromII(Element e) {
107    String r = e.getAttribute("root");
108    if (Utilities.noString(e.getAttribute("extension"))) {
109      if (isGuid(r))
110        return "urn:uuid:" + r;
111      else if (UriForOid(r) != null)
112        return UriForOid(r);
113      else
114        return UriForOid(r);
115    } else {
116      if (isGuid(r))
117        return "urn:uuid:" + r + "::" + e.getAttribute("extension");
118      else if (UriForOid(r) != null)
119        return UriForOid(r) + "::" + e.getAttribute("extension");
120      else
121        return "urn:oid:" + r + "::" + e.getAttribute("extension");
122    }
123  }
124
125  private String UriForOid(String r) {
126    String uri = OIDUtils.getUriForOid(r);
127    if (uri != null)
128      return uri;
129    else {
130      oids.add(r);
131      return "urn:oid:" + r;
132    }
133  }
134
135  public boolean isGuid(String r) {
136    return r.matches("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
137  }
138
139  public InstantType makeInstantFromTS(Element child) throws Exception {
140    InstantType i = InstantType.parseV3(child.getAttribute("value"));
141    return i;
142  }
143
144  public CodeableConcept makeCodeableConceptFromCD(Element cv) throws Exception {
145    if (cv == null)
146      return null;
147    CodeableConcept cc = new CodeableConcept();
148    cc.addCoding(makeCodingFromCV(cv));
149    for (Element e : cda.getChildren(cv, "translation"))
150      cc.addCoding(makeCodingFromCV(e));
151    if (cda.getChild(cv, "originalText") != null) {
152      Element ote = cda.getChild(cv, "originalText");
153//                      if (cda.getChild(ote, "reference") != null) {
154//                              if (cda.getChild(ote, "reference").getAttribute("value").startsWith("#")) {
155//                                      Element t = cda.getByXmlId(cda.getChild(ote, "reference").getAttribute("value").substring(1));
156//                                      String ot = t.getTextContent().trim();
157//                                      cc.setText(Utilities.noString(ot) ? null : ot);
158//                              } else
159//                                      throw new Exception("external references not handled yet "+cda.getChild(ote, "reference").getAttribute("value"));
160//                      } else {                        
161      String ot = ote.getTextContent().trim();
162      cc.setText(Utilities.noString(ot) ? null : ot);
163      //}
164    }
165    return cc;
166  }
167
168  public Coding makeCodingFromCV(Element cd) throws Exception {
169    if (cd == null || Utilities.noString(cd.getAttribute("code")))
170      return null;
171    Coding c = new Coding();
172    c.setCode(cd.getAttribute("code"));
173    c.setDisplay(cd.getAttribute("displayName"));
174    String r = cd.getAttribute("codeSystem");
175    String uri = getUriForOID(r);
176    if (uri != null)
177      c.setSystem(uri);
178    else if (isGuid(r))
179      c.setSystem("urn:uuid:" + r);
180    else if (UriForOid(r) != null)
181      c.setSystem(UriForOid(r));
182    else
183      c.setSystem("urn:oid:" + r);
184    return c;
185  }
186
187  private String getUriForOID(String r) {
188    if (r.equals("2.16.840.1.113883.6.1"))
189      return "http://loinc.org";
190    if (r.equals("2.16.840.1.113883.6.96"))
191      return "http://snomed.info/sct";
192    return null;
193  }
194
195  public Address makeAddressFromAD(Element e) {
196    if (e == null)
197      return null;
198    Address a = new Address();
199    String use = e.getAttribute("use");
200    if (use != null) {
201      if (use.equals("H") || use.equals("HP") || use.equals("HV"))
202        a.setUse(AddressUse.HOME);
203      else if (use.equals("WP") || use.equals("DIR") || use.equals("PUB"))
204        a.setUse(AddressUse.WORK);
205      else if (use.equals("TMP"))
206        a.setUse(AddressUse.TEMP);
207      else if (use.equals("BAD"))
208        a.setUse(AddressUse.OLD);
209    }
210    Node n = e.getFirstChild();
211    while (n != null) {
212      if (n.getNodeType() == Node.ELEMENT_NODE) {
213        String v = n.getTextContent();
214        if (n.getLocalName().equals("additionalLocator"))
215          a.getLine().add(makeString(v));
216//                      else if (e.getLocalName().equals("unitID"))
217//                              else if (e.getLocalName().equals("unitType"))
218        else if (n.getLocalName().equals("deliveryAddressLine"))
219          a.getLine().add(makeString(v));
220//                              else if (e.getLocalName().equals("deliveryInstallationType"))
221//                              else if (e.getLocalName().equals("deliveryInstallationArea"))
222//                              else if (e.getLocalName().equals("deliveryInstallationQualifier"))
223//                              else if (e.getLocalName().equals("deliveryMode"))
224//                              else if (e.getLocalName().equals("deliveryModeIdentifier"))
225        else if (n.getLocalName().equals("streetAddressLine"))
226          a.getLine().add(makeString(v));
227//                              else if (e.getLocalName().equals("houseNumber"))
228//                              else if (e.getLocalName().equals("buildingNumberSuffix"))
229//                              else if (e.getLocalName().equals("postBox"))
230//                              else if (e.getLocalName().equals("houseNumberNumeric"))
231//                              else if (e.getLocalName().equals("streetName"))
232//                              else if (e.getLocalName().equals("streetNameBase"))
233//                              else if (e.getLocalName().equals("streetNameType"))
234        else if (n.getLocalName().equals("direction"))
235          a.getLine().add(makeString(v));
236        else if (n.getLocalName().equals("careOf"))
237          a.getLine().add(makeString(v));
238//                              else if (e.getLocalName().equals("censusTract"))
239        else if (n.getLocalName().equals("country"))
240          a.setCountry(v);
241          //else if (e.getLocalName().equals("county"))
242        else if (n.getLocalName().equals("city"))
243          a.setCity(v);
244//                              else if (e.getLocalName().equals("delimiter"))
245//                              else if (e.getLocalName().equals("precinct"))
246        else if (n.getLocalName().equals("state"))
247          a.setState(v);
248        else if (n.getLocalName().equals("postalCode"))
249          a.setPostalCode(v);
250      }
251      n = n.getNextSibling();
252    }
253    return a;
254  }
255
256  public StringType makeString(String v) {
257    StringType s = new StringType();
258    s.setValue(v);
259    return s;
260  }
261
262  public ContactPoint makeContactFromTEL(Element e) throws Exception {
263    if (e == null)
264      return null;
265    if (e.hasAttribute("nullFlavor"))
266      return null;
267    ContactPoint c = new ContactPoint();
268    String use = e.getAttribute("use");
269    if (use != null) {
270      if (use.equals("H") || use.equals("HP") || use.equals("HV"))
271        c.setUse(ContactPointUse.HOME);
272      else if (use.equals("WP") || use.equals("DIR") || use.equals("PUB"))
273        c.setUse(ContactPointUse.WORK);
274      else if (use.equals("TMP"))
275        c.setUse(ContactPointUse.TEMP);
276      else if (use.equals("BAD"))
277        c.setUse(ContactPointUse.OLD);
278    }
279    if (e.getAttribute("value") != null) {
280      String[] url = e.getAttribute("value").split(":");
281      if (url.length == 1) {
282        c.setValue(url[0].trim());
283        c.setSystem(ContactPointSystem.PHONE);
284      } else {
285        if (url[0].equals("tel"))
286          c.setSystem(ContactPointSystem.PHONE);
287        else if (url[0].equals("mailto"))
288          c.setSystem(ContactPointSystem.EMAIL);
289        else if (e.getAttribute("value").contains(":"))
290          c.setSystem(ContactPointSystem.OTHER);
291        else
292          c.setSystem(ContactPointSystem.PHONE);
293        c.setValue(url[1].trim());
294      }
295    }
296    return c;
297
298  }
299
300  public HumanName makeNameFromEN(Element e) {
301    if (e == null)
302      return null;
303    HumanName hn = new HumanName();
304    String use = e.getAttribute("use");
305    if (use != null) {
306      if (use.equals("L"))
307        hn.setUse(NameUse.USUAL);
308      else if (use.equals("C"))
309        hn.setUse(NameUse.OFFICIAL);
310      else if (use.equals("P") || use.equals("A"))
311        hn.setUse(NameUse.ANONYMOUS);
312      else if (use.equals("TMP"))
313        hn.setUse(NameUse.TEMP);
314      else if (use.equals("BAD"))
315        hn.setUse(NameUse.OLD);
316    }
317
318    Node n = e.getFirstChild();
319    while (n != null) {
320      if (n.getNodeType() == Node.ELEMENT_NODE) {
321        String v = n.getTextContent();
322        if (n.getLocalName().equals("family"))
323          hn.setFamilyElement(makeString(v));
324        else if (n.getLocalName().equals("given"))
325          hn.getGiven().add(makeString(v));
326        else if (n.getLocalName().equals("prefix"))
327          hn.getPrefix().add(makeString(v));
328        else if (n.getLocalName().equals("suffix"))
329          hn.getSuffix().add(makeString(v));
330      }
331      n = n.getNextSibling();
332    }
333    return hn;
334  }
335
336  public DateTimeType makeDateTimeFromTS(Element ts) throws Exception {
337    if (ts == null)
338      return null;
339
340    String v = ts.getAttribute("value");
341    if (Utilities.noString(v))
342      return null;
343
344    if (v.length() > 8 && !hasTimezone(v))
345      v += defaultTimezone;
346    DateTimeType d = DateTimeType.parseV3(v);
347    return d;
348  }
349
350  private boolean hasTimezone(String v) {
351    return v.contains("+") || v.contains("-") || v.endsWith("Z");
352  }
353
354
355  public DateType makeDateFromTS(Element ts) throws Exception {
356    if (ts == null)
357      return null;
358
359    String v = ts.getAttribute("value");
360    if (Utilities.noString(v))
361      return null;
362    DateType d = DateType.parseV3(v);
363    return d;
364  }
365
366  public Period makePeriodFromIVL(Element ivl) throws Exception {
367    if (ivl == null)
368      return null;
369    Period p = new Period();
370    Element low = cda.getChild(ivl, "low");
371    if (low != null)
372      p.setStartElement(makeDateTimeFromTS(low));
373    Element high = cda.getChild(ivl, "high");
374    if (high != null)
375      p.setEndElement(makeDateTimeFromTS(high));
376
377    if (p.getStartElement() != null || p.getEndElement() != null)
378      return p;
379    else
380      return null;
381  }
382
383  // this is a weird one - where CDA has an IVL, and FHIR has a date
384  public DateTimeType makeDateTimeFromIVL(Element ivl) throws Exception {
385    if (ivl == null)
386      return null;
387    if (ivl.hasAttribute("value"))
388      return makeDateTimeFromTS(ivl);
389    Element high = cda.getChild(ivl, "high");
390    if (high != null)
391      return makeDateTimeFromTS(high);
392    Element low = cda.getChild(ivl, "low");
393    if (low != null)
394      return makeDateTimeFromTS(low);
395    return null;
396  }
397
398  public Type makeStringFromED(Element e) throws Exception {
399    if (e == null)
400      return null;
401    if (cda.getChild(e, "reference") != null) {
402      if (cda.getChild(e, "reference").getAttribute("value").startsWith("#")) {
403        Element t = cda.getByXmlId(cda.getChild(e, "reference").getAttribute("value").substring(1));
404        String ot = t.getTextContent().trim();
405        return Utilities.noString(ot) ? null : Factory.newString_(ot);
406      } else
407        throw new Exception("external references not handled yet " + cda.getChild(e, "reference").getAttribute("value"));
408    }
409    return Factory.newString_(e.getTextContent());
410  }
411
412  public Type makeTypeFromANY(Element e) throws Exception {
413    if (e == null)
414      return null;
415    String t = e.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
416    if (Utilities.noString(t))
417      throw new Exception("Missing type on RIM attribute with type any");
418    if (t.equals("CD") || t.equals("CE"))
419      return makeCodeableConceptFromCD(e);
420    else if (t.equals("ST"))
421      return makeStringFromED(e);
422    else
423      throw new Exception("Not done yet (type = " + t + ")");
424  }
425
426  public Type makeMatchingTypeFromIVL(Element ivl) throws Exception {
427    if (ivl == null)
428      return null;
429    if (ivl.getAttribute("value") != null)
430      return makeDateTimeFromIVL(ivl);
431    if (cda.getChild(ivl, "low") != null || cda.getChild(ivl, "high") != null)
432      return makePeriodFromIVL(ivl);
433    throw new Exception("not handled yet");
434  }
435
436  public Type makeCodeableConceptFromNullFlavor(String nf) throws Exception {
437    // Some nullFlavors have explicit values in value sets. This can only be called where there aren't.
438    if (nf == null || "".equals(nf))
439      return null;
440    if ("NI".equals(nf))
441      return null; // there's no code for this
442    if ("NA".equals(nf))
443      return Factory.newCodeableConcept("unsupported", "http://hl7.org/fhir/data-absent-reason", "Unsupported"); // todo: is this reasonable? Why else would you use N/A?
444    if ("UNK".equals(nf))
445      return Factory.newCodeableConcept("unknown", "http://hl7.org/fhir/data-absent-reason", "Unknown");
446    if ("ASKU".equals(nf))
447      return Factory.newCodeableConcept("asked", "http://hl7.org/fhir/data-absent-reason", "Asked/Unknown");
448    if ("NAV".equals(nf))
449      return Factory.newCodeableConcept("temp", "http://hl7.org/fhir/data-absent-reason", "Temporarily Unavailable");
450    if ("NASK".equals(nf))
451      return Factory.newCodeableConcept("notasked", "http://hl7.org/fhir/data-absent-reason", "Not Asked");
452    if ("MSK".equals(nf))
453      return Factory.newCodeableConcept("masked", "http://hl7.org/fhir/data-absent-reason", "Masked");
454    if ("OTH".equals(nf))
455      return null; // well, what should be done?
456    return null; // well, what should be done?
457
458  }
459
460  public Range makeRangeFromIVLPQ(Element ivlpq) throws Exception {
461    if (ivlpq == null)
462      return null;
463    Element low = cda.getChild(ivlpq, "low");
464    Element high = cda.getChild(ivlpq, "high");
465    if (low == null && high == null)
466      return null;
467    Range r = new Range();
468    r.setLow(makeSimpleQuantityFromPQ(low, ivlpq.getAttribute("unit")));
469    r.setHigh(makeSimpleQuantityFromPQ(high, ivlpq.getAttribute("unit")));
470    return r;
471  }
472
473  public Quantity makeQuantityFromPQ(Element pq) throws Exception {
474    return makeQuantityFromPQ(pq, null);
475  }
476
477  public Quantity makeQuantityFromPQ(Element pq, String units) throws Exception {
478    if (pq == null)
479      return null;
480    Quantity qty = new Quantity();
481    String n = pq.getAttribute("value").replace(",", "").trim();
482    try {
483      qty.setValue(new BigDecimal(n));
484    } catch (Exception e) {
485      throw new Exception("Unable to process value '" + n + "'", e);
486    }
487    units = Utilities.noString(pq.getAttribute("unit")) ? units : pq.getAttribute("unit");
488    if (!Utilities.noString(units)) {
489      if (ucumSvc == null || ucumSvc.validate(units) != null)
490        qty.setUnit(units);
491      else {
492        qty.setCode(units);
493        qty.setSystem("http://unitsofmeasure.org");
494        qty.setUnit(ucumSvc.getCommonDisplay(units));
495      }
496    }
497    return qty;
498  }
499
500  public SimpleQuantity makeSimpleQuantityFromPQ(Element pq, String units) throws Exception {
501    if (pq == null)
502      return null;
503    SimpleQuantity qty = new SimpleQuantity();
504    String n = pq.getAttribute("value").replace(",", "").trim();
505    try {
506      qty.setValue(new BigDecimal(n));
507    } catch (Exception e) {
508      throw new Exception("Unable to process value '" + n + "'", e);
509    }
510    units = Utilities.noString(pq.getAttribute("unit")) ? units : pq.getAttribute("unit");
511    if (!Utilities.noString(units)) {
512      if (ucumSvc == null || ucumSvc.validate(units) != null)
513        qty.setUnit(units);
514      else {
515        qty.setCode(units);
516        qty.setSystem("http://unitsofmeasure.org");
517        qty.setUnit(ucumSvc.getCommonDisplay(units));
518      }
519    }
520    return qty;
521  }
522
523  public AdministrativeGender makeGenderFromCD(Element cd) throws Exception {
524    String code = cd.getAttribute("code");
525    String system = cd.getAttribute("codeSystem");
526    if ("2.16.840.1.113883.5.1".equals(system)) {
527      if ("F".equals(code))
528        return AdministrativeGender.FEMALE;
529      if ("M".equals(code))
530        return AdministrativeGender.MALE;
531    }
532    throw new Exception("Unable to read Gender " + system + "::" + code);
533  }
534
535  /*
536  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:EIVL_TS]: 389
537  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:EIVL_TS]/event: 389
538  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]: 33470
539  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/high: 20566
540  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/high[nullFlavor:NA]: 9581
541  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/low: 32501
542  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:IVL_TS]/low[nullFlavor:UNK]: 969
543  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:PIVL_TS]: 17911
544  /entry[COMP]/substanceAdministration[SBADM,EVN]/effectiveTime[type:PIVL_TS]/period: 17911
545   */
546  public Type makeSomethingFromGTS(List<Element> children) throws Exception {
547    if (children.isEmpty())
548      return null;
549    if (children.size() == 1) {
550      String type = children.get(0).getAttribute("xsi:type");
551      if (type.equals("IVL_TS"))
552        return makePeriodFromIVL(children.get(0));
553      else
554        throw new Exception("Unknown GTS type '" + type + "'");
555    }
556    CommaSeparatedStringBuilder t = new CommaSeparatedStringBuilder();
557    for (Element c : children)
558      t.append(c.getAttribute("xsi:type"));
559    if (t.toString().equals("IVL_TS, PIVL_TS"))
560      return makeTimingFromBoundedPIVL(children.get(0), children.get(1));
561    if (t.toString().equals("IVL_TS, EIVL_TS"))
562      return makeTimingFromBoundedEIVL(children.get(0), children.get(1));
563    throw new Exception("Unknown GTS pattern '" + t + "'");
564  }
565
566  private Type makeTimingFromBoundedEIVL(Element ivl, Element eivl) throws Exception {
567    Timing t = new Timing();
568    t.setRepeat(new TimingRepeatComponent());
569    Element e = cda.getChild(eivl, "event");
570    t.getRepeat().setBounds(makePeriodFromIVL(ivl));
571    t.getRepeat().addWhen(convertEventTiming(e.getAttribute("code")));
572    return t;
573  }
574
575  private EventTiming convertEventTiming(String e) throws Exception {
576    if ("HS".equals(e))
577      return EventTiming.HS;
578    throw new Exception("Unknown event " + e);
579  }
580
581  private Timing makeTimingFromBoundedPIVL(Element ivl, Element pivl) throws Exception {
582    Timing t = new Timing();
583    t.setRepeat(new TimingRepeatComponent());
584    Element p = cda.getChild(pivl, "period");
585    t.getRepeat().setBounds(makePeriodFromIVL(ivl));
586    t.getRepeat().setPeriod(new BigDecimal(p.getAttribute("value")));
587    t.getRepeat().setPeriodUnit(convertTimeUnit(p.getAttribute("unit")));
588    return t;
589  }
590
591  private UnitsOfTime convertTimeUnit(String u) throws Exception {
592    if ("h".equals(u))
593      return UnitsOfTime.H;
594    if ("d".equals(u))
595      return UnitsOfTime.D;
596    if ("w".equals(u))
597      return UnitsOfTime.WK;
598    throw new Exception("Unknown unit of time " + u);
599  }
600
601  public Set<String> getOids() {
602    return oids;
603  }
604
605  public boolean isGenerateMissingExtensions() {
606    return generateMissingExtensions;
607  }
608
609  public void setGenerateMissingExtensions(boolean generateMissingExtensions) {
610    this.generateMissingExtensions = generateMissingExtensions;
611  }
612
613
614}