View Javadoc

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