001/* 
002 * Copyright 2018 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V..
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.isas.mztab2.io.serialization;
017
018import com.fasterxml.jackson.core.JsonGenerator;
019import com.fasterxml.jackson.databind.SerializerProvider;
020import com.fasterxml.jackson.databind.ser.std.StdSerializer;
021import static de.isas.mztab2.io.serialization.Serializers.addIndexedLine;
022import static de.isas.mztab2.io.serialization.Serializers.addLine;
023import static de.isas.mztab2.io.serialization.Serializers.addLineWithMetadataProperty;
024import static de.isas.mztab2.io.serialization.Serializers.addLineWithParameters;
025import de.isas.mztab2.model.Assay;
026import de.isas.mztab2.model.CV;
027import de.isas.mztab2.model.Contact;
028import de.isas.mztab2.model.Database;
029import de.isas.mztab2.model.IndexedElement;
030import de.isas.mztab2.model.Instrument;
031import de.isas.mztab2.model.Metadata;
032import de.isas.mztab2.model.MsRun;
033import de.isas.mztab2.model.Parameter;
034import de.isas.mztab2.model.Publication;
035import de.isas.mztab2.model.Sample;
036import de.isas.mztab2.model.SampleProcessing;
037import de.isas.mztab2.model.Software;
038import de.isas.mztab2.model.StudyVariable;
039import de.isas.mztab2.model.Uri;
040import java.io.IOException;
041import java.util.Arrays;
042import java.util.Comparator;
043import java.util.List;
044import lombok.extern.slf4j.Slf4j;
045import uk.ac.ebi.pride.jmztab2.model.MZTabConstants;
046import uk.ac.ebi.pride.jmztab2.model.MetadataElement;
047import uk.ac.ebi.pride.jmztab2.model.MetadataProperty;
048import uk.ac.ebi.pride.jmztab2.model.Section;
049
050/**
051 * <p>
052 * MetadataSerializer class. Implements a custom, partially delegating serializer for {@link de.isas.mztab2.model.Metadata} objects 
053 * based on Jackson CSV.</p>
054 *
055 * @author nilshoffmann
056 *
057 */
058@Slf4j
059public class MetadataSerializer extends StdSerializer<Metadata> {
060
061    /**
062     * <p>
063     * Constructor for MetadataSerializer.</p>
064     */
065    public MetadataSerializer() {
066        this(null);
067    }
068
069    /**
070     * <p>
071     * Constructor for MetadataSerializer.</p>
072     *
073     * @param t a {@link java.lang.Class} object.
074     */
075    public MetadataSerializer(Class<Metadata> t) {
076        super(t);
077    }
078
079    /**
080     * <p>
081     * Serialize a list of Parameters for the provided metadata element.</p>
082     *
083     * @param list a {@link java.util.List} object.
084     * @param mtdElement a
085     * {@link uk.ac.ebi.pride.jmztab2.model.MetadataElement} object.
086     * @param jg a {@link com.fasterxml.jackson.core.JsonGenerator} object.
087     * @param sp a {@link com.fasterxml.jackson.databind.SerializerProvider}
088     * object.
089     * @param comparator a {@link java.util.Comparator} object.
090     * @param <T> a T object.
091     */
092    public static <T extends IndexedElement> void serializeListWithMetadataElement(
093        List<T> list, MetadataElement mtdElement, JsonGenerator jg,
094        SerializerProvider sp, Comparator<? super T> comparator) {
095        list.stream().
096            sorted(comparator).
097            forEach((object) ->
098            {
099                if (object != null) {
100                    addIndexedLine(jg, sp, Section.Metadata.getPrefix(),
101                        mtdElement.getName() + "[" + object.getId() + "]",
102                        object);
103                } else {
104                    throw new NullPointerException(
105                        "Object in list for metadata element " + mtdElement.
106                            getName() + " must not be null!");
107                }
108            });
109    }
110
111    /**
112     * <p>
113     * serializeList.</p>
114     *
115     * @param list a {@link java.util.List} object.
116     * @param jg a {@link com.fasterxml.jackson.core.JsonGenerator} object.
117     * @param sp a {@link com.fasterxml.jackson.databind.SerializerProvider}
118     * object.
119     * @param comparator a {@link java.util.Comparator} object.
120     * @param <T> a T object.
121     */
122    public static <T> void serializeList(List<T> list, JsonGenerator jg,
123        SerializerProvider sp, Comparator<? super T> comparator) {
124        list.stream().
125            sorted(comparator).
126            forEach((object) ->
127            {
128                serializeObject(object, jg, sp);
129            });
130    }
131
132    /**
133     * <p>
134     * serializeObject.</p>
135     *
136     * @param object a {@link java.lang.Object} object.
137     * @param jg a {@link com.fasterxml.jackson.core.JsonGenerator} object.
138     * @param sp a {@link com.fasterxml.jackson.databind.SerializerProvider}
139     * object.
140     */
141    public static void serializeObject(Object object, JsonGenerator jg,
142        SerializerProvider sp) {
143        try {
144            
145                log.debug(
146                    "Serializing element " + Serializers.
147                        getElementName(object).
148                        orElse("undefined"));
149            sp.findValueSerializer(object.getClass()).
150                serialize(object, jg, sp);
151        } catch (IOException ex) {
152                log.error("Caught IO exception while trying to serialize "+object, ex);
153        }
154    }
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public void serialize(Metadata t, JsonGenerator jg, SerializerProvider sp) throws IOException {
161        if (t != null) {
162            String prefix = t.getPrefix().
163                name();
164            if(t.getMzTabVersion()==null || t.getMzTabVersion().isEmpty()) {
165                t.setMzTabVersion(MZTabConstants.VERSION_MZTAB_M);
166            }
167            addLine(jg, prefix, Metadata.Properties.mzTabVersion.getPropertyName(), t.getMzTabVersion());
168            addLine(jg, prefix, Metadata.Properties.mzTabID.getPropertyName(), t.
169                getMzTabID());
170            addLine(jg, prefix, Metadata.Properties.title.getPropertyName(), t.
171                getTitle());
172            addLine(jg, prefix, Metadata.Properties.description.getPropertyName(), t.
173                getDescription());
174            //contacts
175            if (t.getContact() != null) {
176                serializeList(t.getContact(), jg, sp, Comparator.comparing(
177                    Contact::getId,
178                    Comparator.nullsFirst(Comparator.naturalOrder())
179                ));
180            } else {
181                
182                    log.debug( "Contacts are null!");
183            }
184            //publications
185            if (t.getPublication() != null) {
186                serializeList(t.getPublication(), jg, sp, Comparator.comparing(
187                    Publication::getId,
188                    Comparator.nullsFirst(Comparator.naturalOrder())
189                ));
190            } else {
191                
192                    log.debug( "Publications are null!");
193            }
194            //file uri
195            if (t.getUri() != null) {
196                serializeListWithMetadataElement(t.getUri(),
197                    MetadataElement.URI, jg, sp, Comparator.comparing(
198                        Uri::getId,
199                        Comparator.nullsFirst(Comparator.naturalOrder())));
200            } else {
201                
202                    log.debug( "External Study is null!");
203            }
204            //external study uri
205            if (t.getExternalStudyUri() != null) {
206                serializeListWithMetadataElement(t.getExternalStudyUri(),
207                    MetadataElement.EXTERNAL_STUDY_URI, jg, sp, Comparator.
208                        comparing(
209                            Uri::getId,
210                            Comparator.nullsFirst(Comparator.naturalOrder())));
211            } else {
212                
213                    log.debug( "External Study is null!");
214            }
215            //instruments
216            if (t.getInstrument() != null) {
217                serializeList(
218                    t.getInstrument(), jg, sp, Comparator.comparing(
219                    Instrument::getId,
220                    Comparator.nullsFirst(Comparator.naturalOrder())
221                ));
222            } else {
223                
224                    log.debug( "Instruments are null!");
225            }
226            //quantification method
227            if (t.getQuantificationMethod() != null) {
228                addLineWithParameters(jg, prefix, "quantification_method",
229                    Arrays.asList(t.getQuantificationMethod()));
230            } else {
231                
232                    log.debug( "Quantification method is null!");
233            }
234            //sample
235            if (t.getSample() != null) {
236                serializeList(
237                    t.getSample(), jg, sp, Comparator.comparing(Sample::getId,
238                    Comparator.nullsFirst(Comparator.naturalOrder())
239                ));
240            } else {
241                
242                    log.debug( "Samples are null!");
243            }
244            //sample processing
245            if (t.getSampleProcessing() != null) {
246                serializeList(
247                    t.getSampleProcessing(), jg, sp, Comparator.comparing(
248                    SampleProcessing::getId,
249                    Comparator.nullsFirst(Comparator.naturalOrder())
250                ));
251            } else {
252                
253                    log.debug( "Sample processing is null!");
254            }
255            //software
256            if (t.getSoftware() != null) {
257                serializeList(
258                    t.getSoftware(), jg, sp, Comparator.comparing(
259                    Software::getId,
260                    Comparator.nullsFirst(Comparator.naturalOrder())
261                ));
262            } else {
263                
264                    log.debug( "Software is null!");
265            }
266            //derivatization agent
267            if (t.getDerivatizationAgent() != null) {
268                serializeListWithMetadataElement(t.getDerivatizationAgent(),
269                    MetadataElement.DERIVATIZATION_AGENT, jg, sp, Comparator.
270                        comparing(
271                            Parameter::getId,
272                            Comparator.nullsFirst(Comparator.naturalOrder())
273                        ));
274            } else {
275                
276                    log.debug( "Derivatization agent is null!");
277            }
278            //ms run
279            if (t.getMsRun() != null) {
280                serializeList(t.getMsRun(), jg, sp, Comparator.comparing(
281                    MsRun::getId,
282                    Comparator.nullsFirst(Comparator.naturalOrder())
283                ));
284            } else {
285                
286                    log.debug( "MS runs are null!");
287            }
288            //assay
289            if (t.getAssay() != null) {
290                serializeList(t.getAssay(), jg, sp, Comparator.comparing(
291                    Assay::getId,
292                    Comparator.nullsFirst(Comparator.naturalOrder())
293                ));
294            } else {
295                
296                    log.debug( "Assays are null!");
297            }
298            //study variable
299            if (t.getStudyVariable() != null) {
300                serializeList(
301                    t.getStudyVariable(), jg, sp, Comparator.comparing(
302                    StudyVariable::getId,
303                    Comparator.nullsFirst(Comparator.naturalOrder())
304                ));
305            } else {
306                
307                    log.debug( "Study Variable is null!");
308            }
309            //custom
310            if (t.getCustom() != null) {
311                serializeListWithMetadataElement(t.getCustom(),
312                    MetadataElement.CUSTOM, jg, sp, Comparator.comparing(
313                        Parameter::getId, Comparator.nullsFirst(Comparator.
314                            naturalOrder())));
315            } else {
316                
317                    log.debug( "Custom is null!");
318            }
319            //cv
320            if (t.getCv() != null) {
321                serializeList(t.getCv(), jg, sp, Comparator.comparing(
322                    CV::getId,
323                    Comparator.nullsFirst(Comparator.naturalOrder())
324                ));
325            } else {
326                
327                    log.debug( "CVs are null!");
328            }
329            //small molecule quantification unit
330            if (t.getSmallMoleculeQuantificationUnit() != null) {
331                addLineWithMetadataProperty(jg, prefix,
332                    MetadataProperty.SMALL_MOLECULE_QUANTIFICATION_UNIT,
333                    MetadataElement.SMALL_MOLECULE, t.
334                        getSmallMoleculeQuantificationUnit());
335            } else {
336                
337                    log.debug(
338                        "Small molecule quantification unit is null!");
339            }
340            //small molecule feature quantification unit
341            if (t.getSmallMoleculeFeatureQuantificationUnit() != null) {
342                addLineWithMetadataProperty(jg, prefix,
343                    MetadataProperty.SMALL_MOLECULE_FEATURE_QUANTIFICATION_UNIT,
344                    MetadataElement.SMALL_MOLECULE_FEATURE, t.
345                        getSmallMoleculeFeatureQuantificationUnit());
346            } else {
347                
348                    log.debug(
349                        "Small molecule feature quantification unit is null!");
350            }
351            //small molecule identification reliability
352            if (t.getSmallMoleculeIdentificationReliability() != null) {
353                addLineWithMetadataProperty(jg, prefix,
354                    MetadataProperty.SMALL_MOLECULE_IDENTIFICATION_RELIABILITY,
355                    MetadataElement.SMALL_MOLECULE, t.
356                        getSmallMoleculeIdentificationReliability());
357            } else {
358                
359                    log.debug(
360                        "Small molecule identification reliability is null!");
361            }
362            //database
363            if (t.getDatabase() != null) {
364                serializeList(t.getDatabase(), jg, sp, Comparator.comparing(
365                    Database::getId,
366                    Comparator.nullsFirst(Comparator.naturalOrder())
367                ));
368            } else {
369                
370                    log.debug( "Databases are null!");
371            }
372            if (t.getIdConfidenceMeasure() != null) {
373                serializeListWithMetadataElement(t.getIdConfidenceMeasure(),
374                    MetadataElement.ID_CONFIDENCE_MEASURE, jg, sp, Comparator.
375                        comparing(
376                            Parameter::getId, Comparator.nullsFirst(Comparator.
377                                naturalOrder())));
378            } else {
379                
380                    log.debug( "Id confidence measure is null!");
381            }
382            if (t.getColunitSmallMolecule() != null) {
383                t.getColunitSmallMolecule().
384                    forEach((colUnit) ->
385                    {
386                        addLine(jg, prefix,
387                            MetadataElement.COLUNIT_SMALL_MOLECULE, colUnit.
388                                getColumnName() + "=" + new ParameterConverter().
389                                convert(colUnit.getParam()));
390                    });
391            } else {
392                
393                    log.debug( "Colunit small molecule is null!");
394            }
395            if (t.getColunitSmallMoleculeFeature() != null) {
396                t.getColunitSmallMoleculeFeature().
397                    forEach((colUnit) ->
398                    {
399                        addLine(jg, prefix,
400                            MetadataElement.COLUNIT_SMALL_MOLECULE_FEATURE,
401                            colUnit.
402                                getColumnName() + "=" + new ParameterConverter().
403                                convert(colUnit.getParam()));
404                    });
405            } else {
406                
407                    log.debug( "Colunit small molecule feature is null!");
408            }
409            if (t.getColunitSmallMoleculeEvidence() != null) {
410                t.getColunitSmallMoleculeEvidence().
411                    forEach((colUnit) ->
412                    {
413                        addLine(jg, prefix,
414                            MetadataElement.COLUNIT_SMALL_MOLECULE_EVIDENCE,
415                            colUnit.
416                                getColumnName() + "=" + new ParameterConverter().
417                                convert(colUnit.getParam()));
418                    });
419            } else {
420                
421                    log.debug( "Colunit small molecule evidence is null!");
422            }
423        }
424    }
425
426}