gov.va.isaac.gui.listview.operations.FindAndReplace.java Source code

Java tutorial

Introduction

Here is the source code for gov.va.isaac.gui.listview.operations.FindAndReplace.java

Source

/**
 * Copyright Notice
 * 
 * This is a work of the U.S. Government and is not subject to copyright
 * protection in the United States. Foreign copyrights may apply.
 * 
 * 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 gov.va.isaac.gui.listview.operations;

import gov.va.isaac.ExtendedAppContext;
import gov.va.isaac.gui.SimpleDisplayConcept;
import gov.va.isaac.gui.listview.operations.FindAndReplaceController.DescriptionType;
import gov.va.isaac.util.OTFUtility;

import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javafx.beans.binding.BooleanExpression;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;

import org.apache.commons.lang3.StringUtils;
import org.glassfish.hk2.api.PerLookup;
import org.ihtsdo.otf.tcc.api.blueprint.DescriptionCAB;
import org.ihtsdo.otf.tcc.api.blueprint.IdDirective;
import org.ihtsdo.otf.tcc.api.blueprint.InvalidCAB;
import org.ihtsdo.otf.tcc.api.blueprint.RefexDirective;
import org.ihtsdo.otf.tcc.api.concept.ConceptVersionBI;
import org.ihtsdo.otf.tcc.api.contradiction.ContradictionException;
import org.ihtsdo.otf.tcc.api.description.DescriptionChronicleBI;
import org.ihtsdo.otf.tcc.api.description.DescriptionVersionBI;
import org.jvnet.hk2.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link FindAndReplace}
 * 
 * A Find / Replace operation, mostly ported from the SearchReplaceDialog in TK2
 *
 * @author <a href="mailto:daniel.armbrust.list@gmail.com">Dan Armbrust</a>
 */
@Service
@PerLookup
public class FindAndReplace extends Operation {

    private FindAndReplaceController frc_;
    private Logger logger_ = LoggerFactory.getLogger(this.getClass());
    private Map<String, Set<String>> successCons = new HashMap<>();

    private FindAndReplace() {
        //For HK2 to init
    }

    @Override
    public void init(ObservableList<SimpleDisplayConcept> conceptList) {
        super.init(conceptList);
        try {
            URL resource = FindAndReplace.class.getResource("FindAndReplaceController.fxml");
            FXMLLoader loader = new FXMLLoader(resource);
            loader.load();
            frc_ = loader.getController();
            super.root_ = frc_.getRoot();
        } catch (IOException e) {
            logger_.error("Unexpected error building panel", e);
            throw new RuntimeException("Error building panel");
        }
    }

    /**
     * @see gov.va.isaac.gui.listview.operations.Operation#getTitle()
     */
    @Override
    public String getTitle() {
        return "Find and Replace";
    }

    /**
     * @see gov.va.isaac.gui.listview.operations.Operation#conceptListChanged()
     */
    @Override
    protected void conceptListChanged() {
        //noop
    }

    /**
     * @see gov.va.isaac.gui.listview.operations.Operation#isValid()
     */
    @Override
    public BooleanExpression isValid() {
        return frc_.allFieldsValid();
    }

    /**
     * @see gov.va.isaac.gui.listview.operations.Operation#getOperationDescription()
     */
    @Override
    public String getOperationDescription() {
        return "Perform a Find and Replace operation on content in the database";
    }

    /**
     * @see gov.va.isaac.gui.listview.operations.Operation#createTask()
     */
    @Override
    public CustomTask<OperationResult> createTask() {
        return new CustomTask<OperationResult>(FindAndReplace.this) {
            private Matcher matcher;

            @Override
            protected OperationResult call() throws Exception {
                double i = 0;
                successCons.clear();
                Set<SimpleDisplayConcept> modifiedConcepts = new HashSet<SimpleDisplayConcept>();
                for (SimpleDisplayConcept c : conceptList_) {
                    if (cancelRequested_) {
                        return new OperationResult(FindAndReplace.this.getTitle(), cancelRequested_);
                    }

                    String newTxt = null;
                    Set<String> successMatches = new HashSet<>();

                    updateProgress(i, conceptList_.size());
                    updateMessage("Processing " + c.getDescription());

                    // For each concept, filter the descriptions to be changed based on user selected DescType
                    ConceptVersionBI con = OTFUtility.getConceptVersion(c.getNid());
                    Set<DescriptionVersionBI<?>> descsToChange = getDescsToChange(con);

                    for (DescriptionVersionBI<?> desc : descsToChange) {
                        // First see if text is found in desc before moving onward
                        if (frc_.isRegExp() && hasRegExpMatch(desc) || !frc_.isRegExp() && hasGenericMatch(desc)) {

                            // Now check if language is selected, that it exists in language refset
                            if (frc_.getLanguageRefset().getNid() == 0
                                    || !desc.getAnnotationsActive(OTFUtility.getViewCoordinate(),
                                            frc_.getLanguageRefset().getNid()).isEmpty()) {

                                // Replace Text
                                if (frc_.isRegExp()) {
                                    newTxt = replaceRegExp();
                                } else {
                                    newTxt = replaceGeneric(desc);
                                }

                                DescriptionType descType = getDescType(con, desc);
                                successMatches.add("    --> '" + desc.getText() + "' changed to '" + newTxt
                                        + "' ..... of type: " + descType);
                                updateDescription(desc, newTxt);
                            }
                        }
                    }
                    if (successMatches.size() > 0) {
                        modifiedConcepts.add(c);
                        successCons.put(c.getDescription() + " --- " + con.getPrimordialUuid().toString(),
                                successMatches);
                    }

                    updateProgress(++i, conceptList_.size());
                }

                return new OperationResult(FindAndReplace.this.getTitle(), modifiedConcepts, getMsgBuffer());
            }

            private boolean hasRegExpMatch(DescriptionVersionBI<?> desc) {
                Pattern pattern = Pattern.compile(frc_.getSearchText());

                matcher = pattern.matcher(desc.getText());

                if (matcher.find()) {
                    return true;
                } else {
                    return false;
                }
            }

            private String replaceRegExp() {
                // Replace all occurrences of pattern in input
                return matcher.replaceAll(frc_.getReplaceText());
            }

            private String replaceGeneric(DescriptionVersionBI<?> desc) {
                String txt = desc.getText();

                if (frc_.isCaseSens()) {
                    while (txt.contains(frc_.getSearchText())) {
                        txt = txt.replace(frc_.getSearchText(), frc_.getReplaceText());
                    }
                } else {
                    int startIdx = StringUtils.indexOfIgnoreCase(txt, frc_.getSearchText());
                    int endIdx = startIdx + frc_.getSearchText().length();

                    while (startIdx >= 0) {
                        StringBuffer buf = new StringBuffer(txt);
                        buf.replace(startIdx, endIdx, frc_.getReplaceText());
                        txt = buf.toString();

                        startIdx = StringUtils.indexOfIgnoreCase(txt, frc_.getSearchText());
                    }
                }

                return txt;
            }

            private boolean hasGenericMatch(DescriptionVersionBI<?> desc) {
                String txt = desc.getText();

                if (frc_.isCaseSens()) {
                    if (!txt.contains(frc_.getSearchText())) {
                        return false;
                    }
                } else {
                    if (!StringUtils.containsIgnoreCase(txt, frc_.getSearchText())) {
                        return false;
                    }
                }

                return true;
            }

            private void updateDescription(DescriptionVersionBI<?> desc, String newTxt)
                    throws IOException, InvalidCAB, ContradictionException {
                DescriptionCAB dcab = desc.makeBlueprint(OTFUtility.getViewCoordinate(), IdDirective.PRESERVE,
                        RefexDirective.INCLUDE);
                dcab.setText(newTxt);
                DescriptionChronicleBI dcbi = OTFUtility.getBuilder().constructIfNotCurrent(dcab);
                ExtendedAppContext.getDataStore()
                        .addUncommitted(ExtendedAppContext.getDataStore().getConceptForNid(dcbi.getConceptNid()));
            }

            private Set<DescriptionVersionBI<?>> getDescsToChange(ConceptVersionBI con) {
                Set<DescriptionVersionBI<?>> descsToChange = new HashSet<>();

                try {
                    for (DescriptionVersionBI<?> desc : con.getDescriptionsActive()) {

                        if (frc_.getSelectedDescTypes().contains(DescriptionType.FSN)
                                && con.getFullySpecifiedDescription().getNid() == desc.getNid()) {
                            descsToChange.add(desc);
                        } else if (frc_.getSelectedDescTypes().contains(DescriptionType.PT)
                                && con.getPreferredDescription().getNid() == desc.getNid()) {
                            descsToChange.add(desc);
                        } else if (frc_.getSelectedDescTypes().contains(DescriptionType.SYNONYM)
                                && con.getFullySpecifiedDescription().getNid() != desc.getNid()
                                && con.getPreferredDescription().getNid() != desc.getNid()) {
                            descsToChange.add(desc);
                        }
                    }
                } catch (IOException | ContradictionException e) {
                    // TODO (artf231875) Auto-generated catch block
                    e.printStackTrace();
                }

                return descsToChange;
            }

            private DescriptionType getDescType(ConceptVersionBI con, DescriptionVersionBI<?> desc)
                    throws IOException, ContradictionException {
                // TODO (artf231875) Auto-generated method stub
                if (con.getFullySpecifiedDescription().getNid() == desc.getNid()) {
                    return DescriptionType.FSN;
                } else if (con.getPreferredDescription().getNid() == desc.getNid()) {
                    return DescriptionType.PT;
                } else {
                    return DescriptionType.SYNONYM;
                }
            }
        };
    }

    protected String getMsgBuffer() {
        StringBuffer buf = new StringBuffer();

        if (successCons.keySet().size() == 1) {
            buf.append(this.getTitle() + " completed with changes to " + successCons.keySet().size() + " concept.");
        } else {
            buf.append(
                    this.getTitle() + " completed with changes to " + successCons.keySet().size() + " concepts.");
        }

        for (String conStr : successCons.keySet()) {
            buf.append("\n\r\n\rConcept: " + conStr);

            for (String replace : successCons.get(conStr)) {
                buf.append("\n\r" + replace);
            }
        }

        return buf.toString();
    }
}