View Javadoc

1   package uk.ac.ebi.intenz.tools.export;
2   
3   import java.io.OutputStream;
4   import java.io.Serializable;
5   import java.math.BigInteger;
6   import java.net.URL;
7   import java.util.ArrayList;
8   import java.util.Collection;
9   import java.util.Collections;
10  import java.util.HashMap;
11  import java.util.Hashtable;
12  import java.util.Iterator;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.regex.Matcher;
16  import java.util.regex.Pattern;
17  
18  import javax.xml.XMLConstants;
19  import javax.xml.bind.JAXBContext;
20  import javax.xml.bind.JAXBElement;
21  import javax.xml.bind.JAXBException;
22  import javax.xml.bind.Marshaller;
23  import javax.xml.bind.annotation.XmlSchema;
24  import javax.xml.datatype.DatatypeConfigurationException;
25  import javax.xml.datatype.DatatypeFactory;
26  import javax.xml.validation.Schema;
27  import javax.xml.validation.SchemaFactory;
28  
29  import org.apache.commons.lang.StringEscapeUtils;
30  import org.apache.xml.serialize.OutputFormat;
31  import org.apache.xml.serialize.XMLSerializer;
32  import org.xml.sax.SAXException;
33  import org.xml_cml.schema.cml2.react.Cml;
34  import org.xml_cml.schema.cml2.react.Label;
35  
36  import uk.ac.ebi.biobabel.util.collections.OperatorSet;
37  import uk.ac.ebi.intenz.domain.constants.EnzymeNameQualifierConstant;
38  import uk.ac.ebi.intenz.domain.constants.EnzymeViewConstant;
39  import uk.ac.ebi.intenz.domain.constants.XrefDatabaseConstant;
40  import uk.ac.ebi.intenz.domain.enzyme.Cofactor;
41  import uk.ac.ebi.intenz.domain.enzyme.EnzymaticReactions;
42  import uk.ac.ebi.intenz.domain.enzyme.EnzymeClass;
43  import uk.ac.ebi.intenz.domain.enzyme.EnzymeComment;
44  import uk.ac.ebi.intenz.domain.enzyme.EnzymeCommissionNumber;
45  import uk.ac.ebi.intenz.domain.enzyme.EnzymeEntry;
46  import uk.ac.ebi.intenz.domain.enzyme.EnzymeLink;
47  import uk.ac.ebi.intenz.domain.enzyme.EnzymeName;
48  import uk.ac.ebi.intenz.domain.enzyme.EnzymeSubSubclass;
49  import uk.ac.ebi.intenz.domain.enzyme.EnzymeSubclass;
50  import uk.ac.ebi.intenz.domain.reference.Book;
51  import uk.ac.ebi.intenz.domain.reference.Journal;
52  import uk.ac.ebi.intenz.domain.reference.Patent;
53  import uk.ac.ebi.intenz.domain.reference.Reference;
54  import uk.ac.ebi.intenz.tools.sib.translator.XCharsASCIITranslator;
55  import uk.ac.ebi.intenz.xml.jaxb.BookType;
56  import uk.ac.ebi.intenz.xml.jaxb.CofactorType;
57  import uk.ac.ebi.intenz.xml.jaxb.DatabaseType;
58  import uk.ac.ebi.intenz.xml.jaxb.EcClassType;
59  import uk.ac.ebi.intenz.xml.jaxb.EcSubclassType;
60  import uk.ac.ebi.intenz.xml.jaxb.EcSubsubclassType;
61  import uk.ac.ebi.intenz.xml.jaxb.Editorial;
62  import uk.ac.ebi.intenz.xml.jaxb.EntryType;
63  import uk.ac.ebi.intenz.xml.jaxb.EnzymeNameQualifierType;
64  import uk.ac.ebi.intenz.xml.jaxb.EnzymeNameType;
65  import uk.ac.ebi.intenz.xml.jaxb.EnzymeType;
66  import uk.ac.ebi.intenz.xml.jaxb.Intenz;
67  import uk.ac.ebi.intenz.xml.jaxb.JournalType;
68  import uk.ac.ebi.intenz.xml.jaxb.LinkType;
69  import uk.ac.ebi.intenz.xml.jaxb.ObjectFactory;
70  import uk.ac.ebi.intenz.xml.jaxb.PatentType;
71  import uk.ac.ebi.intenz.xml.jaxb.ReactionType;
72  import uk.ac.ebi.intenz.xml.jaxb.ReferenceType;
73  import uk.ac.ebi.intenz.xml.jaxb.ViewType;
74  import uk.ac.ebi.intenz.xml.jaxb.ViewableType;
75  import uk.ac.ebi.intenz.xml.jaxb.XmlContentType;
76  import uk.ac.ebi.rhea.cml.CmlMapper;
77  import uk.ac.ebi.rhea.domain.Database;
78  import uk.ac.ebi.rhea.domain.Reaction;
79  
80  import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
81  
82  /**
83   * Exporter of IntEnz data in XML format.
84   * Currently, the following <i>flavours</i> of XML are available:
85   * <ul>
86   * 		<li>ASCII: the IntEnz fields with XML markup are translated
87   * 			into ASCII.</li>
88   * 		<li>XCHARS: those fields are left as are, but within <code>CDATA</code>
89   * 			sections.</li>
90   * </ul>
91   * The flavour can be changed using the
92   * {@link #setFlavour(uk.ac.ebi.intenz.tools.export.XmlExporter.Flavour) setFlavour}
93   * method.<br>
94   * Note that the <code>export</code> methods are synchronized in order to avoid changing
95   * the flavour in the middle of a dump.
96   * @author rafalcan
97   */
98  public class XmlExporter {
99  
100     public static enum Flavour { ASCII, XCHARS }
101     
102     /**
103      * Elements known to (possibly) contain XML markup.
104      */
105     static final String[] XML_CONTENT_ELEMENTS = new String[]{
106             "http://www.ebi.ac.uk/intenz^accepted_name",
107             "http://www.ebi.ac.uk/intenz^authors",
108             "http://www.ebi.ac.uk/intenz^cofactor",
109             "http://www.ebi.ac.uk/intenz^comment",
110             "http://www.ebi.ac.uk/intenz^description",
111             "http://www.ebi.ac.uk/intenz^editor",
112             "http://www.ebi.ac.uk/intenz^link",
113             "http://www.ebi.ac.uk/intenz^name",
114             "http://www.ebi.ac.uk/intenz^note",
115             "http://www.ebi.ac.uk/intenz^reaction",
116             "http://www.ebi.ac.uk/intenz^synonym",
117             "http://www.ebi.ac.uk/intenz^systematic_name",
118             "http://www.ebi.ac.uk/intenz^title"
119     };
120     
121     /**
122      * Pre-defined namespaces prefixes to be declared in the root element.
123      */
124     private final static Map<String, String> NS_PREFIXES =
125     	new Hashtable<String, String>();
126     /**
127      * Schema locations for predefined namespaces.
128      */
129     private final static Map<String, String> NS_SCHEMA_LOCATIONS =
130     	new Hashtable<String, String>();
131     static {
132     	NS_PREFIXES.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
133 		NS_PREFIXES.put("http://www.ebi.ac.uk/xchars", "x");
134 		NS_PREFIXES.put(Cml.class.getPackage().getAnnotation(XmlSchema.class)
135 				.namespace(), "cml");
136     }
137 
138     private Map<EnzymeNameQualifierConstant, EnzymeNameQualifierType> NAME_QUALIFIERS;
139     private Map<EnzymeViewConstant, ViewType> VIEWS;
140     private Map<XrefDatabaseConstant, DatabaseType> DATABASES;
141     private Map<String, Object> DESCRIPTIONS;
142     private Marshaller marshaller;
143     private ObjectFactory of;
144 	private Flavour flavour;
145     
146     public XmlExporter() throws JAXBException, SAXException{
147 		this.DESCRIPTIONS = null;
148 		this.flavour = Flavour.XCHARS;
149         this.of = new ObjectFactory();
150         buildNameQualifiersMap();
151         buildViewMap();
152         buildDbMap();
153         Package intenzPkg = Intenz.class.getPackage();
154 		JAXBContext context = JAXBContext.newInstance(
155         		intenzPkg.getName() + ":" + Cml.class.getPackage().getName());
156         marshaller = context.createMarshaller();
157         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
158         marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,
159         		intenzPkg.getAnnotation(XmlSchema.class).namespace()
160         		+ " "
161         		+ "ftp://ftp.ebi.ac.uk/pub/databases/intenz/xml/intenz.xsd");
162         marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper",
163         		new NamespacePrefixMapper(){
164 					@Override
165 					public String getPreferredPrefix(String arg0, String arg1, boolean arg2) {
166 						return NS_PREFIXES.get(arg0);
167 					}
168 					@Override
169 					public String[] getPreDeclaredNamespaceUris() {
170 						return NS_PREFIXES.keySet().toArray(
171 								new String[NS_PREFIXES.size()]);
172 					}
173 				});
174 		URL intenzXsdUrl =
175 				XmlExporter.class.getClassLoader().getResource("intenz.xsd");
176 		Schema intenzXsd =
177 				SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
178 					.newSchema(intenzXsdUrl);
179 		marshaller.setSchema(intenzXsd);
180     }
181     
182     private void buildNameQualifiersMap(){
183         NAME_QUALIFIERS = new HashMap<EnzymeNameQualifierConstant,
184         		EnzymeNameQualifierType>();
185         NAME_QUALIFIERS.put(EnzymeNameQualifierConstant.AMBIGUOUS,
186         		EnzymeNameQualifierType.AMBIGUOUS);
187         NAME_QUALIFIERS.put(EnzymeNameQualifierConstant.INCORRECT,
188         		EnzymeNameQualifierType.INCORRECT);
189         NAME_QUALIFIERS.put(EnzymeNameQualifierConstant.MISLEADING,
190         		EnzymeNameQualifierType.MISLEADING);
191         NAME_QUALIFIERS.put(EnzymeNameQualifierConstant.MISPRINT,
192         		EnzymeNameQualifierType.MISPRINT);
193         NAME_QUALIFIERS.put(EnzymeNameQualifierConstant.OBSOLETE,
194         		EnzymeNameQualifierType.OBSOLETE);
195     }
196     
197     private void buildViewMap(){
198         VIEWS = new HashMap<EnzymeViewConstant, ViewType>();
199         VIEWS.put(EnzymeViewConstant.INTENZ, ViewType.INTENZ_IUBMB_SIB);
200         VIEWS.put(EnzymeViewConstant.IUBMB, ViewType.IUBMB);
201         VIEWS.put(EnzymeViewConstant.SIB, ViewType.SIB);
202         VIEWS.put(EnzymeViewConstant.IUBMB_INTENZ, ViewType.INTENZ_IUBMB);
203         VIEWS.put(EnzymeViewConstant.SIB_INTENZ, ViewType.INTENZ_SIB);
204         VIEWS.put(EnzymeViewConstant.IUBMB_SIB, ViewType.IUBMB_SIB);
205     }
206     
207     private void buildDbMap(){
208         DATABASES = new HashMap<XrefDatabaseConstant, DatabaseType>();
209         DATABASES.put(XrefDatabaseConstant.BRENDA,DatabaseType.BRENDA);
210         DATABASES.put(XrefDatabaseConstant.CAS,DatabaseType.CAS);
211         DATABASES.put(XrefDatabaseConstant.DIAGRAM,DatabaseType.DIAGRAM);
212         DATABASES.put(XrefDatabaseConstant.ERGO,DatabaseType.ERGO);
213         DATABASES.put(XrefDatabaseConstant.ENZYME,DatabaseType.EX_PA_SY);
214         DATABASES.put(XrefDatabaseConstant.GO,DatabaseType.GO);
215         DATABASES.put(XrefDatabaseConstant.KEGG,DatabaseType.KEGG_ENZYME);
216         DATABASES.put(XrefDatabaseConstant.MEROPS,DatabaseType.MEROPS);
217         DATABASES.put(XrefDatabaseConstant.MIM,DatabaseType.MIM);
218         DATABASES.put(XrefDatabaseConstant.NIST74,DatabaseType.NIST_74);
219         DATABASES.put(XrefDatabaseConstant.PROSITE,DatabaseType.PROSITE);
220         DATABASES.put(XrefDatabaseConstant.UMBBD,DatabaseType.UM_BBD);
221         DATABASES.put(XrefDatabaseConstant.SWISSPROT,DatabaseType.UNI_PROT);
222         DATABASES.put(XrefDatabaseConstant.WIT,DatabaseType.WIT);
223 		DATABASES = Collections.unmodifiableMap(DATABASES);
224     }
225 
226     public void setDescriptions(Map<String, Object> descriptions){
227 		this.DESCRIPTIONS = Collections.unmodifiableMap(descriptions);
228 	}
229 
230 	public void setFlavour(Flavour flavour){
231 		this.flavour = flavour;
232 	}
233 
234 	/**
235 	 * Exports one enzyme entry as IntEnzXML.
236 	 * @param entry the enzyme entry to export.
237 	 * @param release the IntEnz release number to mention in the exported XML.
238 	 * @param relDate the IntEnz release date to mention in the exported XML.
239 	 * @param os the OutputStream to write the XML to.
240 	 * @throws Exception
241 	 */
242     public void export(EnzymeEntry entry, String release,
243             String relDate, OutputStream os) throws Exception {
244         export(Collections.singletonList(entry), release, relDate, os);
245     }
246     
247     /**
248      * Exports a list of enzymes as IntEnzXML.
249      * @param entries the entries to export.
250 	 * @param release the IntEnz release number to mention in the exported XML.
251 	 * @param relDate the IntEnz release date to mention in the exported XML.
252 	 * @param os the OutputStream to write the XML to.
253      * @throws Exception
254      */
255     public void export(List<EnzymeEntry> entries, String release,
256             String relDate, OutputStream os) throws Exception{
257         Intenz intenz = of.createIntenz();
258         intenz.setRelease(BigInteger.valueOf(Long.valueOf(release)));
259         intenz.setDate(DatatypeFactory.newInstance().newXMLGregorianCalendar(relDate));
260         for (EnzymeEntry entry : entries) {
261             int ec1 = entry.getEc().getEc1();
262             int ec2 = entry.getEc().getEc2();
263             int ec3 = entry.getEc().getEc3();
264             
265             EcClassType clazz = getClazz(intenz, ec1);
266             EcSubclassType subClazz = getSubClazz(clazz, ec1, ec2);
267             EcSubsubclassType subSubClazz = getSubSubClazz(subClazz, ec1, ec2, ec3);
268             
269             EntryType jaxbEntry = getJaxbEntry(entry);
270             subSubClazz.getEnzyme().add(jaxbEntry);
271         }
272 //        marshaller.marshal(intenz, os);
273         marshaller.marshal(intenz, getXMLSerializer(os));
274     }
275     
276     private EcClassType getClazz(Intenz intenz, int ec1) {
277         for (EcClassType c : intenz.getEcClass()) {
278             if (c.getEc1().intValue() == ec1) return c;
279         }
280         EcClassType clazz = of.createEcClassType();
281         clazz.setEc1(BigInteger.valueOf(ec1));
282         // Only if we have (need) descriptions:
283         if (DESCRIPTIONS != null){
284             EnzymeClass c = (EnzymeClass) DESCRIPTIONS.get(String.valueOf(ec1));
285             if (c.getName() != null && c.getName().length() > 0){
286                 XmlContentType name = of.createXmlContentType();
287 				name.getContent().add(getFlavoured(c.getName()));
288                 clazz.setName(name);
289             }
290             if (c.getDescription() != null && c.getDescription().length() > 0){
291                 XmlContentType cDescription = of.createXmlContentType();
292 				cDescription.getContent().add(getFlavoured(c.getDescription().trim()));
293                 clazz.setDescription(cDescription);
294             }
295         }
296         intenz.getEcClass().add(clazz);
297         return clazz;
298     }
299     
300     private EcSubclassType getSubClazz(EcClassType clazz, int ec1, int ec2){
301         for (EcSubclassType sc : clazz.getEcSubclass()){
302             if (sc.getEc2().intValue() == ec2) return sc;
303         }
304         EcSubclassType subClazz = of.createEcSubclassType();
305         subClazz.setEc2(BigInteger.valueOf(ec2));
306         // Only if we have (need) descriptions:
307         if (DESCRIPTIONS != null){
308             EnzymeSubclass sc = (EnzymeSubclass) DESCRIPTIONS.get(ec1+"."+ec2);
309             if (sc.getName() != null && sc.getName().length() > 0){
310                 XmlContentType name = of.createXmlContentType();
311                 name.getContent().add(getFlavoured(sc.getName()));
312                 subClazz.setName(name);
313             }
314             if (sc.getDescription() != null && sc.getDescription().length() > 0){
315                 XmlContentType scDescription = of.createXmlContentType();
316                 scDescription.getContent().add(getFlavoured(sc.getDescription().trim()));
317                 subClazz.setDescription(scDescription);
318             }
319         }
320         clazz.getEcSubclass().add(subClazz);
321         return subClazz;
322     }
323     
324     private EcSubsubclassType getSubSubClazz(EcSubclassType subClazz, int ec1, int ec2, int ec3){
325         for (EcSubsubclassType ssc : subClazz.getEcSubSubclass()){
326             if (ssc.getEc3().intValue() == ec3) return ssc;
327         }
328         EcSubsubclassType subSubClazz = of.createEcSubsubclassType();
329         subSubClazz.setEc3(BigInteger.valueOf(ec3));
330         // Only if we have (need) descriptions:
331         if (DESCRIPTIONS != null){
332             EnzymeSubSubclass ssc = (EnzymeSubSubclass) DESCRIPTIONS.get(ec1+"."+ec2+"."+ec3);
333             if (ssc.getName() != null && ssc.getName().length() > 0){
334                 XmlContentType name = of.createXmlContentType();
335                 name.getContent().add(getFlavoured(ssc.getName()));
336                 subSubClazz.setName(name);
337             }
338             if (ssc.getDescription() != null && ssc.getDescription().length() > 0){
339                 XmlContentType sscDescription = of.createXmlContentType();
340                 sscDescription.getContent().add(getFlavoured(ssc.getDescription().trim()));
341                 subSubClazz.setDescription(sscDescription);
342             }
343         }
344         subClazz.getEcSubSubclass().add(subSubClazz);
345         return subSubClazz;
346     }
347 	
348     /**
349 	 * Processes a <code>String</code> to adapt it to the particular flavour
350 	 * of this exporter. This method should be used when populating the
351 	 * elements listed in {@link #XML_CONTENT_ELEMENTS}.
352 	 *
353 	 * @param s a <code>String</code> value
354 	 * @return a <code>String</code> value
355 	 */
356 	private String getFlavoured(String s){
357 		String flavoured = null;
358 		switch (flavour){
359 		case ASCII:
360 			flavoured = XCharsASCIITranslator.getInstance().toASCII(s, true, true);
361 			break;
362 		case XCHARS:
363             Pattern p = Pattern.compile(" <?[?=]>? ");
364             Matcher m = p.matcher(s);
365             flavoured = s;
366             while (m.find()){
367             	String dirSign = m.group(0);
368             	String escaped = dirSign.replaceAll("<","&lt;").replaceAll(">","&gt;");
369             	flavoured = flavoured.replace(dirSign, escaped);
370             }
371 			// Add xchars namespace prefix:
372 			flavoured = flavoured.replaceAll("(</?)(?! |-|/)","$1x:");
373 			break;
374 		}
375 		return flavoured;
376 	}
377 
378     private XMLSerializer getXMLSerializer(OutputStream os) {
379         OutputFormat outFormat = new OutputFormat();
380 		switch (flavour){
381 		case ASCII:
382 			break;
383 		case XCHARS:
384 			// If we want CDATA:
385 //			outFormat.setCDataElements(XML_CONTENT_ELEMENTS);
386 			// If we don't want CDATA:
387 			outFormat.setNonEscapingElements(XML_CONTENT_ELEMENTS);
388 			break;
389 		}
390 // 		outFormat.setPreserveSpace(true);
391         outFormat.setIndenting(true);
392 //      outFormat.setIndent(4);
393 		outFormat.setOmitDocumentType(false);
394         
395         XMLSerializer serializer = new XMLSerializer(outFormat);
396         serializer.setOutputByteStream(os);
397         serializer.setNamespaces(true);
398         
399         return serializer;
400     }
401 
402     private EntryType getJaxbEntry(EnzymeEntry entry)
403     throws DatatypeConfigurationException {
404         EntryType jaxbEntry = of.createEntryType();
405         // EC number:
406         jaxbEntry.setEc("EC ".concat(entry.getEc().toString()));
407         jaxbEntry.setEc4(BigInteger.valueOf(entry.getEc().getEc4()));
408         jaxbEntry.setPreliminary(EnzymeCommissionNumber.isPreliminary(
409         		entry.getEc().toString()));
410         
411         if (entry.getHistory().isDeletedRootNode()){
412             jaxbEntry.setDeleted(of.createInactiveStatusType());
413             String note = getInactiveEntryNote(entry);
414             if (note.length() > 1)
415                 jaxbEntry.getDeleted().setNote(getFlavoured(note));
416         } else if (entry.getHistory().isTransferredRootNode()){
417             jaxbEntry.setTransferred(of.createInactiveStatusType());
418             String note = getInactiveEntryNote(entry);
419             if (note.length() > 1)
420                 jaxbEntry.getTransferred().setNote(getFlavoured(note));
421         } else {
422             setNames(entry, jaxbEntry, of);
423             setReactions(entry, jaxbEntry, of);
424             setCofactors(entry, jaxbEntry, of);
425             setComments(entry, jaxbEntry, of);
426             setLinks(entry, jaxbEntry, of);
427             setReferences(entry, jaxbEntry, of);
428         }
429         
430         // History:
431         jaxbEntry.setHistory(entry.getHistory().getRootNode().getHistoryLine());
432         
433         return jaxbEntry;
434     }
435 
436     /**
437      * @param entry
438      * @param jaxbEnzyme
439      * @param of
440      * @throws DatatypeConfigurationException
441      */
442     private void setReferences(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) throws DatatypeConfigurationException {
443         // References:
444         for (Object o : entry.getReferences()) {
445             if (jaxbEnzyme.getReferences() == null)
446                 jaxbEnzyme.setReferences(of.createReferences());
447             Reference ref = (Reference) o;
448             ReferenceType jaxbRef = null;
449             if (ref instanceof Book){
450                 Book book = (Book) ref;
451                 BookType jaxbBook = of.createBookType();
452                 Editorial editorial = of.createEditorial();
453                 editorial.setContent(book.getPublisher());
454                 editorial.setPlace(book.getPublisherPlace());
455                 jaxbBook.setEditorial(editorial);
456                 jaxbBook.setEdition(book.getEdition(true));
457                 jaxbBook.setEditor(getFlavoured(book.getEditor(true)));
458                 jaxbBook.setName(getFlavoured(book.getPubName()));
459                 jaxbBook.setVolume(book.getVolume());
460                 jaxbBook.setFirstPage(book.getFirstPage());
461                 jaxbBook.setLastPage(book.getLastPage());
462                 jaxbRef = jaxbBook;
463             } else if (ref instanceof Journal){
464                 Journal journal = (Journal) ref;
465                 JournalType jaxbJournal = of.createJournalType();
466                 jaxbJournal.setName(getFlavoured(journal.getPubName()));
467                 jaxbJournal.setVolume(journal.getVolume());
468                 jaxbJournal.setFirstPage(journal.getFirstPage());
469                 jaxbJournal.setLastPage(journal.getLastPage());
470                 if (journal.getMedlineId() != null && journal.getMedlineId().length() > 0)
471                     jaxbJournal.setMedline(journal.getMedlineId());
472                 if (journal.getPubMedId() != null && journal.getPubMedId().length() > 0)
473                     jaxbJournal.setPubmed(journal.getPubMedId());
474                 jaxbRef = jaxbJournal;
475             } else if (ref instanceof Patent){
476                 Patent patent = (Patent) ref;
477                 PatentType jaxbPatent = of.createPatentType();
478                 jaxbPatent.setNumber(patent.getPatentNumber());
479                 jaxbRef = jaxbPatent;
480             }
481             jaxbRef.setAuthors(getFlavoured(ref.getAuthors()));
482             jaxbRef.setTitle(getFlavoured(ref.getTitle()));
483             jaxbRef.setYear(DatatypeFactory.newInstance().newXMLGregorianCalendar(ref.getYear()));
484             jaxbRef.setView(VIEWS.get(ref.getView()));
485             jaxbEnzyme.getReferences().getBookOrJournalOrPatent().add(jaxbRef);
486         }
487     }
488 
489     /**
490      * @param entry
491      * @param jaxbEnzyme
492      * @param of
493      */
494     private void setLinks(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) {
495         // Links:
496         for (Object o : entry.getLinks()) {
497             EnzymeLink link = (EnzymeLink) o;
498             if (EnzymeLink.isStaticLink(link.getXrefDatabaseConstant()))
499                 continue;
500             if (jaxbEnzyme.getLinks() == null)
501                 jaxbEnzyme.setLinks(of.createLinks());
502             LinkType jaxbLink = of.createLinkType();
503             jaxbLink.setDb(DATABASES.get(link.getXrefDatabaseConstant()));
504             if (link.getXrefDatabaseConstant().equals(XrefDatabaseConstant.DIAGRAM)){
505             	jaxbLink.setHref(link.getSpecificUrl());
506             } else if (link.getXrefDatabaseConstant().equals(XrefDatabaseConstant.MEROPS)){
507                 String meropsId = link.getSpecificUrl().substring(link.getSpecificUrl().indexOf("id=")+3);
508                 jaxbLink.setAccessionNumber(meropsId);
509             	jaxbLink.setHref(link.getSpecificUrl());
510             } else {
511                 jaxbLink.setAccessionNumber(link.getAccession());
512                 if (link.getXrefDatabaseConstant().getUrl().length() > 0){
513                     jaxbLink.setHref(link.getXrefDatabaseConstant().getUrl()+link.getAccession());
514                 }
515             }
516             if (link.getDataComment() != null)
517                 jaxbLink.setComment(link.getDataComment());
518             jaxbLink.getContent().add(
519             		StringEscapeUtils.escapeXml(link.getName()));
520             jaxbLink.setView(VIEWS.get(link.getView()));
521             jaxbEnzyme.getLinks().getLink().add(jaxbLink);
522         }
523         // Cross-references to Rhea:
524         EnzymaticReactions er = entry.getEnzymaticReactions();
525         if (er != null && er.size() > 0){
526             for (int i = 0; i < er.size(); i++) {
527                 Reaction reaction = er.getReaction(i);
528                 if (reaction.getId().equals(Reaction.NO_ID_ASSIGNED)
529                 		|| !reaction.getStatus().isPublic()){
530                 	continue;
531                 }
532                 if (jaxbEnzyme.getLinks() == null)
533                     jaxbEnzyme.setLinks(of.createLinks());
534                 LinkType rheaLink = of.createLinkType();
535                 rheaLink.setDb(DatabaseType.RHEA);
536                 rheaLink.setAccessionNumber(reaction.getId().toString());
537                 rheaLink.setView(ViewType.INTENZ);
538                 rheaLink.setHref(Database.RHEA.getEntryUrl(reaction.getId().toString()));
539                 rheaLink.getContent().add(getFlavoured(reaction.getTextualRepresentation()));
540                 jaxbEnzyme.getLinks().getLink().add(rheaLink);
541             }
542         }
543     }
544 
545     /**
546      * @param entry
547      * @param jaxbEnzyme
548      * @param of
549      */
550     private void setComments(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) {
551         // Comments:
552         for (Object o : entry.getComments()) {
553             if (jaxbEnzyme.getComments() == null)
554                 jaxbEnzyme.setComments(of.createComments());
555             EnzymeComment comment = (EnzymeComment) o;
556             ViewableType jaxbComment = of.createViewableType();
557             jaxbComment.getContent().add(getFlavoured(comment.getCommentText()));
558             jaxbComment.setView(VIEWS.get(comment.getView()));
559             jaxbEnzyme.getComments().getComment().add(jaxbComment);
560         }
561     }
562 
563     /**
564      * @param entry
565      * @param jaxbEnzyme
566      * @param of
567      */
568     private void setCofactors(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) {
569         // Cofactors:
570     	
571         for (Iterator<?> it = entry.getCofactors().iterator(); it.hasNext();){
572         	Object cofactor = it.next();
573             if (jaxbEnzyme.getCofactors() == null)
574                 jaxbEnzyme.setCofactors(of.createCofactors());
575 			if (cofactor instanceof Cofactor){
576 				JAXBElement<CofactorType> jaxbCofactor =
577 						cofactor2jaxb(of, (Cofactor) cofactor);
578 	            jaxbEnzyme.getCofactors().getContent().add(jaxbCofactor);
579 			} else {
580 				OperatorSet os = (OperatorSet) cofactor;
581 				jaxbEnzyme.getCofactors().getContent()
582 						.addAll(cofactors2jaxb(of, os));
583 			}
584 			if (it.hasNext()){
585 				jaxbEnzyme.getCofactors().getContent().add(" and ");
586 			}
587         }
588     }
589 
590 	/**
591 	 * Creates a JAXB cofactor from an IntEnz cofactor.
592 	 * @param of an object factory to create JAXB objects.
593 	 * @param cofactor an IntEnz cofactor.
594 	 * @return a JAXB cofactor.
595 	 */
596 	private JAXBElement<CofactorType> cofactor2jaxb(ObjectFactory of, Cofactor cofactor) {
597 		CofactorType cofactorType = of.createCofactorType();
598 		cofactorType.getContent()
599 				.add(getFlavoured(cofactor.getCompound().getName()));
600 		cofactorType.setView(VIEWS.get(cofactor.getView()));
601 		cofactorType.setDb(cofactor.getCompound().getXref().getDatabaseName());
602 		cofactorType.setAccession(cofactor.getCompound().getAccession());
603 		return of.createCofactor(cofactorType);
604 	}
605 
606     private Collection<Serializable> cofactors2jaxb(ObjectFactory of, OperatorSet os) {
607     	Collection<Serializable> jaxbCofactors =
608     			new ArrayList<Serializable>();
609     	jaxbCofactors.add("(");
610 		for (Iterator<?> it = os.iterator(); it.hasNext();){
611 			Object o = it.next();
612 			if (o instanceof Cofactor){
613 				Cofactor cofactor = (Cofactor) o;
614 				jaxbCofactors.add(cofactor2jaxb(of, cofactor));
615 			} else {
616 				jaxbCofactors.addAll(cofactors2jaxb(of, (OperatorSet) o));
617 			}
618 			if (it.hasNext()) jaxbCofactors.add(" "
619 					+ os.getOperator().toLowerCase().replaceAll("\\d", "")
620 					+ " ");
621 		}
622     	jaxbCofactors.add(")");
623 		return jaxbCofactors;
624 	}
625 
626 	/**
627      * @param entry
628      * @param jaxbEnzyme
629      * @param of
630      */
631     private void setReactions(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) {
632         // Reactions:
633         EnzymaticReactions er = entry.getEnzymaticReactions();
634         for (int i = 0; i < er.size(); i++) {
635             Reaction reaction = er.getReaction(i);
636             Object xmlReaction = null;
637 			if (reaction.getId() > Reaction.NO_ID_ASSIGNED){
638 				// Rhea reaction:
639 				if (!reaction.getStatus().isPublic()) continue;
640 				org.xml_cml.schema.cml2.react.Reaction cmlReaction =
641 						new CmlMapper().mapRheaReaction(reaction);
642 				// As of 2012-11-13, Rhea reactions are only used in IntEnz view
643 				Label viewLabel = new Label();
644 				viewLabel.setValue("view:" + ViewType.INTENZ);
645 				cmlReaction.getLabel().add(viewLabel);
646 				Label iubmbLabel = new Label();
647 				iubmbLabel.setValue("iubmb:" + er.getReactionIubmbFlag(i));
648 				cmlReaction.getLabel().add(iubmbLabel);
649 				xmlReaction = cmlReaction;
650 			} else {
651 				// Plain text reaction:
652 	            ReactionType jaxbReaction = of.createReactionType();
653 	            jaxbReaction.getContent().add(getFlavoured(reaction.getTextualRepresentation()));
654 	            jaxbReaction.setView(VIEWS.get(er.getReactionView(i)));
655 	            jaxbReaction.setIubmb(er.getReactionIubmbFlag(i));
656 	            xmlReaction = jaxbReaction;
657 			}
658             if (jaxbEnzyme.getReactions() == null)
659                 jaxbEnzyme.setReactions(of.createReactions());
660 
661             jaxbEnzyme.getReactions().getReactionOrReaction().add(xmlReaction);
662         }
663     }
664 
665     /**
666      * @param entry
667      * @param jaxbEnzyme
668      * @param of
669      */
670     private void setNames(EnzymeEntry entry, EnzymeType jaxbEnzyme, ObjectFactory of) {
671         // Names:
672         for (Object o : entry.getCommonNames()) {
673             EnzymeName commonName = (EnzymeName) o;
674             EnzymeNameType jaxbComName = getJaxbEnzymeName(of, commonName);
675             jaxbEnzyme.getAcceptedName().add(jaxbComName);
676         }
677         EnzymeName sysName = entry.getSystematicName();
678         if (sysName != null && sysName.getName().length() > 0){
679             EnzymeNameType jaxbSysName = getJaxbEnzymeName(of, sysName);
680             jaxbEnzyme.setSystematicName(jaxbSysName);
681         }
682         for (Object o : entry.getSynonyms()){
683             if (jaxbEnzyme.getSynonyms() == null)
684                 jaxbEnzyme.setSynonyms(of.createSynonyms());
685             EnzymeName synonym = (EnzymeName) o;
686             EnzymeNameType jaxbSynonym = getJaxbEnzymeName(of, synonym);
687             jaxbEnzyme.getSynonyms().getSynonym().add(jaxbSynonym);
688         }
689     }
690 
691     /**
692      * @param entry
693      * @return
694      */
695     private String getInactiveEntryNote(EnzymeEntry entry) {
696         StringBuffer note = new StringBuffer();
697         String entryName = entry.getCommonName(EnzymeViewConstant.INTENZ).getName();
698         String historyNote = entry.getHistory().getLatestHistoryEventOfRoot().getNote();
699         note.append(entryName);
700         if (entryName.length() > 0 && historyNote.length() > 0) note.append(". ");
701         note.append(historyNote);
702         return note.toString();
703     }
704 
705     /**
706      * @param of
707      * @param name
708      * @return
709      */
710     private EnzymeNameType getJaxbEnzymeName(ObjectFactory of, EnzymeName name) {
711         EnzymeNameType jaxbName = of.createEnzymeNameType();
712         jaxbName.getContent().add(getFlavoured(name.getName()));
713         jaxbName.setQualifier(NAME_QUALIFIERS.get(name.getQualifier()));
714         jaxbName.setView(VIEWS.get(name.getView()));
715         return jaxbName;
716     }
717 
718 }