org.gbif.ipt.action.manage.TranslationAction.java Source code

Java tutorial

Introduction

Here is the source code for org.gbif.ipt.action.manage.TranslationAction.java

Source

/***************************************************************************
 * 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;
    }
}