Skip to main content
Bumped by Community user
Bumped by Community user
Bumped by Community user
deleted 43 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Refactor legacy code to spring - spring bean or not?

I am refactoring a legacy codebase to use spring. I am newish to spring and was wondering if you have any suggestions for the following code I refactored. Specifically about providing the ExpeditionEntitiesService. Any tips would be highly appreciatedExpeditionEntitiesService.

BelowHere is a REST service which uploads a file.:

The next class is used to convert the file to triples to be stored in apacheApache fuseki tdb.TBD:

The next class is used by the Triplifier to generate the mapping file used to create the triples.:

The next class is used to get the unique persistent identifier for the triples.:

Refactor legacy code to spring - spring bean or not?

I am refactoring a legacy codebase to use spring. I am newish to spring and was wondering if you have any suggestions for the following code I refactored. Specifically about providing the ExpeditionEntitiesService. Any tips would be highly appreciated.

Below is a REST service which uploads a file.

The next class is used to convert the file to triples to be stored in apache fuseki tdb.

The next class is used by the Triplifier to generate the mapping file used to create the triples.

The next class is used to get the unique persistent identifier for the triples.

Refactor legacy code to spring

I am refactoring a legacy codebase to use spring. I am newish to spring and was wondering if you have any suggestions for the following code I refactored. Specifically about providing the ExpeditionEntitiesService.

Here is a REST service which uploads a file:

The next class is used to convert the file to triples to be stored in Apache fuseki TBD:

The next class is used by the Triplifier to generate the mapping file used to create the triples:

The next class is used to get the unique persistent identifier for the triples:

Source Link

Refactor legacy code to spring - spring bean or not?

I am refactoring a legacy codebase to use spring. I am newish to spring and was wondering if you have any suggestions for the following code I refactored. Specifically about providing the ExpeditionEntitiesService. Any tips would be highly appreciated.

Below is a REST service which uploads a file.

public class myRestService {
     @POST
     public Response upload(//params) {
         // do work
         ExpeditionEntities expeditionEntities = expeditionService.getExpeditionEntities(processController.getExpeditionId());
        ExpeditionEntitiesService expeditionEntitiesService = new ExpeditionEntitiesService(expeditionEntities, processController, bcidService, expeditionService);
        // run the triplifier
        Triplifier triplifier = new Triplifier(outputPrefix, uploadPath(), processController, expeditionEntitiesService);

        boolean runDeepRoots = Boolean.valueOf(settingsManager.retrieveValue("deepRoots"));

        triplifier.run(processController.getValidation().getSqliteFile());
         // more work
     }
}

The next class is used to convert the file to triples to be stored in apache fuseki tdb.

public class Triplifier {

    public Connection connection;

    private String outputFolder;
    private Model model;
    private String tripleOutputFile;
    private String filenamePrefix;
    private ProcessController processController;
    private final ExpeditionEntitiesService expeditionEntitiesService;

    private static Logger logger = LoggerFactory.getLogger(Triplifier.class);

    /**
     * triplify dataset on the tabularDataReader, writing output to the specified outputFolder and filenamePrefix
     *
     * @param filenamePrefix
     * @param outputFolder
     */
    public Triplifier(String filenamePrefix, String outputFolder,
                      ProcessController processController, ExpeditionEntitiesService expeditionEntitiesService) {
        this.outputFolder = outputFolder;
        this.filenamePrefix = filenamePrefix;
        this.processController = processController;
        this.expeditionEntitiesService = expeditionEntitiesService;
    }

    public String getOutputFolder() {return outputFolder;}

    public String getFilenamePrefix() {return filenamePrefix;}

    public Model getModel() {return model;}

    public String getTripleOutputFile() {return tripleOutputFile;}

    /**
     * Return triples
     *
     * @return
     */
    private void getTriples() {
        System.gc();
        String status = "\tWriting Temporary Output ...";
        processController.appendStatus(status + "<br>");

        // Write the model
        model = new ModelD2RQ(FileUtils.toURL(getMapping()),
                FileUtils.langN3, "urn:x-biscicol:");
        model.setNsPrefix("ark", "http://ezid.cdlib.org/id/ark");
        // Write the model as simply a Turtle file
        File tripleFile = PathManager.createUniqueFile(filenamePrefix + ".n3", outputFolder);
        try {
            FileOutputStream fos = new FileOutputStream(tripleFile);
            model.write(fos, FileUtils.langNTriple, null);
            fos.close();
        } catch (FileNotFoundException e) {
            throw new FimsRuntimeException(500, e);
        } catch (IOException e) {
            logger.warn("IOException thrown trying to close FileOutputStream object.", e);
        }
        tripleOutputFile = outputFolder + File.separator + tripleFile.getName();

        if (tripleFile.length() < 1)
            throw new FimsRuntimeException("No triples to write!", 500);
    }

    /**
     * Construct the mapping file for D2RQ to read
     *
     * @return
     */
    private String getMapping() {
        connection.verifyFile();

        File mapFile = PathManager.createUniqueFile(filenamePrefix + ".mapping.n3", outputFolder);
        try {
            PrintWriter pw = new PrintWriter(mapFile);
            TabularDataReader tdr = processController.getValidation().getTabularDataReader();
            Mapping mapping = processController.getMapping();
            new D2RQPrinter(pw, connection, expeditionEntitiesService).printD2RQ(tdr.getColNames(), mapping);
            pw.close();
        } catch (FileNotFoundException e) {
            throw new FimsRuntimeException(500, e);
        }
        return outputFolder + File.separator + mapFile.getName();
    }

    /**
     * Run the triplifier using this class
     */
    public boolean run(File sqlLiteFile) {
        String status = "Converting Data Format ...";
        processController.appendStatus(status + "<br>");

        this.connection = new Connection(sqlLiteFile);
        getTriples();
        return true;
    }
}

The next class is used by the Triplifier to generate the mapping file used to create the triples.

public class D2RQPrinter {
    private PrintWriter pw;
    private Connection connection;
    private final ExpeditionEntitiesService expeditionEntitiesService;

    public D2RQPrinter(PrintWriter pw, Connection connection, ExpeditionEntitiesService expeditionEntitiesService) {
        this.pw = pw;
        this.connection = connection;
        this.expeditionEntitiesService = expeditionEntitiesService;
    }

    /**
     * Generate D2RQ Mapping Language representation of this Mapping's connection, entities and relations.
     */
    public void printD2RQ(List<String> colNames, Mapping mapping) {
        printPrefixes();
        printConnectionD2RQ();
        for (Entity entity : mapping.getEntities())
            printEntityD2RQ(entity, colNames);
        for (Relation relation : mapping.getRelations()) {
            printRelationD2RQ(relation, mapping);
        }
    }

    /**
     * Generate D2RQ Mapping Language representation of this Relation.
     *
     */
    public void printRelationD2RQ(Relation relation, Mapping mapping) {

        Entity subjEntity = mapping.findEntity(relation.getSubject());
        Entity objEntity = mapping.findEntity(relation.getObject());

        if (subjEntity == null || objEntity == null)
            return;

        String subjClassMap = getClassMap(subjEntity);
        String objClassMap = getClassMap(objEntity);

        pw.println("map:" + subjClassMap + "_" + objClassMap + "_rel" + " a d2rq:PropertyBridge;");
        pw.println("\td2rq:belongsToClassMap " + "map:" + subjClassMap + ";");
        pw.println("\td2rq:property <" + relation.getPredicate() + ">;");
        pw.println(getPersistentIdentifierMapping(objEntity));
        pw.println("\td2rq:condition \"" + objEntity.getWorksheetUniqueKey() + " <> ''\";");
        pw.println("\t.");
    }

    /**
     * Generate D2RQ Mapping Language ClassMap name for a given Entity.
     *
     * @return D2RQ Mapping ClassMap name.
     */
    private String getClassMap(Entity entity) {
        return entity.getWorksheet() + "_" + entity.getWorksheetUniqueKey() + "_" + entity.getConceptAlias();
    }

    /**
     * Generate D2RQ Mapping Language representation of this Entity with Attributes.
     */
    private void printEntityD2RQ(Entity entity, List<String> colNames) {
        pw.println("map:" + getClassMap(entity) + " a d2rq:ClassMap;");
        pw.println("\td2rq:dataStorage " + "map:database;");
        pw.println(getPersistentIdentifierMapping(entity));
        pw.println("\td2rq:class <" + entity.getConceptURI() + ">;");
        // ensures non-null values ... don't apply if this is a hash
        if (!entity.getColumn().contains("hash"))
            pw.println("\td2rq:condition \"" + entity.getColumn() + " <> ''\";");

        // TODO: add in extra conditions (May not be necessary)
        //pw.println(getExtraConditions());
        pw.println("\t.");

        // Get a list of colNames that we know are good from the spreadsheet
        // Normalize the column names so they can be mapped according to how they appear in SQLite
        ArrayList<String> normalizedColNames = new ArrayList<String>();
        Iterator it = colNames.iterator();
        while (it.hasNext()) {
            String colName = (String) it.next();
            normalizedColNames.add(colName.replace(" ", "_").replace("/", ""));
        }

        // Loop through attributes associated with this Entity
        if (entity.getAttributes().size() > 0) {
            for (Attribute attribute : entity.getAttributes())
                printAttributeD2RQ(attribute, entity, normalizedColNames);
        }
    }

    /**
     * * Generate D2RQ Mapping Language representation of this Attribute.
     *
     * @param parent
     * @param colNames
     */
    private void printAttributeD2RQ(Attribute attribute, Entity parent, List<String> colNames) {

        String classMap = getClassMap(parent);
        String table = parent.getWorksheet();
        String classMapStringEquivalence = "";

        Boolean runColumn = false;

        if (colNames.contains(attribute.getColumn())) {
            runColumn = true;
        }

        // Only print this column if it is in a list of colNames
        if (runColumn) {
            String classMapString = "map:" + classMap + "_" + attribute.getColumn();
            pw.println(classMapString + " a d2rq:PropertyBridge;");
            pw.println("\td2rq:belongsToClassMap " + "map:" + classMap + ";");
            pw.println("\td2rq:property <" + attribute.getUri() + ">;");
            pw.println("\td2rq:column \"" + table + "." + attribute.getColumn() + "\";");
            pw.println("\td2rq:condition \"" + table + "." + attribute.getColumn() + " <> ''\";");
            // Specify an equivalence, which is isDefinedBy
            classMapStringEquivalence = classMapString + "_Equivalence";
            pw.println("\td2rq:additionalPropertyDefinitionProperty " + classMapStringEquivalence + ";");
            pw.println("\t.");

            // Always use isDefinedBy, even if the user has not expressed it explicitly.  We do this by
            // using the uri value if NO isDefinedBy is expressed.
            pw.println(classMapStringEquivalence + " a d2rq:AdditionalProperty;");
            pw.println("\td2rq:propertyName <" + attribute.getIsDefinedByURIString() + ">;");
            if (attribute.getDefined_by()!= null) {
                pw.println("\td2rq:propertyValue <" + attribute.getDefined_by() + ">;");
            } else {
                pw.println("\td2rq:propertyValue <" + attribute.getUri() + ">;");
            }
            pw.println("\t.");
            /*
           Loop multi-value columns
           This is used when the Configuration file indicates an attribute that should be composed of more than one column
            */
        } else if (attribute.getColumn().contains(",")) {

            // TODO: clean this up and integrate with above code.
            String tempColumnName = attribute.getColumn().replace(",", "");

            String[] columns = attribute.getColumn().split(",");

            // Check if we should run this -- all columns need to be present in colNames list
            Boolean runMultiValueColumn = true;
            for (int i = 0; i < columns.length; i++) {
                if (!colNames.contains(columns[i])) {
                    runMultiValueColumn = false;
                }
            }

            // Only run this portion if the tempColumnName appears
            if (runMultiValueColumn) {

                String classMapString = "map:" + classMap + "_" + tempColumnName;
                pw.println(classMapString + " a d2rq:PropertyBridge;");
                pw.println("\td2rq:belongsToClassMap " + "map:" + classMap + ";");
                pw.println("\td2rq:property <" + attribute.getUri() + ">;");

                // Construct SQL Expression
                StringBuilder result = new StringBuilder();

                // Call this a sqlExpression
                result.append("\td2rq:sqlExpression \"");

                // Append ALL columns together using the delimiter... ALL are required
                if (attribute.getType().equals("all")) {
                    for (int i = 0; i < columns.length; i++) {
                        if (i != 0)
                            result.append(" || '" + attribute.getDelimited_by() + "' || ");
                        // Set required function parameters
                        if (attribute.getType().equals("all"))
                            pw.println("\td2rq:condition \"" + table + "." + columns[i] + " <> ''\";");
                        result.append(columns[i]);
                    }
                    result.append("\";");
                }

                // This is the YMD case using a very special SQLIte function to format data
                // Assume that columns are Year, Month, and Day EXACTLY
                else if (attribute.getType().equals("ymd")) {
                    // Require Year
                    pw.println("\td2rq:condition \"" + table + "." + columns[0] + " <> ''\";");

                    result.append("yearCollected ||  ifnull(nullif('-'||substr('0'||monthCollected,-2,2),'-0') || " +
                            "ifnull(nullif('-'||substr('0'||dayCollected,-2,2),'-0'),'')" +
                            ",'') ");
                    result.append("\";");

                }

                pw.println(result.toString());

                //pw.println("\td2rq:column \"" + table + "." + column + "\";");
                //pw.println("\td2rq:condition \"" + table + "." + column + " <> ''\";");

                // Specify an equivalence, which is isDefinedBy
                classMapStringEquivalence = classMapString + "_Equivalence";
                pw.println("\td2rq:additionalPropertyDefinitionProperty " + classMapStringEquivalence + ";");
                pw.println("\t.");

                // Always use isDefinedBy, even if the user has not expressed it explicitly.  We do this by
                // using the uri value if NO isDefinedBy is expressed.
                pw.println(classMapStringEquivalence + " a d2rq:AdditionalProperty;");
                pw.println("\td2rq:propertyName <" + attribute.getIsDefinedByURIString() + ">;");
                if (attribute.getDefined_by() != null) {
                    pw.println("\td2rq:propertyValue <" + attribute.getDefined_by() + ">;");
                } else {
                    pw.println("\td2rq:propertyValue <" + attribute.getUri() + ">;");
                }
                pw.println("\t.");

            }
        }
    }


    /**
     * Generate D2RQ Mapping Language representation of this Connection.
     */
    private void printConnectionD2RQ() {
        pw.println("map:database a d2rq:Database;");
        pw.println("\td2rq:jdbcDriver \"" + connection.system.driver + "\";");
        pw.println("\td2rq:jdbcDSN \"" + connection.getJdbcUrl() + "\";");
        if (connection.username != null && !connection.username.isEmpty())
            pw.println("\td2rq:username \"" + connection.username + "\";");
        if (connection.password != null && !connection.password.isEmpty())
            pw.println("\td2rq:password \"" + connection.password + "\";");
        pw.println("\td2rq:fetchSize \"" + (connection.system == DBsystem.mysql ? Integer.MIN_VALUE : 500) + "\";");
        pw.println("\t.");
    }

    /**
     * Generate all possible RDF prefixes.
     */
    private void printPrefixes() {
        // TODO: Allow configuration files to specify namespace prefixes!
        pw.println("@prefix map: <" + "" + "> .");
        pw.println("@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .");
        pw.println("@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .");
        pw.println("@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .");
        pw.println("@prefix d2rq: <http://www.wiwiss.fu-berlin.de/suhl/bizer/D2RQ/0.1#> .");
        pw.println("@prefix jdbc: <http://d2rq.org/terms/jdbc/> .");
        pw.println("@prefix ro: <http://www.obofoundry.org/ro/ro.owl#> .");
        pw.println("@prefix bsc: <http://biscicol.org/terms/index.html#> .");
        pw.println("@prefix urn: <http://biscicol.org/terms/index.html#> .");
        // TODO: update this prefix to EZID location when suffixPassthrough is ready
        pw.println("@prefix ark: <http://biscicol.org/id/ark:> .");


        pw.println();
    }

    /**
     * Sets the URI as a identifier to a column, or not, according to D2RQ conventions
     *
     * @param entity
     * @return
     */
    private String getPersistentIdentifierMapping(Entity entity) {
        String identifier = expeditionEntitiesService.getEntityIdentifier(entity);

        return "\td2rq:uriPattern \"" + identifier + "@@" + entity.getColumn() + "@@\";";

    }
}

The next class is used to get the unique persistent identifier for the triples.

public class ExpeditionEntitiesService {
    private static String DEFAULT_IDENTIFIER_PREFIX = "urn:x-biscicol:";
    private final ExpeditionEntities expeditionEntities;
    private final ProcessController processController;
    private final BcidService bcidService;
    private final ExpeditionService expeditionService;

    public ExpeditionEntitiesService(ExpeditionEntities expeditionEntities, ProcessController processController,
                                     BcidService bcidService, ExpeditionService expeditionService) {
        this.expeditionEntities = expeditionEntities;
        this.processController = processController;
        this.bcidService = bcidService;
        this.expeditionService = expeditionService;
    }

    public String getEntityIdentifier(Entity entity) {
        // Use the DeepRoots System to lookup Key
        String identifier = null;
        if (expeditionEntities != null) {
            identifier = lookupPrefix(entity);
        }

        // Use the default namespace value if dRoots is unsuccessful...
        if (identifier == null) {
            identifier = DEFAULT_IDENTIFIER_PREFIX + entity.getConceptAlias() + ":";
        }
        return identifier;
    }
        /**
         * Find the appropriate identifier for a concept contained in this file
         *
         * @return returns the Bcid for Entity resourceType in this DeepRoots file
         */
    public String lookupPrefix(Entity entity) {
        HashMap<String, String> entities = expeditionEntities.getEntities();
        Iterator it = entities.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry) it.next();
            if (pairs.getKey().toString().trim().equals(entity.getConceptAlias().trim())) {
                String postfix = (String) pairs.getValue();
                return postfix;
            }
        }
        FimsPrinter.out.println("\tWarning: " + entity.getConceptAlias() + " cannot be mapped in Deep Roots, attempting to create mapping");
        // Create a mapping in the deeproots system for this URI
        FimsPrinter.out.println("\tCreating bcid root for " + entity.getConceptAlias() + " with resource type = " + entity.getConceptURI());

        Bcid bcid = new Bcid.BcidBuilder(entity.getConceptAlias())
                .title(entity.getConceptAlias())
                .build();

        bcidService.create(bcid, processController.getUserId());

        Expedition expedition = expeditionService.getExpedition(processController.getExpeditionCode(), processController.getProjectId());
        bcidService.attachBcidToExpedition(bcid, expedition.getExpeditionId());

        // Add this element to the entities string so we don't keep trying to add it in the loop above
        entities.put(entity.getConceptAlias(), String.valueOf(bcid.getIdentifier()));
        System.out.println("\tNew identifier = " + bcid.getIdentifier());
        return String.valueOf(bcid.getIdentifier());
    }
}