Java tutorial
/*************************************************************************** * Copyright 2010 Global Biodiversity Information Facility Secretariat * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. ***************************************************************************/ package org.gbif.ipt.action.manage; import org.gbif.dwc.terms.Term; import org.gbif.ipt.config.AppConfig; import org.gbif.ipt.model.Extension; import org.gbif.ipt.model.ExtensionMapping; import org.gbif.ipt.model.ExtensionProperty; import org.gbif.ipt.model.PropertyMapping; import org.gbif.ipt.model.Vocabulary; import org.gbif.ipt.model.VocabularyConcept; import org.gbif.ipt.service.SourceException; import org.gbif.ipt.service.admin.RegistrationManager; import org.gbif.ipt.service.admin.VocabulariesManager; import org.gbif.ipt.service.manage.ResourceManager; import org.gbif.ipt.service.manage.SourceManager; import org.gbif.ipt.struts2.SimpleTextProvider; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import com.google.common.base.Strings; import com.google.inject.Inject; import com.google.inject.servlet.SessionScoped; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; public class TranslationAction extends ManagerBaseAction { private static final long serialVersionUID = -8350422710092468050L; // logging private static final Logger LOG = Logger.getLogger(TranslationAction.class); @SessionScoped static class Translation { private String rowType; private Term term; private TreeMap<String, String> sourceValues; private TreeMap<String, String> translatedValues; /** * Return a map populated with all source value to translated value pairs. */ public Map<String, String> getPersistentMap() { Map<String, String> m = new HashMap<String, String>(); for (Entry<String, String> translatedValueEntry : translatedValues.entrySet()) { if (!Strings.isNullOrEmpty(translatedValueEntry.getValue())) { m.put(sourceValues.get(translatedValueEntry.getKey()), translatedValueEntry.getValue().trim()); } } return m; } /** * @return map with original source values, e.g. {"k1", "Obs"}. */ public Map<String, String> getSourceValues() { return sourceValues; } /** * @return map with translated values, e.g. {"k1", "Observation"}. Entries relate to entries in sourceValues by * via their key. */ public Map<String, String> getTranslatedValues() { return translatedValues; } /** * Check whether the translation has been loaded already. Call to prevent reloading original source values each * time translation page gets loaded, for example. * * @param rowType to which Term belongs * @param term Term * @return true if the translation has been loaded already, false otherwise */ public boolean isLoaded(String rowType, Term term) { return this.rowType != null && this.rowType.equals(rowType) && this.term != null && this.term.equals(term) && sourceValues != null; } public void setTmap(String rowType, Term term, TreeMap<String, String> sourceValues, TreeMap<String, String> translatedValues) { this.sourceValues = sourceValues; this.translatedValues = translatedValues; this.rowType = rowType; this.term = term; } } private SourceManager sourceManager; private VocabulariesManager vocabManager; private Translation trans; protected static final String REQ_PARAM_TERM = "term"; protected static final String REQ_PARAM_ROWTYPE = "rowtype"; protected static final String REQ_PARAM_MAPPINGID = "mid"; // config private PropertyMapping field; private ExtensionProperty property; private ExtensionMapping mapping; private Map<String, String> vocabTerms = new HashMap<String, String>(); private Integer mid; private String id; @Inject public TranslationAction(SimpleTextProvider textProvider, AppConfig cfg, RegistrationManager registrationManager, ResourceManager resourceManager, SourceManager sourceManager, VocabulariesManager vocabManager, Translation trans) { super(textProvider, cfg, registrationManager, resourceManager); this.sourceManager = sourceManager; this.vocabManager = vocabManager; this.trans = trans; defaultResult = SUCCESS; } /** * Automatically map source values to the terms in a vocabulary. A match occurs when the source value matches * against one of the vocabulary's term's name, preferred name, or alternate name. * * @return SUCCESS result, staying on translation page */ public String automap() { if (property == null || property.getVocabulary() == null) { addActionError(getText("manage.translation.cantfind.vocabulary")); } else { Vocabulary vocab = property.getVocabulary(); int count = 0; for (Entry<String, String> sourceValueEntry : getSourceValuesMap().entrySet()) { // only if not yet mapped if (!getTmap().containsValue(sourceValueEntry.getValue())) { VocabularyConcept vc = vocab.findConcept(sourceValueEntry.getValue()); if (vc != null) { getTmap().put(sourceValueEntry.getKey(), vc.getIdentifier()); count++; } } } addActionMessage(getText("manage.translation.mapped.terms", new String[] { String.valueOf(count) })); } return SUCCESS; } /** * Deletes the translation for the PropertyTerm. The sessionScoped translation must also be deleted, otherwise it * will reappear on the next page visit. The source values get reloaded so they are populated on next page visit. * * @return NONE result, going back to mapping page */ @Override public String delete() { // proceed with deletion if (field != null) { // 1. ensure the translation map on the PropertyMapping (field) is empty field.setTranslation(new TreeMap<String, String>()); // 2. ensure the static sessionScoped translation for this rowType and ConceptTerm is empty trans.setTmap(this.mapping.getExtension().getRowType(), property, new TreeMap<String, String>(), new TreeMap<String, String>()); // 3. save the resource saveResource(); // 4. add msg to appear in UI indicating the translation for this PropertyMapping has been deleted addActionMessage(getText("manage.translation.deleted", new String[] { field.getTerm().toString() })); // 5. reload source values, so they aren't empty on next page visit reloadSourceValues(); } else { LOG.error("User wanted to deleted translation for propertyMapping field, but field was null"); } // capture rowType, needed in redirect Extension ext = mapping.getExtension(); id = (ext != null) ? ext.getRowType() : null; // leaves translation page, goes back to mapping page return NONE; } @Override public void prepare() { super.prepare(); notFound = true; try { // get mapping sequence id from parameters as setters are not called yet String midStr = StringUtils.trimToNull(req.getParameter(REQ_PARAM_MAPPINGID)); if (midStr != null) { mid = Integer.valueOf(midStr); mapping = resource.getMapping(req.getParameter(REQ_PARAM_ROWTYPE), mid); } } catch (Exception e) { LOG.error("An exception was encountered: " + e.getMessage(), e); } if (mapping != null) { field = mapping.getField(req.getParameter(REQ_PARAM_TERM)); if (field != null) { notFound = false; property = mapping.getExtension().getProperty(field.getTerm()); if (property.getVocabulary() != null) { vocabTerms = vocabManager.getI18nVocab(property.getVocabulary().getUriString(), getLocaleLanguage(), true); } if (!trans.isLoaded(mapping.getExtension().getRowType(), field.getTerm())) { reloadSourceValues(); } } } } /** * Reload the source values, and display to the User this has happened. * * @return SUCCESS regardless of outcome */ public String reload() { reloadSourceValues(); // leaves the user on the translation page return SUCCESS; } /** * Clears the existing translation, reloads the source values, and repopulates existing translations. * The key of each entry in the translation.sourceValues map, e.g. {{"k1", "obs"}, {"k2", "spe"}} corresponds to each * entry in the translation.translatedValues map, e.g. {{"k1", "Observation"}, {"k2", "Specimen"}}. */ void reloadSourceValues() { try { String midStr = StringUtils.trimToNull(req.getParameter(REQ_PARAM_MAPPINGID)); if (midStr != null) { mid = Integer.valueOf(midStr); mapping = resource.getMapping(req.getParameter(REQ_PARAM_ROWTYPE), mid); } // reinitialize translation, including maps trans.setTmap(this.mapping.getExtension().getRowType(), property, new TreeMap<String, String>(), new TreeMap<String, String>()); // reload new values int i = 1; for (String val : sourceManager.inspectColumn(mapping.getSource(), field.getIndex(), 1000, 10000)) { StringBuilder key = new StringBuilder(); key.append('k'); key.append(i); getSourceValuesMap().put(key.toString(), val); i++; } // keep existing translations if (field.getTranslation() != null) { for (Entry<String, String> entry : field.getTranslation().entrySet()) { // only keep entries with values mapped that exist in the newly reloaded map if (entry.getValue() != null && getSourceValuesMap().containsValue(entry.getKey())) { for (Entry<String, String> sourceValueEntry : getSourceValuesMap().entrySet()) { if (sourceValueEntry.getValue().equals(entry.getKey())) { getTmap().put(sourceValueEntry.getKey(), entry.getValue()); } } } } } // bring it to user's attention, that the source values have been reloaded addActionMessage(getText("manage.translation.reloaded.values", new String[] { String.valueOf(getSourceValuesMap().size()), field.getTerm().toString() })); } catch (SourceException e) { // if an error has occurred, bring it to the user's attention addActionError(getText("manage.translation.reloaded.fail", new String[] { field.getTerm().toString(), e.getMessage() })); } } /** * Persist the translation for the PropertyTerm by saving the Resource anew, and display to the User this happened. * * @return NONE result, going back to mapping page */ @Override public String save() { // put map with non empty values back to field field.setTranslation(trans.getPersistentMap()); // save entire resource config saveResource(); id = mapping.getExtension().getRowType(); addActionMessage(getText("manage.translation.saved", new String[] { field.getTerm().toString() })); return NONE; } public PropertyMapping getField() { return field; } @Override public String getId() { return id; } public Integer getMid() { return mid; } public ExtensionProperty getProperty() { return property; } public Map<String, String> getSourceValuesMap() { return trans.getSourceValues(); } public Map<String, String> getTmap() { return trans.getTranslatedValues(); } public Map<String, String> getVocabTerms() { return vocabTerms; } /** * On submitting the translation form sets the translated values map, named "tmap". * * @param translatedValues map with translated values, whose key corresponds to translation.sourceValues map */ public void setTmap(TreeMap<String, String> translatedValues) { this.trans.translatedValues = translatedValues; } public Translation getTrans() { return trans; } public void setField(PropertyMapping field) { this.field = field; } public void setProperty(ExtensionProperty property) { this.property = property; } /** * setMapping method name interrupts with Struts2/freemarker page. * * @param mapping ExtensionMapping */ public void setExtensionMapping(ExtensionMapping mapping) { this.mapping = mapping; } }