View Javadoc
1   package fr.ifremer.reefdb.dao.referential.taxon;
2   
3   /*
4    * #%L
5    * Reef DB :: Core
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   *
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   *
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import com.google.common.collect.*;
27  import fr.ifremer.quadrige3.core.dao.referential.StatusCode;
28  import fr.ifremer.quadrige3.core.dao.referential.TaxonGroupTypeCode;
29  import fr.ifremer.quadrige3.core.dao.referential.taxon.*;
30  import fr.ifremer.quadrige3.core.dao.technical.Assert;
31  import fr.ifremer.quadrige3.core.dao.technical.Dates;
32  import fr.ifremer.quadrige3.core.dao.technical.hibernate.TemporaryDataHelper;
33  import fr.ifremer.quadrige3.core.service.technical.CacheService;
34  import fr.ifremer.quadrige3.synchro.meta.DatabaseColumns;
35  import fr.ifremer.quadrige3.synchro.meta.data.DataSynchroTables;
36  import fr.ifremer.quadrige3.synchro.meta.referential.ReferentialSynchroTables;
37  import fr.ifremer.reefdb.config.ReefDbConfiguration;
38  import fr.ifremer.reefdb.dao.technical.Daos;
39  import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
40  import fr.ifremer.reefdb.dto.ReefDbBeans;
41  import fr.ifremer.reefdb.dto.referential.CitationDTO;
42  import fr.ifremer.reefdb.dto.referential.TaxonDTO;
43  import fr.ifremer.reefdb.dto.referential.TaxonomicLevelDTO;
44  import fr.ifremer.reefdb.service.ReefDbTechnicalException;
45  import org.apache.commons.collections4.CollectionUtils;
46  import org.apache.commons.lang3.StringUtils;
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  import org.hibernate.SessionFactory;
50  import org.hibernate.type.DateType;
51  import org.hibernate.type.IntegerType;
52  import org.hibernate.type.StringType;
53  import org.nuiton.i18n.I18n;
54  import org.springframework.beans.factory.annotation.Autowired;
55  import org.springframework.cache.Cache;
56  import org.springframework.dao.DataRetrievalFailureException;
57  import org.springframework.stereotype.Repository;
58  
59  import javax.annotation.Nonnull;
60  import javax.annotation.Resource;
61  import java.time.LocalDate;
62  import java.util.*;
63  import java.util.stream.Collectors;
64  
65  /**
66   * <p>ReefDbTaxonNameDaoImpl class.</p>
67   */
68  @Repository("reefDbTaxonNameDao")
69  public class ReefDbTaxonNameDaoImpl extends TaxonNameDaoImpl implements ReefDbTaxonNameDao {
70  
71      private static final Log LOG = LogFactory.getLog(ReefDbTaxonNameDaoImpl.class);
72  
73      private static final Multimap<String, String> taxonNameIdColumnsByReferentialTables = ImmutableListMultimap.<String, String>builder()
74              .put(ReferentialSynchroTables.TAXON_GROUP_HISTORICAL_RECORD.name(), DatabaseColumns.TAXON_NAME_ID.name())
75              .put(ReferentialSynchroTables.TAXON_NAME.name(), DatabaseColumns.PARENT_TAXON_NAME_ID.name()).build();
76  
77      private static final Multimap<String, String> refTaxonIdColumnsByDataTables = ImmutableListMultimap.<String, String>builder()
78              .put(DataSynchroTables.TAXON_MEASUREMENT.name(), DatabaseColumns.REF_TAXON_ID.name()).build();
79  
80      private static final Multimap<String, String> taxonNameIdColumnsByDataTables = ImmutableListMultimap.<String, String>builder()
81              .put(DataSynchroTables.TAXON_MEASUREMENT.name(), DatabaseColumns.TAXON_NAME_ID.name()).build();
82  
83      private static final Map<String, String> validDtColumnsByDataTables = ImmutableMap.<String, String>builder()
84              .put(DataSynchroTables.TAXON_MEASUREMENT.name(), DatabaseColumns.TAXON_MEAS_VALID_DT.name()).build();
85  
86      @Resource
87      protected CacheService cacheService;
88      @Resource
89      protected ReefDbConfiguration config;
90      @Resource(name = "reefDbTaxonNameDao")
91      protected ReefDbTaxonNameDao loopbackTaxonNameDao;
92      @Resource(name = "referenceTaxonDao")
93      protected ReferenceTaxonDao referenceTaxonDao;
94  
95      /**
96       * <p>Constructor for ReefDbTaxonNameDaoImpl.</p>
97       *
98       * @param sessionFactory a {@link org.hibernate.SessionFactory} object.
99       */
100     @Autowired
101     public ReefDbTaxonNameDaoImpl(SessionFactory sessionFactory) {
102         super(sessionFactory);
103     }
104 
105     /**
106      * {@inheritDoc}
107      */
108     @Override
109     public List<TaxonDTO> getAllTaxonNames() {
110 
111         Cache cacheByReferenceId = cacheService.getCache(TAXON_NAME_BY_REFERENCE_ID_CACHE);
112         Cache cacheById = cacheService.getCache(TAXON_NAME_BY_ID_CACHE);
113 
114         Map<Integer, String> taxRefMap = loopbackTaxonNameDao.getTaxRefByTaxonNameId();
115         Map<Integer, String> wormsMap = loopbackTaxonNameDao.getWormsByTaxonNameId();
116 
117         Iterator<Object[]> it = queryIterator("allTaxonName");
118 
119         long nbTaxonName = 0;
120         long nbRefTaxon = 0;
121         List<TaxonDTO> result = Lists.newArrayList();
122         while (it.hasNext()) {
123             Object[] source = it.next();
124             TaxonDTO taxon = toTaxonDTO(Arrays.asList(source).iterator());
125 
126             // add other references
127             taxon.setTaxRef(taxRefMap.get(taxon.getId()));
128             taxon.setWormsRef(wormsMap.get(taxon.getId()));
129 
130             result.add(taxon);
131 
132             // update cache by id
133             cacheById.put(taxon.getId(), taxon);
134             nbTaxonName++;
135             // update cache by reference id
136             if (taxon.isReferent()) {
137                 cacheByReferenceId.put(taxon.getReferenceTaxonId(), taxon);
138                 nbRefTaxon++;
139             }
140         }
141 
142         if (LOG.isDebugEnabled()) {
143             LOG.debug(String.format("%s Taxon name loaded, %s reference taxon loaded", nbTaxonName, nbRefTaxon));
144         }
145         return ImmutableList.copyOf(result);
146     }
147 
148     /**
149      * {@inheritDoc}
150      */
151     @Override
152     public TaxonDTO getTaxonNameByReferenceId(int referenceTaxonId) {
153 
154         Object[] source = queryUnique("taxonNameByReferenceId", "taxonReferenceId", IntegerType.INSTANCE, referenceTaxonId);
155 
156         if (source == null) {
157             throw new DataRetrievalFailureException("Can't load taxon name with reference taxon id = " + referenceTaxonId);
158         }
159 
160         return toTaxonDTO(Arrays.asList(source).iterator());
161     }
162 
163     /**
164      * {@inheritDoc}
165      */
166     @Override
167     public TaxonDTO getTaxonNameById(int taxonId) {
168 
169         Object[] source = queryUnique("taxonNameById", "taxonNameId", IntegerType.INSTANCE, taxonId);
170 
171         if (source == null) {
172             return null;
173         }
174 
175         TaxonDTO taxon = toTaxonDTO(Arrays.asList(source).iterator());
176         fillReferent(taxon);
177         return taxon;
178     }
179 
180     /**
181      * {@inheritDoc}
182      *
183      * @param date
184      */
185     @Override
186     public Multimap<Integer, TaxonDTO> getAllTaxonNamesMapByTaxonGroupId(@Nonnull LocalDate date) {
187 
188         Iterator<Object[]> it = queryIterator("taxonNameIdsWithTaxonGroupId",
189                 "referenceDate", DateType.INSTANCE, Dates.convertToDate(date, config.getDbTimezone()),
190                 "taxonGroupTypeCode", StringType.INSTANCE, TaxonGroupTypeCode.IDENTIFICATION.getValue());
191 
192         Multimap<Integer, TaxonDTO> result = ArrayListMultimap.create();
193         while (it.hasNext()) {
194             Object[] source = it.next();
195             Iterator<Object> row = Arrays.asList(source).iterator();
196             Integer taxonGroupId = (Integer) row.next();
197             result.put(taxonGroupId, loopbackTaxonNameDao.getTaxonNameById((Integer) row.next()));
198         }
199         return result;
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     @Override
206     public List<TaxonDTO> getTaxonNamesByIds(List<Integer> taxonIds) {
207 
208         if (CollectionUtils.isEmpty(taxonIds)) return new ArrayList<>();
209 
210         return loopbackTaxonNameDao.getAllTaxonNames().stream().filter(taxon -> taxonIds.contains(taxon.getId())).collect(Collectors.toList());
211     }
212 
213     /**
214      * {@inheritDoc}
215      */
216     @Override
217     public void fillTaxonsProperties(List<TaxonDTO> taxons) {
218 
219         if (CollectionUtils.isEmpty(taxons)) {
220             return;
221         }
222 
223         Map<Integer, String> taxRefMap = loopbackTaxonNameDao.getTaxRefByTaxonNameId();
224         Map<Integer, String> wormsMap = loopbackTaxonNameDao.getWormsByTaxonNameId();
225 
226         for (TaxonDTO taxon : taxons) {
227 
228             // parent taxon and reference taxon
229             fillParentAndReferent(taxon);
230 
231             // composites
232             if (taxon.isVirtual()) {
233                 taxon.setCompositeTaxons(loopbackTaxonNameDao.getCompositeTaxonNames(taxon.getId()));
234             }
235 
236             // fill other references like (WORMS and TAXREFv80)
237             taxon.setTaxRef(taxRefMap.get(taxon.getId()));
238             taxon.setWormsRef(wormsMap.get(taxon.getId()));
239 
240         }
241     }
242 
243     private void fillTaxonProperties(TaxonDTO taxon) {
244 
245         // parent taxon and reference taxon
246         fillParentAndReferent(taxon);
247 
248         // fill other references like (WORMS and TAXREFv80)
249         taxon.setTaxRef(loopbackTaxonNameDao.getTaxRefByTaxonNameId().get(taxon.getId()));
250         taxon.setWormsRef(loopbackTaxonNameDao.getWormsByTaxonNameId().get(taxon.getId()));
251 
252     }
253 
254     /**
255      * {@inheritDoc}
256      */
257     @Override
258     public List<TaxonDTO> findFullTaxonNamesByCriteria(String levelCode, String name, boolean isStrictName, Boolean isLocal) {
259         List<TaxonDTO> result = findTaxonNamesByCriteria(levelCode, name, isStrictName, isLocal);
260 
261         fillTaxonsProperties(result);
262 
263         return result;
264     }
265 
266     /**
267      * {@inheritDoc}
268      */
269     @Override
270     public List<TaxonDTO> findTaxonNamesByCriteria(String levelCode, String name, boolean isStrictName, final Boolean isLocal) {
271 
272         List<TaxonDTO> result = Lists.newArrayList();
273 
274         // for better performance if no parameter
275         if (StringUtils.isBlank(levelCode) && StringUtils.isBlank(name)) {
276 
277             result.addAll(loopbackTaxonNameDao.getAllTaxonNames());
278 
279         } else {
280 
281             Iterator<Object[]> it = queryIterator("taxonNamesByCriteria",
282                     "levelCd", StringType.INSTANCE, levelCode,
283                     "name", StringType.INSTANCE, isStrictName ? null : name,
284                     "strictName", StringType.INSTANCE, isStrictName ? name : null);
285 
286             while (it.hasNext()) {
287                 Object[] source = it.next();
288                 result.add(toTaxonDTO(Arrays.asList(source).iterator()));
289             }
290         }
291 
292         fillReferents(result);
293 
294         return ImmutableList.copyOf(isLocal == null
295                 ? result
296                 : ReefDbBeans.filterReferential(result, isLocal)
297         );
298     }
299 
300     /**
301      * {@inheritDoc}
302      */
303     @Override
304     public List<TaxonomicLevelDTO> getAllTaxonomicLevels() {
305         Iterator<Object[]> it = queryIterator("allTaxonomicLevels");
306 
307         List<TaxonomicLevelDTO> result = Lists.newArrayList();
308         while (it.hasNext()) {
309             Object[] source = it.next();
310             result.add(toTaxonomicLevelDTO(Arrays.asList(source).iterator()));
311         }
312         return result;
313     }
314 
315     /**
316      * {@inheritDoc}
317      */
318     @Override
319     public List<TaxonDTO> getCompositeTaxonNames(Integer taxonNameId) {
320         Iterator<Object[]> it = queryIterator("compositeTaxonNamesByTaxonNameId",
321                 "taxonNameId", IntegerType.INSTANCE, taxonNameId);
322 
323         List<TaxonDTO> result = Lists.newArrayList();
324         while (it.hasNext()) {
325             Object[] source = it.next();
326             TaxonDTO taxon = toTaxonDTO(Arrays.asList(source).iterator());
327             fillTaxonProperties(taxon);
328             result.add(taxon);
329         }
330         return result;
331     }
332 
333     /**
334      * {@inheritDoc}
335      */
336     @Override
337     public Map<Integer, String> getTaxRefByTaxonNameId() {
338 
339         return getAlternateReferencesMap(config.getAlternativeTaxonOriginTaxRef());
340     }
341 
342     /**
343      * {@inheritDoc}
344      */
345     @Override
346     public Map<Integer, String> getWormsByTaxonNameId() {
347 
348         return getAlternateReferencesMap(config.getAlternativeTaxonOriginWorms());
349     }
350 
351     private Map<Integer, String> getAlternateReferencesMap(String originCode) {
352 
353         Map<Integer, String> result = Maps.newHashMap();
354         if (StringUtils.isNotBlank(originCode)) {
355 
356             Iterator<Object[]> rows = queryIterator("alternateTaxonCode",
357                     "originCode", StringType.INSTANCE, originCode);
358 
359             while (rows.hasNext()) {
360                 Object[] row = rows.next();
361                 result.put((Integer) row[0], (String) row[1]);
362             }
363         }
364 
365         return result;
366     }
367 
368     /**
369      * {@inheritDoc}
370      */
371     @Override
372     public void saveTaxons(List<? extends TaxonDTO> taxons) {
373         if (CollectionUtils.isEmpty(taxons)) {
374             return;
375         }
376 
377         for (TaxonDTO taxon : taxons) {
378             if (taxon.isDirty()) {
379                 saveTaxon(taxon);
380                 taxon.setDirty(false);
381             }
382         }
383         getSession().flush();
384         getSession().clear();
385     }
386 
387     /**
388      * {@inheritDoc}
389      */
390     @Override
391     public void deleteTaxons(List<Integer> taxonIds) {
392         if (taxonIds == null) return;
393         taxonIds.stream().filter(Objects::nonNull).distinct().forEach(id -> {
394             remove(id);
395 
396             // If local taxon, delete the associated reference taxon
397             boolean isLocalTaxon = TemporaryDataHelper.isTemporaryId(id);
398             if (isLocalTaxon) {
399                 referenceTaxonDao.remove(id);
400             }
401         });
402         getSession().flush();
403         getSession().clear();
404     }
405 
406     /**
407      * {@inheritDoc}
408      */
409     @Override
410     public void replaceTemporaryTaxon(Integer sourceId, Integer sourceReferenceId, Integer targetId, Integer targetReferenceId, boolean delete) {
411         Assert.notNull(sourceId);
412         Assert.notNull(targetId);
413         Assert.notNull(sourceReferenceId);
414         Assert.notNull(targetReferenceId);
415 
416         // taxon name: Replace inside referential tables
417         executeMultipleUpdate(taxonNameIdColumnsByReferentialTables, sourceId, targetId);
418 
419         // taxon name: Replace inside data tables, but NOT if already validate
420         executeMultipleUpdateWithNullCondition(taxonNameIdColumnsByDataTables, validDtColumnsByDataTables, sourceId, targetId);
421 
422         // reference taxon: Replace inside data tables, but NOT if already validate
423         executeMultipleUpdateWithNullCondition(refTaxonIdColumnsByDataTables, validDtColumnsByDataTables, sourceReferenceId, targetReferenceId);
424 
425         if (delete) {
426             // delete temporary taxon name
427             remove(sourceId);
428 
429             // If local taxon name, delete the associated reference taxon (fix mantis #39386)
430             boolean isLocalTaxon = TemporaryDataHelper.isTemporaryId(sourceId);
431             if (isLocalTaxon) {
432                 referenceTaxonDao.remove(sourceId);
433             }
434         }
435 
436         getSession().flush();
437         getSession().clear();
438 
439     }
440 
441     /**
442      * {@inheritDoc}
443      */
444     @Override
445     public boolean isTaxonNameUsedInReferential(int taxonId) {
446 
447         return executeMultipleCount(taxonNameIdColumnsByReferentialTables, taxonId);
448     }
449 
450     /**
451      * {@inheritDoc}
452      */
453     @Override
454     public boolean isReferenceTaxonUsedInReferential(int refTaxonId, int excludedTaxonNameId) {
455 
456         Long countInTaxonName = queryUniqueTyped("countReferenceTaxonInTaxonName",
457                 "refTaxonId", IntegerType.INSTANCE, refTaxonId,
458                 "excludedTaxonNameId", IntegerType.INSTANCE, excludedTaxonNameId);
459         return countInTaxonName > 0;
460     }
461 
462     /**
463      * {@inheritDoc}
464      */
465     @Override
466     public boolean isReferenceTaxonUsedInData(int refTaxonId) {
467 
468         return executeMultipleCount(refTaxonIdColumnsByDataTables, refTaxonId);
469     }
470 
471     /**
472      * {@inheritDoc}
473      */
474     @Override
475     public boolean isReferenceTaxonUsedInValidatedData(int refTaxonId) {
476 
477         return executeMultipleCountWithNotNullCondition(refTaxonIdColumnsByDataTables, validDtColumnsByDataTables, refTaxonId);
478     }
479 
480     // INTERNAL METHODS
481 
482     private void saveTaxon(TaxonDTO taxon) {
483         Assert.notNull(taxon);
484         Assert.isTrue(taxon.getId() == null || taxon.getId() < 0);
485         Assert.notBlank(taxon.getName());
486         Assert.notNull(taxon.getParentTaxon());
487         Assert.notNull(taxon.getLevel());
488 
489         TaxonName target;
490         if (taxon.getId() == null) {
491             target = TaxonName.Factory.newInstance();
492             target.setTaxonNameId(TemporaryDataHelper.getNewNegativeIdForTemporaryData(getSession(), target.getClass()));
493         } else {
494             target = get(taxon.getId());
495         }
496 
497         target.setTaxonNameCompleteNm(taxon.getName());
498         target.setTaxonomicLevel(load(TaxonomicLevelImpl.class, taxon.getLevel().getCode()));
499 
500         if (target.getReferenceTaxon() == null) {
501             // By default, use: refTaxonId = taxonNameId
502             int refTaxonId = target.getTaxonNameId();
503 
504             // Check this refTaxonId if not used
505             if (get(ReferenceTaxonImpl.class, refTaxonId) != null) {
506                 throw new ReefDbTechnicalException(I18n.t("reefdb.error.referential.badLocalTaxonNameId", refTaxonId));
507             }
508 
509             ReferenceTaxon refTaxon = ReferenceTaxon.Factory.newInstance();
510             refTaxon.setRefTaxonId(refTaxonId);
511             refTaxon.setUpdateDt(newUpdateTimestamp());
512             target.setReferenceTaxon(refTaxon);
513             getSession().save(refTaxon);
514 
515             // Affect to bean (Mantis #39754)
516             taxon.setReferenceTaxonId(refTaxonId);
517         }
518 
519         target.setParentTaxonName(load(taxon.getParentTaxon().getId()));
520 
521         target.setTaxonNameCm(taxon.getComment());
522         target.setTaxonNameIsRefer(true);
523         target.setTaxonNameTempor(true);
524         target.setTaxonNameIsVirtual(true);
525         target.setTaxonNameObsol(taxon.isObsolete());
526         if (taxon.getCitation() != null) {
527             target.setCitId(load(CitationImpl.class, taxon.getCitation().getId()));
528         } else {
529             target.setCitId(null);
530         }
531 
532         getSession().save(target);
533         taxon.setId(target.getTaxonNameId());
534     }
535 
536     private TaxonDTO toTaxonDTO(Iterator<Object> source) {
537         TaxonDTO result = ReefDbBeanFactory.newTaxonDTO();
538 
539         // Id
540         result.setId((Integer) source.next());
541 
542         // Name (complete name)
543         result.setName((String) source.next());
544 
545         result.setComment((String) source.next());
546 
547         result.setReferent((Boolean) source.next());
548         result.setVirtual((Boolean) source.next());
549         result.setObsolete((Boolean) source.next());
550         result.setTemporary((Boolean) source.next());
551 
552         result.setReferenceTaxonId((Integer) source.next());
553         result.setParentTaxonId((Integer) source.next());
554 
555         String levelCode = (String) source.next();
556         String levelLabel = (String) source.next();
557         String levelName = (String) source.next();
558         Integer levelNb = (Integer) source.next();
559         Integer citationId = (Integer) source.next();
560         String citationName = (String) source.next();
561 
562         result.setCreationDate(Daos.convertToDate(source.next()));
563         result.setUpdateDate(Daos.convertToDate(source.next()));
564 
565         // taxonomic level
566         if (levelCode != null) {
567             TaxonomicLevelDTO level = ReefDbBeanFactory.newTaxonomicLevelDTO();
568             level.setCode(levelCode);
569             level.setLabel(levelLabel);
570             level.setName(levelName);
571             level.setNumber(levelNb);
572 
573             result.setLevel(level);
574         }
575 
576         // citation
577         if (citationId != null) {
578             CitationDTO citation = ReefDbBeanFactory.newCitationDTO();
579             citation.setId(citationId);
580             citation.setName(citationName);
581 
582             result.setCitation(citation);
583         }
584 
585         // Status
586         StatusCode statusCode;
587         if (Boolean.TRUE.equals(result.isTemporary())) {
588             statusCode = StatusCode.TEMPORARY;
589         } else {
590             statusCode = StatusCode.ENABLE;
591         }
592         result.setStatus(Daos.getStatus(statusCode));
593 
594         return result;
595     }
596 
597     /**
598      * {@inheritDoc}
599      */
600     @Override
601     public void fillParentAndReferent(TaxonDTO taxon) {
602 
603         // referent Taxon
604         fillReferent(taxon);
605 
606         // parent Taxon
607         if (taxon.getParentTaxonId() != null) {
608             if (taxon.getParentTaxonId().equals(taxon.getId())) {
609                 taxon.setParentTaxon(taxon);
610             } else {
611                 taxon.setParentTaxon(loopbackTaxonNameDao.getTaxonNameById(taxon.getParentTaxonId()));
612             }
613         }
614     }
615 
616     @Override
617     public void fillReferents(List<TaxonDTO> taxons) {
618 
619         if (taxons == null) return;
620         taxons.forEach(this::fillReferent);
621     }
622 
623     private void fillReferent(TaxonDTO taxon) {
624 
625         // get referent taxon
626         if (taxon.getReferenceTaxon() == null || !Objects.equals(taxon.getReferenceTaxon().getId(), taxon.getReferenceTaxonId())) {
627             taxon.setReferenceTaxon(loopbackTaxonNameDao.getTaxonNameByReferenceId(taxon.getReferenceTaxonId()));
628         }
629     }
630 
631     private TaxonomicLevelDTO toTaxonomicLevelDTO(Iterator<Object> source) {
632         TaxonomicLevelDTO result = ReefDbBeanFactory.newTaxonomicLevelDTO();
633 
634         // code
635         result.setCode((String) source.next());
636 
637         // label
638         result.setLabel((String) source.next());
639 
640         // name
641         result.setName((String) source.next());
642 
643         //number
644         result.setNumber((Integer) source.next());
645 
646         return result;
647 
648     }
649 }