001    package edu.nrao.sss.model.resource;
002    
003    import java.io.FileNotFoundException;
004    import java.io.Reader;
005    import java.io.Writer;
006    import java.util.ArrayList;
007    import java.util.Arrays;
008    import java.util.Date;
009    import java.util.List;
010    import java.util.UUID;
011    
012    import javax.xml.bind.JAXBException;
013    import javax.xml.bind.annotation.XmlAttribute;
014    import javax.xml.bind.annotation.XmlElement;
015    import javax.xml.bind.annotation.XmlElementRef;
016    import javax.xml.bind.annotation.XmlElementRefs;
017    import javax.xml.bind.annotation.XmlElementWrapper;
018    import javax.xml.bind.annotation.XmlID;
019    import javax.xml.bind.annotation.XmlRootElement;
020    import javax.xml.bind.annotation.XmlTransient;
021    import javax.xml.bind.annotation.XmlType;
022    import javax.xml.stream.XMLStreamException;
023    
024    import org.apache.log4j.Logger;
025    
026    import edu.nrao.sss.catalog.NameableCatalogItem;
027    import edu.nrao.sss.model.UserAccountable;
028    import edu.nrao.sss.util.Identifiable;
029    import edu.nrao.sss.util.JaxbUtility;
030    
031    /**
032     * A container of scientific and hardware specifications for an observation of
033     * of an astronomical source.
034     * <p>
035     * <b>Version Info:</b>
036     * <table style="margin-left:2em">
037     *   <tr><td>$Revision: 2234 $</td>
038     *   <tr><td>$Date: 2009-04-23 14:16:36 -0600 (Thu, 23 Apr 2009) $</td>
039     *   <tr><td>$Author: dharland $ (last person to modify)</td>
040     * </table></p>
041     * 
042     * @author David M. Harland
043     * @since 2006-02-24
044     */
045    @XmlRootElement
046    @XmlType(propOrder={"name",
047                        "createdBy","createdOn","lastUpdatedBy","lastUpdatedOn",
048                        "notes", "scienceSpecification",
049                        "telescope", "antennaElectronicsConfiguration",
050                        "xmlBackendList"})
051    public class Resource
052      implements NameableCatalogItem<Resource>, Identifiable //, UserAccountable
053    {
054      private static final Logger log = Logger.getLogger(Resource.class);
055      
056      private static final String INIT_NAME = "[New Resource]";
057      private static final String NO_NAME   = "[Unnamed Resource]";
058    
059      //IDENTIFICATION
060      private Long   id;
061      private String name;
062    
063      @XmlAttribute(required=true)
064      @XmlID
065      String xmlId;
066      
067      //USER TRACKING
068      private Long createdBy;      //This is a user ID
069      private Date createdOn;
070      private Long lastUpdatedBy;  //This is a user ID
071      private Date lastUpdatedOn;
072    
073      //SCIENCE VIEW
074      private ResourceSpecification scienceSpecification;
075      
076      //INSTRUMENT VIEW
077      @XmlElement
078      private TelescopeType      telescope;
079      private AntennaElectronics antennaElectronics;
080      
081      private List<TelescopeBackend> backends;
082    
083      //OTHER
084      private List<String> notes;
085    
086      /** Creates a new instance. */
087      public Resource()
088      {
089        initialize();
090      }
091      
092      /** Creates a new instance with the given name. */ 
093      public Resource(String name)
094      {
095        this();
096        
097        this.name = (name != null && !name.equals("")) ? name : NO_NAME;
098      }
099    
100      /** Initializes the instance variables of this class.  */
101      private void initialize()
102      {
103        id    = Identifiable.UNIDENTIFIED;
104        name  = INIT_NAME;
105        xmlId = "resource-" + UUID.randomUUID().toString();
106    
107        createdBy     = UserAccountable.NULL_USER_ID;
108        createdOn     = new Date();
109        lastUpdatedBy = UserAccountable.NULL_USER_ID;
110        lastUpdatedOn = new Date();
111    
112        scienceSpecification = new ResourceSpecification();
113        
114        telescope          = TelescopeType.getDefault();
115        antennaElectronics = telescope.makeElectronics();
116        backends           = new ArrayList<TelescopeBackend>();
117        
118        notes = new ArrayList<String>();
119      }
120      
121      /**
122       *  Resets this resource to its initial state.
123       *  A reset resource has the same state as a new resource. 
124       */
125      public void reset()
126      {
127        initialize();
128        
129        backends.clear();
130        notes.clear();
131      }
132    
133      //============================================================================
134      // IDENTIFICATION
135      //============================================================================
136    
137      //This method exists for the benefit of the persistence layer
138      void setId(Long id)
139      {
140        this.id = (id == null) ? Identifiable.UNIDENTIFIED : id;
141      }
142    
143      /* (non-Javadoc)
144       * @see edu.nrao.sss.util.Identifiable#getId()
145       */
146      @XmlAttribute
147      public Long getId()
148      {
149        return id;
150      }
151    
152      /**
153       * Resets the identifier of this resource
154       * to a value that represents the unidentified state.
155       * <p>
156       * This method is useful for preparing a resource for storage in a database.
157       * The ID property (as of now, though this may change in the future) is
158       * used by our persistence mechanism to identify objects.  If you are
159       * persisting this object for the first time, you may need to call
160       * this method before performing a save.  This is especially true if
161       * you have created this object from XML, as the XML unmarshalling
162       * brings along the ID property.</p> 
163       */
164      public void clearId()
165      {
166        this.id = Identifiable.UNIDENTIFIED;
167        
168        scienceSpecification.clearId();
169        
170        for (TelescopeBackend backend : backends)
171          backend.clearId();
172      }
173    
174      /**
175       * Sets the name of this resource.
176       * <p>
177       * If {@code newName} is <i>null</i> or the empty string
178       * (<tt>""</tt>), the request to change the name will be
179       * denied and the current name will remain in place.</p>
180       * 
181       * @param newName the new name of this resource.
182       */
183      public void setName(String newName)
184      {
185        if (newName != name && newName.length() > 0)
186          name = newName;
187      }
188      
189      /**
190       * Returns the name of this resource.
191       * @return the name of this resource.
192       */
193      public String getName()
194      {
195        return name;
196      }
197    
198      //============================================================================
199      // INTERFACE UserAccountable
200      //============================================================================
201      
202      public void setCreatedBy(Long userId)
203      {
204        createdBy = (userId == null) ? UserAccountable.NULL_USER_ID : userId;
205      }
206      
207      public void setCreatedOn(Date d)
208      {
209        if (d != null)
210          createdOn = d;
211      }
212    
213      public void setLastUpdatedBy(Long userId)
214      {
215        lastUpdatedBy = (userId == null) ? UserAccountable.NULL_USER_ID : userId;
216      }
217    
218      public void setLastUpdatedOn(Date d)
219      {
220        if (d != null)
221          lastUpdatedOn = d;
222      }
223    
224      public Long getCreatedBy()      { return createdBy;     }
225      public Date getCreatedOn()      { return createdOn;     }
226      public Long getLastUpdatedBy()  { return lastUpdatedBy; }
227      public Date getLastUpdatedOn()  { return lastUpdatedOn; }
228    
229      //============================================================================
230      // SCIENCE VIEW
231      //============================================================================
232    
233      /**
234       * Sets the scientific specification for this resource.
235       * 
236       * @param newSpec
237       *   the scientific specification for this resource.  If this value is
238       *   <i>null</i> it will be replaced by a new empty specification.
239       */
240      public void setScienceSpecification(ResourceSpecification newSpec)
241      {
242        scienceSpecification =
243          (newSpec == null) ? new ResourceSpecification() : newSpec;
244      }
245      
246      /**
247       * Returns the scientific specification for this resource.
248       * 
249       * @return the scientific specification for this resource.
250       */
251      public ResourceSpecification getScienceSpecification()
252      {
253        return scienceSpecification;
254      }
255      
256      /**
257       * Returns <i>true</i> if this resource has a non-empty scientific
258       * specification.  A "non-empty" specification is one that has at least
259       * one subspecification (pulsar, sky frequency, or spectral line).
260       * 
261       * @return
262       *   <i>true</i> if this resource has a non-empty scientific specification.
263       */
264      public boolean hasScienceSpecification()
265      {
266        return
267          scienceSpecification.getSkyFrequencySpecs().size() > 0 ||
268          scienceSpecification.getSpectralLineSpecs().size() > 0 ||
269          scienceSpecification.getPulsarSpecs().size() > 0;
270      }
271    
272      //============================================================================
273      // INSTRUMENT VIEW
274      //============================================================================
275    
276      /**
277       * Sets the telescope whose setup is described by this specification.
278       * <p>
279       * <b>SIDE EFFECTS:</b> changing the telescope type also changes the
280       * {@link #getAntennaElectronics() antenna electronics} held by this
281       * resource, and may change the backend as well.</p>
282       * 
283       * @param newTelescope
284       *   the telescope whose setup is described by this
285       *   specification.  If this value is <i>null</i>
286       *   a default telescope will be used instead.
287       */
288      @XmlTransient
289      public void setTelescope(TelescopeType newTelescope)
290      {
291        if (newTelescope == null)
292          newTelescope = TelescopeType.getDefault();
293        
294        //Because we're also valuing the antennaElectronics property here,
295        //we probably want to point persistence mechanisms such as
296        //JAXB and Hibernate directly at the telescope variable.
297        //See also the private set/getAntennaElectronicsConfiguration
298        //methods.
299        if (!newTelescope.equals(telescope))
300        {
301          telescope = newTelescope;
302          antennaElectronics = telescope.makeElectronics();
303          
304          //Update our list of backends.  For those backends that are not valid
305          //with the new telescope, delete them from our list.  For those that
306          //are valid, update them w/ the new antenna electronics.
307          List<CorrelatorName>   validBackends = telescope.getBackendTypes();
308          List<TelescopeBackend> oldBackends   = new ArrayList<TelescopeBackend>(backends);
309          for (TelescopeBackend tbe : oldBackends)
310          {
311            if (validBackends.contains(tbe.getName()))
312              tbe.setSignalSource(antennaElectronics);
313            else
314              backends.remove(tbe);
315          }
316        }
317      }
318      
319      /**
320       * Returns the telescope whose setup is described by this specification.
321       * @return the telescope whose setup is described by this specification.
322       */
323      public TelescopeType getTelescope()
324      {
325        return telescope;
326      }
327      
328      /**
329       * Returns antenna electronics that are configured to match this resource.
330       * @return the antenna electronics used by this resource.
331       */
332      public AntennaElectronics getAntennaElectronics()
333      {
334        return antennaElectronics;
335      }
336      
337      /**
338       * Returns the backend of the given type held by this resource.
339       * If this resource does not currently have a backend of this type,
340       * one is created -- so long at it is a valid backend for this
341       * resource's telescope -- and returned.
342       * <p>
343       * The returned backend is the one held directly by this resource,
344       * so changes made to it will be reflected herein.</p>
345       * 
346       * @param backendType
347       *   the type of backend desired.
348       *   
349       * @return
350       *   the backend of the given type held by this resource.
351       * 
352       * @throws IllegalArgumentException
353       *   if {@code backendType} is not a valid backend for this resource's
354       *   telescope.
355       *   
356       * @see #setTelescope(TelescopeType)
357       * @see TelescopeType#getBackendTypes()
358       */
359      public TelescopeBackend getBackend(CorrelatorName backendType)
360      {
361        //Quick exit if we already have it
362        for (TelescopeBackend currBackend : backends)
363          if (currBackend.getName().equals(backendType))
364            return currBackend;
365        
366        //Reject if backend type is not supported by our telescope
367        if (!telescope.getBackendTypes().contains(backendType))
368          throw new IllegalArgumentException("Backend type " + backendType +
369            " is not supported by this resource's telescope (" + telescope + ").");
370    
371        //This could throw exception.
372        CorrelatorConfiguration newBackend =
373          CorrelatorConfiguration.makeFor(backendType, antennaElectronics);
374        
375        backends.add(newBackend);
376        
377        return newBackend;
378      }
379      
380      /**
381       * Returns a list of the backends currently held by this resource.
382       * The returned list is not held directly by this resource, so changes to
383       * it will not be reflected herein.  The objects in the list, however,
384       * are the actual backends held by this resource, so changes to those
385       * will affect this resource.
386       * 
387       * @return a list of the backends currently held by this resource.
388       * 
389       * @see #getBackend(CorrelatorName)
390       */
391      public List<TelescopeBackend> getBackends()
392      {
393        return new ArrayList<TelescopeBackend>(backends);
394      }
395    
396      /**
397       * Removes from this resource the backend of the given type.
398       * 
399       * @param backendType
400       *   the type of backend to remove from this resource.
401       *   
402       * @return
403       *   the backend of the given type formerly held by this resource,
404       *   or <i>null</i> if this resource had no such backend at the
405       *   time this method was called.
406       */
407      public TelescopeBackend removeBackend(CorrelatorName backendType)
408      {
409        TelescopeBackend unwanted = null;
410        
411        for (TelescopeBackend backend : backends)
412        {
413          if (backend.getName().equals(backendType))
414          {
415            unwanted = backend;
416            break;
417          }
418        }
419        
420        if (unwanted != null)
421          backends.remove(unwanted);
422        
423        return unwanted;
424      }
425      
426      /**
427       * Removes all backends from this resource.
428       * @return
429       *   the list of backends formerly held by this resource.  The returned
430       *   list will never be <i>null</i> but could be empty.
431       */
432      public List<TelescopeBackend> removeBackends()
433      {
434        List<TelescopeBackend> unwanted =
435          new ArrayList<TelescopeBackend>(backends);
436        
437        backends.clear();
438        
439        return unwanted;
440      }
441      
442      //----------------------------------------------------------------------------
443      // Persistence Helpers
444      //----------------------------------------------------------------------------
445      //These private set/getAntennaElectronicsConfiguration methods are used
446      //by JAXB, and perhaps by Hibernate.  JAXB and Hibernate will also be
447      //told to work with the telescope variable directly, NOT through the
448      //setTelescope method.  This is because setTelescope, which is meant
449      //for "normal" clients, creates antennaElectronics based on the
450      //new telescope type.
451      //All this is done because client objects work with AntennaElectronics,
452      //but we persist that in the form of AntennaElectronicsConfiguration.
453      
454      private boolean fetchedAntennaElec = false;
455      private boolean fetchedBackends    = false;
456      
457      //JAXB use
458      @XmlElement
459      @SuppressWarnings("unused")
460      private void
461        setAntennaElectronicsConfiguration(AntennaElectronicsConfiguration config)
462      {
463        antennaElectronics = config.getTelescope().makeElectronics();
464        antennaElectronics.configureFrom(config);
465        fetchedAntennaElec = true;
466        
467        if (fetchedBackends)
468          connectBackendsToAntElec();
469      }
470      
471      //JAXB use
472      @SuppressWarnings("unused")
473      private AntennaElectronicsConfiguration getAntennaElectronicsConfiguration()
474      {
475        return antennaElectronics.getConfiguration();
476      }
477    
478      //Hibernate use
479      @SuppressWarnings("unused")
480      private void setAntennaElectronics(AntennaElectronics newElec)
481      {
482        antennaElectronics = newElec;
483        fetchedAntennaElec = true;
484        
485        if (fetchedBackends)
486          connectBackendsToAntElec();
487      }
488      
489      //Hibernate use (JAXB's trouble w/ lists means we can't share these methods any more)
490      @SuppressWarnings("unused")
491      private void setBackendList(List<TelescopeBackend> replacementList)
492      {
493        backends = replacementList;
494        fetchedBackends = true;
495        
496        if (fetchedAntennaElec)
497          connectBackendsToAntElec();
498      }
499      @SuppressWarnings("unused")
500      private List<TelescopeBackend> getBackendList()  { return backends; }
501      
502      //JAXB use
503      @XmlElementWrapper(name="backendElectronics")
504      @XmlElementRefs
505      (
506        {
507          @XmlElementRef(type=edu.nrao.sss.model.resource.evla.EvlaWidarConfiguration.class),
508          @XmlElementRef(type=edu.nrao.sss.model.resource.vla.VlaConfiguration.class)
509        }
510      )
511      @SuppressWarnings("unused")
512      private void setXmlBackendList(TelescopeBackend[] replacementList)
513      {
514        backends.clear();
515        backends.addAll(Arrays.asList(replacementList));
516        fetchedBackends = true;
517        
518        if (fetchedAntennaElec)
519          connectBackendsToAntElec();
520      }
521      
522      //JAXB & Hibernate use
523      @SuppressWarnings("unused")
524      private TelescopeBackend[] getXmlBackendList()
525      {
526        return backends.toArray(new TelescopeBackend[backends.size()]);
527      }
528      
529      private void connectBackendsToAntElec()
530      {
531        //In the unlikely event we have null electronics, use the default
532        if (antennaElectronics == null)
533        {
534          log.warn("antennaElectronics is NULL in connectBackendsToAntElec().");
535    
536          TelescopeType tt = (telescope == null) ? TelescopeType.getDefault() : telescope;
537          antennaElectronics = tt.makeElectronics();
538        }
539        
540        for (TelescopeBackend backend : backends)
541          backend.setSignalSource(antennaElectronics);
542        
543        //Reset fetch flags
544        fetchedAntennaElec = false;
545        fetchedBackends    = false;
546      }
547      
548      //============================================================================
549      // OTHER PROPERTIES
550      //============================================================================
551    
552      /**
553       * Returns a list of notes about this resource.
554       * Each note is free-form text with no particular structure.
555       * <p>
556       * This method returns the list actually held by this {@code Resource}, so
557       * any list manipulations may be performed by first fetching the list and
558       * then operating on it.</p>
559       * 
560       * @return a list of notes about this resource.
561       */
562      @XmlElementWrapper
563      @XmlElement(name="note")
564      public List<String> getNotes()
565      {
566        return notes;
567      }
568      
569      /** This is here for mechanisms that need setX/getX pairs, such as JAXB. */
570      @SuppressWarnings("unused")
571      private void setNotes(List<String> replacementList)
572      {
573        notes = (replacementList == null) ? new ArrayList<String>()
574                                          : replacementList;
575      }
576    
577      //============================================================================
578      // XML
579      //============================================================================
580    
581      /**
582       * Returns an XML representation of this resource.
583       * @return an XML representation of this resource.
584       * @throws JAXBException if anything goes wrong during the conversion to XML.
585       */
586      public String toXml() throws JAXBException
587      {
588        return JaxbUtility.getSharedInstance().objectToXmlString(this);
589      }
590      
591      /**
592       * Writes an XML representation of this resource to {@code writer}.
593       * @param writer the device to which XML is written.
594       * @throws JAXBException if anything goes wrong during the conversion to XML.
595       */
596      public void writeAsXmlTo(Writer writer) throws JAXBException
597      {
598        JaxbUtility.getSharedInstance().writeObjectAsXmlTo(writer, this, null);
599      }
600    
601      /**
602       * Creates a new resource from the XML data in the given file.
603       * 
604       * @param xmlFile the name of an XML file.  This method will attempt to locate
605       *                the file by using {@link Class#getResource(String)}.
606       *                
607       * @return a new resource from the XML data in the given file.
608       * 
609       * @throws FileNotFoundException if the XML file cannot be found.
610       * 
611       * @throws JAXBException if the schema file used (if any) is malformed, if
612       *           the XML file cannot be read, or if the XML file is not
613       *           schema-valid.
614       * 
615       * @throws XMLStreamException if there is a problem opening the XML file,
616       *           if the XML is not well-formed, or for some other
617       *           "unexpected processing conditions".
618       */
619      public static Resource fromXml(String xmlFile)
620        throws JAXBException, XMLStreamException, FileNotFoundException
621      {
622        return JaxbUtility.getSharedInstance()
623                          .xmlFileToObject(xmlFile, Resource.class);
624      }
625      
626      /**
627       * Creates a new resource based on the XML data read from {@code reader}.
628       * 
629       * @param reader the source of the XML data.
630       *               If this value is <i>null</i>, <i>null</i> is returned.
631       *               
632       * @return a new resource based on the XML data read from {@code reader}.
633       * 
634       * @throws XMLStreamException if the XML is not well-formed,
635       *           or for some other "unexpected processing conditions".
636       *           
637       * @throws JAXBException if anything else goes wrong during the
638       *           transformation.
639       */
640      public static Resource fromXml(Reader reader)
641        throws JAXBException, XMLStreamException
642      {
643        return JaxbUtility.getSharedInstance()
644                          .readObjectAsXmlFrom(reader, Resource.class, null);
645      }
646    
647      //============================================================================
648      // 
649      //============================================================================
650      
651      /**
652       *  Returns a resource that is a copy of this one.
653       *  <p>
654       *  If anything goes wrong during the cloning procedure,
655       *  a {@code RuntimeException} will be thrown.</p>
656       */
657      @Override
658      public Resource clone()
659      {
660        Resource clone = null;
661        
662        try
663        {
664          //This line takes care of the primitive & immutable fields properly
665          clone = (Resource)super.clone();
666          
667          //We do NOT want the clone to have the same ID as the original.
668          //The ID is here for the persistence layer; it is in charge of
669          //setting IDs.  To help it, we put the clone's ID in the uninitialized
670          //state.
671          clone.id = Identifiable.UNIDENTIFIED;
672          
673          clone.xmlId = "resource-" + UUID.randomUUID().toString();
674    
675          clone.createdOn     = new Date();
676          clone.lastUpdatedOn = clone.createdOn;
677          clone.notes         = new ArrayList<String>(this.notes);
678    
679          clone.scienceSpecification = this.scienceSpecification.clone();
680    
681          clone.antennaElectronics = clone.telescope.makeElectronics();
682          clone.antennaElectronics.configureFrom(
683            this.antennaElectronics.getConfiguration());
684          
685          clone.backends = new ArrayList<TelescopeBackend>();
686          for (TelescopeBackend backend : this.backends)
687          {
688            TelescopeBackend beClone = backend.clone();
689            beClone.setSignalSource(clone.antennaElectronics);
690            clone.backends.add(beClone);
691          }
692        }
693        catch (Exception ex)
694        {
695          throw new RuntimeException(ex);
696        }
697    
698        return clone;
699      }
700     
701      /** Returns <i>true</i> if {@code o} is equal to this resource. */
702      @Override
703      public boolean equals(Object o)
704      {
705        //Quick exit if o is this
706        if (o == this)
707          return true;
708        
709        //Quick exit if o is null
710        if (o == null)
711          return false;
712       
713        //Quick exit if classes are different
714        if (!o.getClass().equals(this.getClass()))
715          return false;
716       
717        //A safe cast if we got this far
718        Resource other = (Resource)o;
719        
720        //Attributes that we INTENTIONALLY DO NOT COMPARE:
721        //  id,
722        //  createdOn, createdBy, lastUpdatedOn, lastUpdatedBy
723    
724        if (!other.name.equals(this.name))
725          return false;
726    
727        if (!other.telescope.equals(this.telescope))
728          return false;
729        
730        if (!other.getAntennaElectronics().getConfiguration().equals(
731              this.getAntennaElectronics().getConfiguration()))
732          return false;
733        
734        if (!other.scienceSpecification.equals(this.scienceSpecification))
735          return false;
736        
737        //TODO
738        //Not yet sure whether we're going to institute value-equality for backends.
739        //For now we use a weak test -- if the lists are different sizes,
740        //the backends are diff.
741      //if (!other.backends.equals(this.backends))
742      //  return false;
743        if (other.backends.size() != this.backends.size())
744          return false;
745        
746        return true;
747      }
748      
749      //private boolean objectsAreEqual(Object thisOne, Object thatOne)
750      //{
751      //  return (thisOne == null) ? (thatOne == null) : thisOne.equals(thatOne);
752      //}
753    
754      /** Returns a hash code value for this resource. */
755      @Override
756      public int hashCode()
757      {
758        //Taken from the Effective Java book by Joshua Bloch.
759        //The constants 17 & 37 are arbitrary & carry no meaning.
760        int result = 17;
761        
762        //You MUST keep this method in sync w/ the equals method
763        
764        result = 37 * result + name.hashCode();
765        result = 37 * result + telescope.hashCode();
766        result = 37 * result + antennaElectronics.getConfiguration().hashCode();
767        result = 37 * result + backends.hashCode();
768        result = 37 * result + scienceSpecification.hashCode();
769    
770        return result;
771      }
772    
773      //============================================================================
774      // 
775      //============================================================================
776    
777      /*
778      public static void main(String[] args)
779      {
780        ResourceBuilder builder = new ResourceBuilder();
781        builder.makeResource("dummy", TelescopeType.EVLA);
782      }
783      */
784      /*
785      //For quick, manual, testing
786      public static void main(String[] args)
787      {
788        //Create an in-memory resource and marshal to XML
789        ResourceBuilder builder = new ResourceBuilder();
790        builder.setIdentifiers(true);
791        
792        Resource resource = builder.makeResource("Backend Test", null);
793        
794        try
795        {
796          System.out.println(resource.toXml());
797        }
798        catch (JAXBException ex)
799        {
800          System.out.println("Trouble w/ resource.toXml:");
801          System.out.println(ex.getMessage());
802          ex.printStackTrace();
803          
804          System.out.println("Attempting to write XML w/out schema verification:");
805          JaxbUtility.getSharedInstance().setLookForDefaultSchema(false);
806          try
807          {
808            System.out.println(resource.toXml());
809          }
810          catch (JAXBException ex2)
811          {
812            System.out.println("Still had trouble w/ resource.toXml.  Msg:");
813            System.out.println(ex.getMessage());
814            ex.printStackTrace();
815          }
816        }
817      }
818      */
819      /*
820      public static void main(String... args) throws Exception
821      {
822        java.io.File input =
823          new java.io.File("/export/home/calmer/dharland/JUNK/resource3.xml");
824        
825        Resource rsrc = Resource.fromXml(input.getAbsolutePath());
826        
827        rsrc.writeAsXmlTo(new java.io.PrintWriter(System.out));
828      }
829      */
830    }