/* * Copyright (C) 2012 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.common.mods.custom; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Set; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlElement; import cz.cas.lib.proarc.common.mods.custom.ArrayMapper.ArrayItem; import cz.cas.lib.proarc.common.mods.custom.NameMapper.NameItem.NameRole; import cz.cas.lib.proarc.mods.CodeOrText; import cz.cas.lib.proarc.mods.ModsDefinition; import cz.cas.lib.proarc.mods.NameDefinition; import cz.cas.lib.proarc.mods.NamePartDefinition; import cz.cas.lib.proarc.mods.ObjectFactory; import cz.cas.lib.proarc.mods.RoleDefinition; import cz.cas.lib.proarc.mods.RoleTermDefinition; /** * Usage: * <pre> * {@code // read List<NameItem> all = map(mods); List<NameItem> authors = filter(all, true, NameRole.AUTHOR); List<NameItem> contributors = filter(all, true, NameRole.CONTRIBUTOR); // write all = map(mods); List<NameItem> others = filter(all, false, NameRole.AUTHOR, NameRole.CONTRIBUTOR); List<NameItem> news = MapperUtils.mergeList(cast(authors, NameRole.AUTHOR), cast(contributors, NameRole.CONTRIBUTOR), others); map(mods, news); * } * </pre> * * {@code mods/name/namePart[@type={family,given}]} * {@code mods/name/role/roleTerm/[@type={CODE,TEXT}]}, see * authors:[{family:'', given:''}] * XXX names can be of type personal, corporate, conference, family * * @author Jan Pokorsky */ final class NameMapper { public static final String TYPE_PERSONAL = "personal"; ArrayMapper<NameDefinition, NameItem> nameMap = new ArrayMapper<>(new NameItemMapper()); public List<NameItem> map(ModsDefinition mods) { List<NameDefinition> names = mods.getName(); return nameMap.map(names); } public ModsDefinition map(ModsDefinition mods, List<NameItem> authors, List<NameItem> contributors) { List<NameItem> oldItems = map(mods); List<NameItem> others = filter(oldItems, true, NameRole.OTHER); List<NameItem> names = MapperUtils.mergeList( cast(MapperUtils.noNull(authors), NameRole.AUTHOR), cast(MapperUtils.noNull(contributors), NameRole.CONTRIBUTOR), others); return map(mods, names); } public ModsDefinition map(ModsDefinition mods, List<NameItem> names) { List<NameDefinition> oldies = mods.getName(); List<NameDefinition> news = nameMap.map(MapperUtils.noNull(names), oldies); oldies.clear(); oldies.addAll(news); return mods; } public static List<NameItem> filter(List<NameItem> names, boolean include, NameRole first, NameRole... rest) { return filter(names, EnumSet.of(first, rest), include); } public static List<NameItem> filter(List<NameItem> names, Set<NameRole> filter, boolean include) { List<NameItem> result = new ArrayList<>(); for (NameItem name : names) { boolean contains = filter.contains(name.getRole()); if ((include == true && include == contains) || (include == false && include == contains)) { result.add(name); } } return result; } /** * Ensures that items belongs to role. */ public static List<NameItem> cast(List<NameItem> items, NameRole role) { for (NameItem item : items) { item.setRole(role); } return items; } private static final class NameItemMapper implements ArrayMapper.ItemMapper<NameDefinition, NameItem> { private static final String TYPE_FAMILY = "family"; private static final String TYPE_GIVEN = "given"; private final ObjectFactory factory = new ObjectFactory(); @Override public NameItem map(NameDefinition source) { NameItem result = new NameItem(); int familyCount = 0; int givenCount = 0; for (RoleDefinition role : source.getRole()) { if (result.getRole() != null && result.getRole() != NameRole.OTHER) { continue; } result.setRole(NameRole.fromDom(role)); } for (NamePartDefinition namePart : source.getNamePart()) { if (familyCount == 0 || givenCount == 0) { String type = namePart.getType(); String partValue = namePart.getValue(); if (familyCount == 0 && TYPE_FAMILY.equals(type)) { result.setFamily(partValue); ++familyCount; } else if (givenCount == 0 && TYPE_GIVEN.equals(type)) { result.setGiven(partValue); ++givenCount; } } } return result; } @Override public NameDefinition map(final NameItem item, final NameDefinition origin) { if (item.getRole() == NameRole.OTHER) { return origin; } int familyCount = 0; int givenCount = 0; NameDefinition result = origin != null ? origin : new NameDefinition(); for (NamePartDefinition namePart : result.getNamePart()) { String type = namePart.getType(); if (familyCount == 0 && TYPE_FAMILY.equals(type)) { namePart.setValue(item.getFamily()); ++familyCount; } else if (givenCount == 0 && TYPE_GIVEN.equals(type)) { namePart.setValue(item.getGiven()); ++givenCount; } if (familyCount > 0 && givenCount > 0) { break; } } if (familyCount == 0 && item.getFamily() != null) { createPartName(result, TYPE_FAMILY, item.getFamily()); } if (givenCount == 0 && item.getGiven() != null) { createPartName(result, TYPE_GIVEN, item.getGiven()); } if (origin == null) { // new item result.setType(TYPE_PERSONAL); createRole(result, item.getRole()); } return result; } private void createPartName(NameDefinition nameType, String type, String name) { NamePartDefinition namePart = factory.createNamePartDefinition(); namePart.setType(type); namePart.setValue(name); nameType.getNamePart().add(namePart); } private void createRole(NameDefinition name, NameRole role) { RoleDefinition roleType = factory.createRoleDefinition(); RoleTermDefinition roleTerm = factory.createRoleTermDefinition(); roleTerm.setType(CodeOrText.CODE); roleTerm.setValue(role.getCode()); roleType.getRoleTerm().add(roleTerm); roleTerm = factory.createRoleTermDefinition(); roleTerm.setType(CodeOrText.TEXT); roleTerm.setValue(role.getText()); roleType.getRoleTerm().add(roleTerm); name.getRole().add(roleType); } } @javax.xml.bind.annotation.XmlAccessorType(XmlAccessType.FIELD) public static class NameItem implements ArrayItem { private Integer index; @XmlElement(name = ModsConstants.FIELD_NAME_FAMILY) private String family; @XmlElement(name = ModsConstants.FIELD_NAME_GIVEN) private String given; private transient NameRole role; public enum NameRole { AUTHOR("cre", "Author"), CONTRIBUTOR("ctb", "Contributor"), OTHER("undefined", "undefined"); private String code; private String text; private NameRole(String code, String text) { this.code = code; this.text = text; } public String getCode() { return code; } public String getText() { return text; } public static NameRole fromCode(String code) { for (NameRole role : values()) { if (role.getCode().equals(code)) { return role; } } return OTHER; } public static NameRole fromText(String text) { for (NameRole role : values()) { if (role.getText().equals(text)) { return role; } } return OTHER; } private static NameRole fromDom(RoleDefinition... roles) { NameRole result = NameRole.OTHER; for (RoleDefinition role : roles) { for (RoleTermDefinition roleTerm : role.getRoleTerm()) { switch (roleTerm.getType()) { case CODE: return fromCode(roleTerm.getValue()); case TEXT: return fromText(roleTerm.getValue()); } } } return result; } } public NameItem(Integer index, String family, String given, NameRole role) { this.index = index; this.family = MapperUtils.normalize(family); this.given = MapperUtils.normalize(given); this.role = role; } public NameItem(String family, String given, NameRole role) { this(null, family, given, role); } public NameItem() { } @Override public Integer getArrayIndex() { return index; } @Override public void setArrayIndex(Integer index) { this.index = index; } public String getFamily() { return family; } public void setFamily(String family) { this.family = MapperUtils.normalize(family); } public String getGiven() { return given; } public void setGiven(String given) { this.given = MapperUtils.normalize(given); } public NameRole getRole() { return role; } public void setRole(NameRole role) { this.role = role; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NameItem other = (NameItem) obj; if ((this.family == null) ? (other.family != null) : !this.family.equals(other.family)) { return false; } if ((this.given == null) ? (other.given != null) : !this.given.equals(other.given)) { return false; } if (this.role != other.role) { return false; } return true; } @Override public String toString() { return String.format("NameValue{family=%s, given=%s, role=%s, index=%s}", family, given, role, index); } } }