2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.io
.berlinModel
.in
;
12 import java
.sql
.ResultSet
;
13 import java
.sql
.SQLException
;
14 import java
.util
.HashMap
;
15 import java
.util
.HashSet
;
18 import java
.util
.UUID
;
20 import org
.apache
.log4j
.Logger
;
21 import org
.springframework
.stereotype
.Component
;
23 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
24 import eu
.etaxonomy
.cdm
.io
.berlinModel
.BerlinModelTransformer
;
25 import eu
.etaxonomy
.cdm
.io
.berlinModel
.in
.validation
.BerlinModelTaxonNameImportValidator
;
26 import eu
.etaxonomy
.cdm
.io
.common
.IImportConfigurator
;
27 import eu
.etaxonomy
.cdm
.io
.common
.IOValidator
;
28 import eu
.etaxonomy
.cdm
.io
.common
.ImportHelper
;
29 import eu
.etaxonomy
.cdm
.io
.common
.ResultSetPartitioner
;
30 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
31 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
32 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
33 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
34 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
35 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
36 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
37 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
38 import eu
.etaxonomy
.cdm
.model
.name
.CultivarPlantName
;
39 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
40 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
41 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
42 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
43 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
44 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
45 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
53 public class BerlinModelTaxonNameImport
extends BerlinModelImportBase
{
54 private static final Logger logger
= Logger
.getLogger(BerlinModelTaxonNameImport
.class);
56 public static final String NAMESPACE
= "TaxonName";
58 public static final UUID SOURCE_ACC_UUID
= UUID
.fromString("c3959b4f-d876-4b7a-a739-9260f4cafd1c");
60 private static int modCount
= 5000;
61 private static final String pluralString
= "TaxonNames";
62 private static final String dbTableName
= "Name";
65 public BerlinModelTaxonNameImport(){
70 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery()
73 protected String
getRecordQuery(BerlinModelImportConfigurator config
) {
74 Source source
= config
.getSource();
76 String facultativCols
= "";
77 String strFacTable
= "RefDetail";
78 String strFacColumn
= "IdInSource";
79 String strColAlias
= null;
80 if (checkSqlServerColumnExists(source
, strFacTable
, strFacColumn
)){
81 facultativCols
+= ", " + strFacTable
+ "." + strFacColumn
;
82 if (! CdmUtils
.Nz(strColAlias
).equals("") ){
83 facultativCols
+= " AS " + strColAlias
;
87 String strRecordQuery
=
88 "SELECT Name.* , RefDetail.RefDetailId, RefDetail.RefFk, " +
89 " RefDetail.FullRefCache, RefDetail.FullNomRefCache, RefDetail.PreliminaryFlag AS RefDetailPrelim, RefDetail.Details, " +
90 " RefDetail.SecondarySources, Rank.RankAbbrev, Rank.Rank " +
92 " FROM Name LEFT OUTER JOIN RefDetail ON Name.NomRefDetailFk = RefDetail.RefDetailId AND " +
93 " Name.NomRefFk = RefDetail.RefFk " +
94 " LEFT OUTER JOIN Rank ON Name.RankFk = Rank.rankID " +
95 " WHERE name.nameId IN ("+ID_LIST_TOKEN
+") ";
96 //strQuery += " AND RefDetail.PreliminaryFlag = 1 ";
97 //strQuery += " AND Name.Created_When > '03.03.2004' ";
98 return strRecordQuery
;
103 * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#doPartition(eu.etaxonomy.cdm.io.berlinModel.in.ResultSetPartitioner, eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportState)
105 public boolean doPartition(ResultSetPartitioner partitioner
, BerlinModelImportState state
) {
108 boolean success
= true ;
109 BerlinModelImportConfigurator config
= state
.getConfig();
110 Set
<TaxonNameBase
> namesToSave
= new HashSet
<TaxonNameBase
>();
111 Map
<String
, Team
> teamMap
= (Map
<String
, Team
>) partitioner
.getObjectMap(BerlinModelAuthorTeamImport
.NAMESPACE
);
113 ResultSet rs
= partitioner
.getResultSet();
120 if ((i
++ % modCount
) == 0 && i
!= 1 ){ logger
.info("Names handled: " + (i
-1));}
122 //create TaxonName element
123 int nameId
= rs
.getInt("nameId");
124 Object authorFk
= rs
.getObject("AuthorTeamFk");
125 Object exAuthorFk
= rs
.getObject("ExAuthorTeamFk");
126 Object basAuthorFk
= rs
.getObject("BasAuthorTeamFk");
127 Object exBasAuthorFk
= rs
.getObject("ExBasAuthorTeamFk");
128 String strCultivarGroupName
= rs
.getString("CultivarGroupName");
129 String strCultivarName
= rs
.getString("CultivarName");
132 boolean useUnknownRank
= true;
133 Rank rank
= BerlinModelTransformer
.rankId2Rank(rs
, useUnknownRank
);
135 TaxonNameBase taxonNameBase
;
136 if (config
.getNomenclaturalCode() != null){
137 taxonNameBase
= config
.getNomenclaturalCode().getNewTaxonNameInstance(rank
);
139 if (taxonNameBase
instanceof BotanicalName
){
140 if (CdmUtils
.isNotEmpty(strCultivarGroupName
) && CdmUtils
.isNotEmpty(strCultivarName
)){
141 taxonNameBase
= CultivarPlantName
.NewInstance(rank
);
145 taxonNameBase
= NonViralName
.NewInstance(rank
);
149 //TODO rank should never be null or a more sophisticated algorithm has to be implemented for genus/supraGenericName
150 logger
.warn("Rank is null. Genus epethiton was imported. May be wrong");
153 if (rank
!= null && rank
.isSupraGeneric()){
154 dbAttrName
= "supraGenericName";
156 dbAttrName
= "genus";
158 cdmAttrName
= "genusOrUninomial";
159 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
161 dbAttrName
= "genusSubdivisionEpi";
162 cdmAttrName
= "infraGenericEpithet";
163 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
165 dbAttrName
= "speciesEpi";
166 cdmAttrName
= "specificEpithet";
167 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
170 dbAttrName
= "infraSpeciesEpi";
171 cdmAttrName
= "infraSpecificEpithet";
172 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
174 dbAttrName
= "unnamedNamePhrase";
175 cdmAttrName
= "appendedPhrase";
176 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
179 dbAttrName
= "details";
180 cdmAttrName
= "nomenclaturalMicroReference";
181 success
&= ImportHelper
.addStringValue(rs
, taxonNameBase
, dbAttrName
, cdmAttrName
);
184 success
&= makeNomenclaturalReference(config
, taxonNameBase
, nameId
, rs
, partitioner
);
187 String sourceAcc
= rs
.getString("Source_Acc");
188 if (CdmUtils
.isNotEmpty(sourceAcc
)){
189 ExtensionType sourceAccExtensionType
= getExtensionType(state
, SOURCE_ACC_UUID
, "Source_Acc","Source_Acc","Source_Acc");
190 Extension datesExtension
= Extension
.NewInstance(taxonNameBase
, sourceAcc
, sourceAccExtensionType
);
194 success
&= doIdCreatedUpdatedNotes(state
, taxonNameBase
, rs
, nameId
, NAMESPACE
);
197 if (taxonNameBase
instanceof NonViralName
){
198 NonViralName nonViralName
= (NonViralName
)taxonNameBase
;
201 if (teamMap
!= null ){
202 nonViralName
.setCombinationAuthorTeam(getAuthorTeam(teamMap
, authorFk
, nameId
, config
));
203 nonViralName
.setExCombinationAuthorTeam(getAuthorTeam(teamMap
, exAuthorFk
, nameId
, config
));
204 nonViralName
.setBasionymAuthorTeam(getAuthorTeam(teamMap
, basAuthorFk
, nameId
, config
));
205 nonViralName
.setExBasionymAuthorTeam(getAuthorTeam(teamMap
, exBasAuthorFk
, nameId
, config
));
207 logger
.warn("TeamMap is null");
217 if (taxonNameBase
instanceof ZoologicalName
){
218 ZoologicalName zooName
= (ZoologicalName
)taxonNameBase
;
219 makeZoologialName(rs
, zooName
, nameId
);
222 else if (taxonNameBase
instanceof BotanicalName
){
223 BotanicalName botName
= (BotanicalName
)taxonNameBase
;
224 success
&= makeBotanicalNamePart(rs
, botName
) ;
228 // dbAttrName = "preliminaryFlag";
229 Boolean preliminaryFlag
= rs
.getBoolean("PreliminaryFlag");
230 if (preliminaryFlag
== true){
231 //Computes all caches and sets
232 taxonNameBase
.setFullTitleCache(taxonNameBase
.getFullTitleCache(), true);
233 taxonNameBase
.setTitleCache(taxonNameBase
.getTitleCache(), true);
234 if (taxonNameBase
instanceof NonViralName
){
235 NonViralName nvn
= (NonViralName
)taxonNameBase
;
236 nvn
.setNameCache(nvn
.getNameCache(), true);
237 nvn
.setAuthorshipCache(nvn
.getAuthorshipCache(), true);
240 namesToSave
.add(taxonNameBase
);
243 catch (UnknownCdmTypeException e
) {
244 logger
.warn("Name with id " + nameId
+ " has unknown rankId " + " and could not be saved.");
248 } //while rs.hasNext()
249 } catch (SQLException e
) {
250 logger
.error("SQLException:" + e
);
255 // logger.info( i + " names handled");
256 getNameService().save(namesToSave
);
261 * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#getRelatedObjectsForPartition(java.sql.ResultSet)
263 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
) {
268 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<Object
, Map
<String
, ?
extends CdmBase
>>();
271 Set
<String
> teamIdSet
= new HashSet
<String
>();
272 Set
<String
> referenceIdSet
= new HashSet
<String
>();
273 Set
<String
> refDetailIdSet
= new HashSet
<String
>();
275 handleForeignKey(rs
, teamIdSet
, "AuthorTeamFk");
276 handleForeignKey(rs
, teamIdSet
, "ExAuthorTeamFk");
277 handleForeignKey(rs
, teamIdSet
, "BasAuthorTeamFk");
278 handleForeignKey(rs
, teamIdSet
, "ExBasAuthorTeamFk");
279 handleForeignKey(rs
, referenceIdSet
, "nomRefFk");
280 handleForeignKey(rs
, refDetailIdSet
, "nomRefDetailFk");
284 nameSpace
= BerlinModelAuthorTeamImport
.NAMESPACE
;
285 cdmClass
= Team
.class;
287 Map
<String
, Person
> teamMap
= (Map
<String
, Person
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, idSet
, nameSpace
);
288 result
.put(nameSpace
, teamMap
);
291 nameSpace
= BerlinModelReferenceImport
.NOM_REFERENCE_NAMESPACE
;
292 cdmClass
= ReferenceBase
.class;
293 idSet
= referenceIdSet
;
294 Map
<String
, ReferenceBase
> nomReferenceMap
= (Map
<String
, ReferenceBase
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, idSet
, nameSpace
);
295 result
.put(nameSpace
, nomReferenceMap
);
297 //biblio reference map
298 nameSpace
= BerlinModelReferenceImport
.BIBLIO_REFERENCE_NAMESPACE
;
299 cdmClass
= ReferenceBase
.class;
300 idSet
= referenceIdSet
;
301 Map
<String
, ReferenceBase
> biblioReferenceMap
= (Map
<String
, ReferenceBase
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, idSet
, nameSpace
);
302 result
.put(nameSpace
, biblioReferenceMap
);
305 nameSpace
= BerlinModelRefDetailImport
.NOM_REFDETAIL_NAMESPACE
;
306 cdmClass
= ReferenceBase
.class;
307 idSet
= refDetailIdSet
;
308 Map
<String
, ReferenceBase
> nomRefDetailMap
= (Map
<String
, ReferenceBase
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, idSet
, nameSpace
);
309 result
.put(nameSpace
, nomRefDetailMap
);
311 //biblio refDetail map
312 nameSpace
= BerlinModelRefDetailImport
.BIBLIO_REFDETAIL_NAMESPACE
;
313 cdmClass
= ReferenceBase
.class;
314 idSet
= refDetailIdSet
;
315 Map
<String
, ReferenceBase
> biblioRefDetailMap
= (Map
<String
, ReferenceBase
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, idSet
, nameSpace
);
316 result
.put(nameSpace
, biblioRefDetailMap
);
318 } catch (SQLException e
) {
319 throw new RuntimeException(e
);
324 private boolean makeZoologialName(ResultSet rs
, ZoologicalName zooName
, int nameId
)
326 boolean success
= true;
328 String authorTeamYear
= rs
.getString("authorTeamYear");
330 if (! "".equals(CdmUtils
.Nz(authorTeamYear
).trim())){
331 Integer publicationYear
= Integer
.valueOf(authorTeamYear
.trim());
332 zooName
.setPublicationYear(publicationYear
);
334 } catch (NumberFormatException e
) {
335 logger
.warn("authorTeamYear could not be parsed for taxonName: "+ nameId
);
337 //original publication year
338 String basAuthorTeamYear
= rs
.getString("basAuthorTeamYear");
340 if (! "".equals(CdmUtils
.Nz(basAuthorTeamYear
).trim())){
341 Integer OriginalPublicationYear
= Integer
.valueOf(basAuthorTeamYear
.trim());
342 zooName
.setOriginalPublicationYear(OriginalPublicationYear
);
344 } catch (NumberFormatException e
) {
345 logger
.warn("basAuthorTeamYear could not be parsed for taxonName: "+ nameId
);
350 private boolean makeBotanicalNamePart(ResultSet rs
, BotanicalName botanicalName
)throws SQLException
{
351 boolean success
= true;
355 dbAttrName
= "HybridFormulaFlag";
356 cdmAttrName
= "isHybridFormula";
357 success
&= ImportHelper
.addBooleanValue(rs
, botanicalName
, dbAttrName
, cdmAttrName
);
359 dbAttrName
= "MonomHybFlag";
360 cdmAttrName
= "isMonomHybrid";
361 success
&= ImportHelper
.addBooleanValue(rs
, botanicalName
, dbAttrName
, cdmAttrName
);
363 dbAttrName
= "BinomHybFlag";
364 cdmAttrName
= "isBinomHybrid";
365 success
&= ImportHelper
.addBooleanValue(rs
, botanicalName
, dbAttrName
, cdmAttrName
);
367 dbAttrName
= "TrinomHybFlag";
368 cdmAttrName
= "isTrinomHybrid";
369 success
&= ImportHelper
.addBooleanValue(rs
, botanicalName
, dbAttrName
, cdmAttrName
);
372 String strCultivarGroupName
= rs
.getString("CultivarGroupName");
373 String strCultivarName
= rs
.getString("CultivarName");
374 if (botanicalName
instanceof CultivarPlantName
){
375 CultivarPlantName cultivarName
= (CultivarPlantName
)botanicalName
;
376 String concatCultivarName
= CdmUtils
.concat("-", strCultivarName
, strCultivarGroupName
);
377 if (CdmUtils
.isNotEmpty(strCultivarGroupName
) && CdmUtils
.isNotEmpty(strCultivarName
)){
378 logger
.warn("CDM does not support cultivarGroupName and CultivarName together: " + concatCultivarName
);
380 cultivarName
.setCultivarName(strCultivarGroupName
);
382 } catch (SQLException e
) {
389 private boolean makeNomenclaturalReference(IImportConfigurator config
, TaxonNameBase taxonNameBase
,
390 int nameId
, ResultSet rs
, ResultSetPartitioner partitioner
) throws SQLException
{
391 Map
<String
, ReferenceBase
> biblioRefMap
= partitioner
.getObjectMap(BerlinModelReferenceImport
.BIBLIO_REFERENCE_NAMESPACE
);
392 Map
<String
, ReferenceBase
> nomRefMap
= partitioner
.getObjectMap(BerlinModelReferenceImport
.NOM_REFERENCE_NAMESPACE
);
393 Map
<String
, ReferenceBase
> biblioRefDetailMap
= partitioner
.getObjectMap(BerlinModelRefDetailImport
.BIBLIO_REFDETAIL_NAMESPACE
);
394 Map
<String
, ReferenceBase
> nomRefDetailMap
= partitioner
.getObjectMap(BerlinModelRefDetailImport
.NOM_REFDETAIL_NAMESPACE
);
396 Object nomRefFkObj
= rs
.getObject("NomRefFk");
397 Object nomRefDetailFkObj
= rs
.getObject("NomRefDetailFk");
398 boolean refDetailPrelim
= rs
.getBoolean("RefDetailPrelim");
400 boolean success
= true;
401 //nomenclatural Reference
402 if (biblioRefMap
!= null){
403 if (nomRefFkObj
!= null){
404 String nomRefFk
= String
.valueOf(nomRefFkObj
);
405 String nomRefDetailFk
= String
.valueOf(nomRefDetailFkObj
);
407 ReferenceBase nomReference
=
408 getReferenceFromMaps(nomRefDetailMap
, biblioRefDetailMap
,
409 nomRefMap
, biblioRefMap
, nomRefDetailFk
, nomRefFk
);
413 if (nomReference
== null ){
415 if (! config
.isIgnoreNull()){
416 logger
.warn("Nomenclatural reference (nomRefFk = " + nomRefFk
+ ") for TaxonName (nameId = " + nameId
+ ")"+
417 " was not found in reference store. Nomenclatural reference was not set!!");
420 if (! INomenclaturalReference
.class.isAssignableFrom(nomReference
.getClass())){
421 logger
.warn("Nomenclatural reference (nomRefFk = " + nomRefFk
+ ") for TaxonName (nameId = " + nameId
+ ")"+
422 " is not assignable from INomenclaturalReference. (Class = " + nomReference
.getClass()+ ")");
424 nomReference
.setNomenclaturallyRelevant(true);
425 taxonNameBase
.setNomenclaturalReference(nomReference
);
432 private static TeamOrPersonBase
getAuthorTeam(Map
<String
, Team
> teamMap
, Object teamIdObject
, int nameId
, BerlinModelImportConfigurator bmiConfig
){
433 if (teamIdObject
== null){
436 String teamId
= String
.valueOf(teamIdObject
);
437 TeamOrPersonBase author
= teamMap
.get(teamId
);
440 if (!bmiConfig
.isIgnoreNull() && ! (teamId
.equals(0) && bmiConfig
.isIgnore0AuthorTeam()) ){
441 logger
.warn("AuthorTeam (teamId = " + teamId
+ ") for TaxonName (nameId = " + nameId
+ ")"+
442 " was not found in authorTeam store. Relation was not set!!");}
451 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IImportConfigurator)
454 protected boolean doCheck(BerlinModelImportState state
){
455 IOValidator
<BerlinModelImportState
> validator
= new BerlinModelTaxonNameImportValidator();
456 return validator
.validate(state
);
460 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getTableName()
463 protected String
getTableName() {
468 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getPluralString()
471 public String
getPluralString() {
476 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
478 protected boolean isIgnore(BerlinModelImportState state
){
479 return ! state
.getConfig().isDoTaxonNames();
487 //FOR FUTURE USE , DONT DELETE
488 // new CdmStringMapper("nameId", "nameId"),
489 // new CdmStringMapper("rankFk", "rankFk"),
490 // new CdmStringMapper("nameCache", "nameCache"),
491 // new CdmStringMapper("unnamedNamePhrase", "unnamedNamePhrase"),
492 // new CdmStringMapper("fullNameCache", "fullNameCache"),
493 // new CdmStringMapper("preliminaryFlag", "preliminaryFlag"),
494 // new CdmStringMapper("supragenericName", "supragenericName"),
495 // new CdmStringMapper("genus", "genus"),
496 // new CdmStringMapper("genusSubdivisionEpi", "genusSubdivisionEpi"),
497 // new CdmStringMapper("speciesEpi", "speciesEpi"),
498 // new CdmStringMapper("infraSpeciesEpi", "infraSpeciesEpi"),
499 // new CdmStringMapper("authorTeamFk", "authorTeamFk"),
500 // new CdmStringMapper("exAuthorTeamFk", "exAuthorTeamFk"),
501 // new CdmStringMapper("basAuthorTeamFk", "basAuthorTeamFk"),
502 // new CdmStringMapper("exBasAuthorTeamFk", "exBasAuthorTeamFk"),
503 // new CdmStringMapper("hybridFormulaFlag", "hybridFormulaFlag"),
504 // new CdmStringMapper("monomHybFlag", "monomHybFlag"),
505 // new CdmStringMapper("binomHybFlag", "binomHybFlag"),
506 // new CdmStringMapper("trinomHybFlag", "trinomHybFlag"),
507 // new CdmStringMapper("cultivarGroupName", "cultivarGroupName"),
508 // new CdmStringMapper("cultivarName", "cultivarName"),
509 // new CdmStringMapper("nomRefFk", "nomRefFk"),
510 // new CdmStringMapper("nomRefDetailFk", "nomRefDetailFk"),
511 // new CdmStringMapper("nameSourceRefFk", "nameSourceRefFk"),
512 // new CdmStringMapper("source_Acc", "source_Acc"),
513 // new CdmStringMapper("created_When", "created_When"),
514 // new CdmStringMapper("created_Who", "created_Who"),
515 // new CdmStringMapper("notes", "notes"),
516 // new CdmStringMapper("parsingComments", "parsingComments"),
517 // new CdmStringMapper("oldNomRefFk", "oldNomRefFk"),
518 // new CdmStringMapper("oldNomRefDetailFk", "oldNomRefDetailFk"),
519 // new CdmStringMapper("updated_Who", "updated_Who"),
520 // new CdmStringMapper("orthoProjection", "orthoProjection"),