net.geoprism.ontology.Classifier.java Source code

Java tutorial

Introduction

Here is the source code for net.geoprism.ontology.Classifier.java

Source

/**
 * Copyright (c) 2015 TerraFrame, Inc. All rights reserved.
 *
 * This file is part of Runway SDK(tm).
 *
 * Runway SDK(tm) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Runway SDK(tm) 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with Runway SDK(tm).  If not, see <http://www.gnu.org/licenses/>.
 */
package net.geoprism.ontology;

import java.sql.Savepoint;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import net.geoprism.TermSynonymRelationship;

import org.apache.commons.lang.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.runwaysdk.business.BusinessFacade;
import com.runwaysdk.business.Relationship;
import com.runwaysdk.business.ontology.OntologyStrategyIF;
import com.runwaysdk.business.ontology.Term;
import com.runwaysdk.business.ontology.TermAndRel;
import com.runwaysdk.dataaccess.BusinessDAOIF;
import com.runwaysdk.dataaccess.DuplicateDataException;
import com.runwaysdk.dataaccess.MdAttributeTermDAOIF;
import com.runwaysdk.dataaccess.ProgrammingErrorException;
import com.runwaysdk.dataaccess.database.BusinessDAOFactory;
import com.runwaysdk.dataaccess.database.Database;
import com.runwaysdk.dataaccess.transaction.Transaction;
import com.runwaysdk.query.AttributeReference;
import com.runwaysdk.query.OIterator;
import com.runwaysdk.query.OR;
import com.runwaysdk.query.QueryFactory;
import com.runwaysdk.system.gis.geo.GeoEntity;
import com.runwaysdk.system.metadata.ontology.DatabaseAllPathsStrategy;

public class Classifier extends ClassifierBase implements com.runwaysdk.generation.loader.Reloadable {
    private static final long serialVersionUID = 1158111601;

    private static final String KEY_CONCATENATOR = ".";

    public Classifier() {
        super();
    }

    /**
     * Persists this Classifier, performs validation on its values, and generates a UniqueId from the display label, if
     * necessary.
     */
    @Override
    @Transaction
    public void apply() {
        // If they didn't specify a UniqueId we can figure one out from the DisplayLabel
        if (this.getClassifierId() == null || this.getClassifierId().length() == 0) {
            String uniqueId = this.getDisplayLabel().getValue().trim().replaceAll("\\s+", "");
            this.setClassifierId(uniqueId);
        }

        super.apply();

        if (this.isNew()) {
            this.addTerm(ClassifierIsARelationship.CLASS);
        }
    }

    public static String buildKey(String pkg, String id) {
        return pkg + KEY_CONCATENATOR + id;
    }

    @Override
    public String buildKey() {
        return Classifier.buildKey(this.getClassifierPackage(), this.getClassifierId());
    }

    @Override
    @Transaction
    public void delete() {
        this.delete(new TreeSet<Classifier>(new Comparator<Classifier>() {
            @Override
            public int compare(Classifier o1, Classifier o2) {
                return o1.getId().compareTo(o2.getId());
            }
        }));
    }

    private void delete(Set<Classifier> orphans) {
        ClassifierProblem.deleteProblems(this);

        /*
         * Delete all synonyms
         */
        List<? extends ClassifierSynonym> synonyms = this.getAllHasSynonym().getAll();

        for (ClassifierSynonym synonym : synonyms) {
            synonym.delete();
        }

        super.delete();

        /*
         * Delete all orphaned children
         */
        QueryFactory factory = new QueryFactory();

        ClassifierQuery query = new ClassifierQuery(factory);
        query.WHERE(query.NOT_IN_isAParent());
        query.AND(query.getId().NE(Classifier.getRoot().getId()));

        OIterator<? extends Classifier> iterator = null;

        try {
            iterator = query.getIterator();

            orphans.addAll(iterator.getAll());
        } finally {
            if (iterator != null) {
                iterator.close();
            }
        }

        Iterator<Classifier> it = orphans.iterator();

        if (it.hasNext()) {
            Classifier classifier = it.next();
            it.remove();

            classifier.delete(orphans);
        }
    }

    /**
     * Returns the <code>Classifier</code> object with a label or synonym that matches the given term. Searches all nodes
     * that are children of the given attribute root nodes including the root nodes.
     * 
     * @param sfTermToMatch
     * @param mdAttributeTermDAO
     * @return the <code>Classifier</code> object with a label or synonym that matches the given term.
     */
    public static Classifier findMatchingTerm(String sfTermToMatch, MdAttributeTermDAOIF mdAttributeTermDAOIF) {
        QueryFactory qf = new QueryFactory();

        ClassifierQuery classifierRootQ = new ClassifierQuery(qf);
        ClassifierTermAttributeRootQuery carQ = new ClassifierTermAttributeRootQuery(qf);
        ClassifierQuery classifierQ = new ClassifierQuery(qf);
        ClassifierAllPathsTableQuery allPathsQ = new ClassifierAllPathsTableQuery(qf);
        ClassifierSynonymQuery synonymQ = new ClassifierSynonymQuery(qf);

        carQ.WHERE(carQ.getParent().EQ(mdAttributeTermDAOIF));

        classifierRootQ.WHERE(classifierRootQ.classifierTermAttributeRoots(carQ));

        allPathsQ.WHERE(allPathsQ.getParentTerm().EQ(classifierRootQ));

        synonymQ.WHERE(synonymQ.getDisplayLabel().localize().EQ(sfTermToMatch));

        classifierQ.WHERE(
                OR.get(classifierQ.getDisplayLabel().localize().EQ(sfTermToMatch), classifierQ.hasSynonym(synonymQ))
                        .AND(classifierQ.EQ(allPathsQ.getChildTerm())));

        OIterator<? extends Classifier> i = classifierQ.getIterator();
        try {
            for (Classifier classifier : i) {
                return classifier;
            }
        } finally {
            i.close();
        }
        return null;
    }

    /**
     * MdMethod used for creating Classifiers.
     * 
     * @param termId
     * @param name
     * @return
     */
    @Transaction
    public static TermAndRel create(Classifier dto, String parentId) {
        Classifier parent = Classifier.get(parentId);

        // If they didn't specify a package we can attempt to figure one out for them.
        if (dto.getClassifierPackage() == null || dto.getClassifierPackage().length() == 0) {
            String camelUniqueId = StringUtils.uncapitalize(parent.getClassifierId().trim().replaceAll("\\s+", ""));

            if (Classifier.getRoot().equals(parent)) {
                dto.setClassifierPackage(camelUniqueId);
            } else {
                dto.setClassifierPackage(parent.getClassifierPackage() + KEY_CONCATENATOR + camelUniqueId);
            }
        }

        dto.apply();

        Relationship rel = dto.addLink(parent, ClassifierIsARelationship.CLASS);

        return new TermAndRel(dto, ClassifierIsARelationship.CLASS, rel.getId());
    }

    public static OntologyStrategyIF createStrategy() {
        return new DatabaseAllPathsStrategy();
    }

    public static Classifier getRoot() {
        return (Classifier) Term.getRoot(Classifier.CLASS);
    }

    /**
     * Returns the JSONObject representation of the node and all of its children nodes
     * 
     * @return
     */
    public JSONObject getJSONObject() {
        try {
            JSONArray children = new JSONArray();
            OIterator<Term> iterator = null;

            try {
                iterator = this.getDirectDescendants(ClassifierIsARelationship.CLASS);

                List<Term> terms = iterator.getAll();

                for (Term term : terms) {
                    Classifier child = (Classifier) term;

                    children.put(child.getJSONObject());
                }

            } finally {
                if (iterator != null) {
                    iterator.close();
                }
            }

            JSONObject object = new JSONObject();
            object.put("label", this.getDisplayLabel().getValue());
            object.put("id", this.getId());
            object.put("type", this.getType());
            object.put("children", children);
            object.put("fetched", true);

            return object;
        } catch (JSONException e) {
            throw new ProgrammingErrorException(e);
        }
    }

    /**
     * Finds the classifier with the given label for the given term attribute. If the classifier does not exist, then it
     * is created.
     * 
     * @param classifierLabel
     * @param mdAttributeTermDAO
     * @return
     */
    @Transaction
    public static Classifier findClassifierAddIfNotExist(String packageString, String classifierLabel,
            MdAttributeTermDAOIF mdAttributeTermDAO) {
        return Classifier.findClassifierAddIfNotExist(packageString, classifierLabel, mdAttributeTermDAO, false);
    }

    /**
     * Finds the classifier with the given label for the given term attribute. If the classifier does not exist, then it
     * is created.
     * 
     * @param packageString
     * @param classifierLabel
     * @param mdAttributeTermDAO
     * @param createProblem
     *          Flag indicating if a ClassifierProblem should be created when a new classifier is created
     * @return
     */
    @Transaction
    public static Classifier findClassifierAddIfNotExist(String packageString, String classifierLabel,
            MdAttributeTermDAOIF mdAttributeTermDAO, boolean createProblem) {
        Classifier classifier = findMatchingTerm(classifierLabel, mdAttributeTermDAO);

        if (classifier == null) {
            classifier = new Classifier();
            classifier.getDisplayLabel().setDefaultValue(classifierLabel);
            classifier.setClassifierId(classifierLabel);
            classifier.setClassifierPackage(packageString);
            classifier.apply();

            // Create a new Classifier problem
            if (createProblem) {
                ClassifierProblem.createProblems(classifier, ClassifierProblemType.UNMATCHED);
            }

            QueryFactory qf = new QueryFactory();

            ClassifierQuery classifierRootQ = new ClassifierQuery(qf);
            ClassifierTermAttributeRootQuery carQ = new ClassifierTermAttributeRootQuery(qf);

            carQ.WHERE(carQ.parentId().EQ(mdAttributeTermDAO.getId()));

            classifierRootQ.WHERE(classifierRootQ.classifierTermAttributeRoots(carQ));

            OIterator<? extends Classifier> i = classifierRootQ.getIterator();
            try {
                for (Classifier classifierRoot : i) {
                    classifier.addLink(classifierRoot, ClassifierIsARelationship.CLASS);
                }
            } finally {
                i.close();
            }
        }

        return classifier;
    }

    @Transaction
    public static String[] restoreSynonym(String synonymId) {
        ClassifierSynonym synonym = ClassifierSynonym.get(synonymId);
        Classifier[] classifiers = synonym.restore();

        Set<String> ids = new TreeSet<String>();

        for (Classifier classifier : classifiers) {
            ids.add(classifier.getId());
        }

        return ids.toArray(new String[ids.size()]);
    }

    @Transaction
    public static String[] makeSynonym(String sourceId, String destinationId) {
        Classifier source = Classifier.get(sourceId);
        Classifier destination = Classifier.get(destinationId);

        ClassifierIsARelationshipQuery query = new ClassifierIsARelationshipQuery(new QueryFactory());
        query.WHERE(query.getChild().EQ(source));

        OIterator<? extends ClassifierIsARelationship> iterator = query.getIterator();

        List<String> ids = new LinkedList<String>();

        try {
            while (iterator.hasNext()) {
                ClassifierIsARelationship locatedIn = iterator.next();

                ids.add(locatedIn.getParentId());
            }
        } finally {
            iterator.close();
        }

        makeSynonym(source, destination);

        ids.add(destinationId);

        return ids.toArray(new String[ids.size()]);
    }

    @Transaction
    public static ClassifierSynonym makeSynonym(Classifier source, Classifier destination) {
        // Delete all problems for the source geo classifier so that they aren't transfered over to the destination
        // classifier
        ClassifierProblemQuery problemQuery = new ClassifierProblemQuery(new QueryFactory());
        problemQuery.WHERE(problemQuery.getClassifier().EQ(source));

        OIterator<? extends ClassifierProblem> iterator = problemQuery.getIterator();

        try {
            while (iterator.hasNext()) {
                ClassifierProblem problem = iterator.next();
                problem.delete();
            }
        } finally {
            iterator.close();
        }

        /*
         * Create the new synonym
         */
        ClassifierSynonym synonym = createSynonym(destination, source.getDisplayLabel().getValue());

        /*
         * Log the original synonym value in the data records in case of a role back
         */
        if (synonym != null) {
            TermSynonymRelationship.logSynonymData(source, synonym.getId(), Classifier.CLASS);
        } else {
            String label = source.getDisplayLabel().getValue();

            List<ClassifierSynonym> synonyms = ClassifierSynonym.getSynonyms(destination, label);

            for (ClassifierSynonym existingSynonym : synonyms) {
                TermSynonymRelationship.logSynonymData(source, existingSynonym.getId(), GeoEntity.CLASS);
            }
        }

        /*
         * Copy over any synonyms to the destination and delete the originals
         */
        BusinessDAOIF sourceDAO = (BusinessDAOIF) BusinessFacade.getEntityDAO(source);

        BusinessDAOFactory.floatObjectIdReferencesDatabase(sourceDAO.getBusinessDAO(), source.getId(),
                destination.getId(), true);

        source.delete();

        return synonym;
    }

    private static ClassifierSynonym createSynonym(Classifier destination, String synonymName) {
        Savepoint savepoint = Database.setSavepoint();

        try {
            ClassifierSynonym synonym = new ClassifierSynonym();
            synonym.getDisplayLabel().setValue(synonymName);

            ClassifierSynonym.createSynonym(synonym, destination.getId());

            return synonym;
        } catch (DuplicateDataException e) {
            // Rollback the savepoint
            Database.rollbackSavepoint(savepoint);

            savepoint = null;
        } finally {
            if (savepoint != null) {
                Database.releaseSavepoint(savepoint);
            }
        }

        return null;
    }

    public static String getClassifierTree(String classifierId) {
        Classifier root = Classifier.getRoot();

        Classifier classifier = Classifier.get(classifierId);

        OIterator<Term> anscestorIt = classifier.getAllAncestors(ClassifierIsARelationship.CLASS);
        Set<String> ids = new HashSet<String>();

        try {
            while (anscestorIt.hasNext()) {
                Classifier ancestor = (Classifier) anscestorIt.next();

                if (!ancestor.getId().equals(root.getId())) {
                    ids.add(ancestor.getId());
                }
            }
        } finally {
            anscestorIt.close();
        }

        JSONArray array = new JSONArray();

        QueryFactory factory = new QueryFactory();

        ClassifierIsARelationshipQuery isAQuery = new ClassifierIsARelationshipQuery(factory);
        isAQuery.WHERE(isAQuery.getParent().EQ(root));
        isAQuery.AND(isAQuery.childId().IN(ids.toArray(new String[ids.size()])));

        ClassifierQuery query = new ClassifierQuery(factory);
        query.WHERE(query.isAParent(isAQuery));
        query.ORDER_BY_ASC(query.getDisplayLabel().localize());

        OIterator<? extends Classifier> classifierIt = query.getIterator();

        try {
            while (classifierIt.hasNext()) {
                Classifier parent = classifierIt.next();

                array.put(Classifier.getJSONObject(parent, ids, true));
            }
        } finally {
            classifierIt.close();
        }

        return array.toString();
    }

    /**
     * Returns the JSONObject representation of the node and all of its children nodes
     * 
     * @param _classifier
     *          Entity to serialize into a JSONObject
     * @param _ids
     *          List of classifier ids in which to include the children in the serialization
     * @param _isRoot
     *          Flag indicating if the classifier represents a root node of the tree
     * @return
     */
    private static JSONObject getJSONObject(Classifier _classifier, Set<String> _ids, boolean _isRoot) {
        try {
            JSONArray children = new JSONArray();

            if (_ids.contains(_classifier.getId())) {
                OIterator<? extends ClassifierIsARelationship> iterator = null;

                try {
                    // Get the relationships where this object is the parent

                    ClassifierIsARelationshipQuery query = new ClassifierIsARelationshipQuery(new QueryFactory());
                    query.WHERE(query.getParent().EQ(_classifier));
                    query.ORDER_BY_ASC(((AttributeReference) query.getChild())
                            .aLocalCharacter(Classifier.DISPLAYLABEL).localize());
                    iterator = query.getIterator();

                    List<? extends ClassifierIsARelationship> relationships = iterator.getAll();

                    for (ClassifierIsARelationship relationship : relationships) {
                        Classifier child = relationship.getChild();

                        JSONObject parentRecord = new JSONObject();
                        parentRecord.put("parentId", relationship.getParentId());
                        parentRecord.put("relId", relationship.getId());
                        parentRecord.put("relType", ClassifierIsARelationship.CLASS);

                        JSONObject object = Classifier.getJSONObject(child, _ids, false);
                        object.put("parentRecord", parentRecord);

                        children.put(object);
                    }

                } finally {
                    if (iterator != null) {
                        iterator.close();
                    }
                }
            }

            String label = _classifier.getDisplayLabel().getValue();

            JSONObject object = new JSONObject();
            object.put("label", label);
            object.put("id", _classifier.getId());
            object.put("type", _classifier.getType());
            object.put("children", children);
            object.put("fetched", (children.length() > 0));

            return object;
        } catch (JSONException e) {
            throw new ProgrammingErrorException(e);
        }
    }

    public static ClassifierProblemView[] getAllProblems() {
        List<ClassifierProblemView> list = new LinkedList<ClassifierProblemView>();

        ClassifierProblemQuery query = new ClassifierProblemQuery(new QueryFactory());
        query.ORDER_BY_DESC(query.getProblemType().getDisplayLabel().localize());
        query.ORDER_BY_ASC(query.getClassifier().getDisplayLabel().localize());

        OIterator<? extends ClassifierProblem> iterator = query.getIterator();

        try {
            while (iterator.hasNext()) {
                ClassifierProblem problem = iterator.next();

                list.addAll(problem.getViews());
            }
        } finally {
            iterator.close();
        }

        return list.toArray(new ClassifierProblemView[list.size()]);
    }

    @Transaction
    public static void deleteClassifierProblem(String problemId) {
        ClassifierProblem problem = ClassifierProblem.get(problemId);
        problem.delete();
    }

    public static Classifier findClassifier(String classifierPackage, String classifierId) {
        ClassifierQuery query = new ClassifierQuery(new QueryFactory());
        query.WHERE(query.getClassifierPackage().EQ(classifierPackage));
        query.WHERE(query.getClassifierId().EQ(classifierId));

        OIterator<? extends Classifier> it = null;

        try {
            it = query.getIterator();

            if (it.hasNext()) {
                Classifier classifier = it.next();

                return classifier;
            }

            return null;
        } finally {
            if (it != null) {
                it.close();
            }
        }
    }

}