it.larusba.integration.neo4j.jsonloader.transformer.UnrefactoredDomainBasedJsonTransformer.java Source code

Java tutorial

Introduction

Here is the source code for it.larusba.integration.neo4j.jsonloader.transformer.UnrefactoredDomainBasedJsonTransformer.java

Source

/**
 * Copyright (c) 2016 LARUS Business Automation [http://www.larus-ba.it]
 * <p>
 * This file is part of the "LARUS Integration Framework for Neo4j".
 * <p>
 * The "LARUS Integration Framework for Neo4j" is 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 it.larusba.integration.neo4j.jsonloader.transformer;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import it.larusba.integration.common.document.bean.JsonDocument;
import it.larusba.integration.common.document.bean.JsonObjectDescriptor;
import it.larusba.integration.neo4j.jsonloader.util.JsonObjectDescriptorHelper;

/**
 * Domain driven {@link JsonTransformer} implementation.
 * <p/>
 * It converts a JSON document into a Cypher statement, following this strategy:
 * <p/>
 * <ul>
 * <li>When primitive, JSON attributes become node properties and their names
 * are used as property names.</li>
 * <li>When object, JSON attributes become new nodes (in a recursive fashion)
 * connected to their own father node.</li>
 * <li>Value for the attribute defined in
 * {@link JsonObjectDescriptor#getTypeAttribute} is assigned to node label.</li>
 * <li>Values for the attributes defined in
 * {@link JsonObjectDescriptor#getUniqueKeyAttributes} become the unique node in
 * the merge operation.</li>
 * </ul>
 * As an example, the following JSON document:
 * 
 * <pre>
 * Person:
 * {
 *   "firstname" : "Lorenzo",
 *   "lastname"  : "Speranzoni",
 *   "age"       : 41,
 *   "job"       :
 *   {
 *     "role"    : "CEO",
 *     "company" :
 *     {
 *       "name"    : "LARUS Business Automation",
 *       "vat"     : "03540680273",
 *       "address" :
 *       {
 *         "street"   : "Via B. Maderna, 7",
 *         "zipCode"  : 30174,
 *         "city"     : "Mestre",
 *         "province" : "Venice",
 *         "country"  : "Italy",
 *         "type"     : "Address"
 *       },
 *       "type"    : "Company" 
 *     },
 *     "type"    : "Job" 
 *   },
 *   "type": "Person"
 * }
 * </pre>
 * 
 * trained with the following domain description:
 * 
 * <pre>
 * JsonObjectDescriptor addressObjectDescriptor = new JsonObjectDescriptor("Address",
 *     Arrays.asList("street", "zipCode"), "type");
 * JsonObjectDescriptor companyObjectDescriptor = new JsonObjectDescriptor("Company", Arrays.asList("vat"), "type");
 * JsonObjectDescriptor jobObjectDescriptor = new JsonObjectDescriptor("Job", Arrays.asList("role"), "type");
 * JsonObjectDescriptor personObjectDescriptor = new JsonObjectDescriptor("Person",
 *     Arrays.asList("firstname", "lastname"), "type");
 * </pre>
 * 
 * will be translated into this sub-graph:
 * 
 * <pre>
 * MERGE (person:Person { firstname: 'Lorenzo', lastname: 'Speranzoni' })
 * ON CREATE SET person._documentId = '1234567890QWERTY', person.age = 41, person.type = 'Person'
 * MERGE (job:Job { role: 'CEO' })
 * ON CREATE SET job._documentId = '1234567890QWERTY', job.type = 'Job'
 * MERGE (company:Company { vat: '03540680273' })
 * ON CREATE SET company._documentId = '1234567890QWERTY', company.name = 'LARUS Business Automation', company.type = 'Company'
 * MERGE (address:Address { street: 'Via B. Maderna, 7', zipCode: 30174 })
 * ON CREATE SET address._documentId = '1234567890QWERTY', address.city = 'Mestre', address.province = 'Venice', address.country = 'Italy'
 * CREATE (company)-[:COMPANY_ADDRESS]->(address)
 * CREATE (job)-[:JOB_COMPANY]->(company)
 * CREATE (person)-[:PERSON_JOB]->(job)
 * </pre>
 *
 * 
 * @author Lorenzo Speranzoni
 * 
 * @see <a href="http://neo4j.com/blog/cypher-load-json-from-url/">http://neo4j.
 *      com/blog/cypher-load-json-from-url/</a>
 * 
 * @since Mar 5, 2016
 */
@Deprecated
public class UnrefactoredDomainBasedJsonTransformer implements JsonTransformer<String> {

    /**
     * @see it.larusba.integration.neo4j.jsonloader.transformer.JsonTransformer#transform(it.larusba.integration.common.document.bean.JsonDocument)
     */
    @Override
    public String transform(JsonDocument jsonDocument)
            throws JsonParseException, JsonMappingException, IOException {

        Map<String, Object> documentMap = new ObjectMapper().readValue(jsonDocument.getContent(),
                new TypeReference<Map<String, Object>>() {
                });

        JsonObjectDescriptorHelper jsonObjectDescriptorHelper = new JsonObjectDescriptorHelper(
                jsonDocument.getObjectDescriptors());

        return transform(jsonDocument.getId(), jsonDocument.getType(), documentMap, jsonObjectDescriptorHelper,
                null);
    }

    /**
     * @param documentId
     * @param documentType
     * @param documentMap
     * @param objectDescriptors
     * @return
     */
    @SuppressWarnings("unchecked")
    private String transform(String documentId, String documentType, Map<String, Object> documentMap,
            JsonObjectDescriptorHelper objectDescriptorHelper, Integer position) {

        boolean firstAttr = true;
        boolean firstUniqueAttr = true;

        List<String> childNodes = new ArrayList<String>();
        List<String> childRelationships = new ArrayList<String>();

        StringBuffer rootNode = new StringBuffer();

        String nodeLabel = buildNodeLabel(documentType, documentMap, objectDescriptorHelper);
        String nodeReference = buildNodeReference(position, nodeLabel);

        //TODO implement
        if (objectDescriptorHelper.hasUniqueKeyAttributes(nodeLabel)) {
        } else {
        }

        rootNode.append("MERGE (").append(nodeReference).append(":").append(nodeLabel);

        StringBuffer nodeAttributes = new StringBuffer();

        for (String attributeName : documentMap.keySet()) {

            Object attributeValue = documentMap.get(attributeName);

            if (attributeValue instanceof Map) {

                childNodes.add(transform(documentId, StringUtils.capitalize(attributeName),
                        (Map<String, Object>) attributeValue, objectDescriptorHelper, null));

                childRelationships
                        .add(new StringBuffer().append("CREATE (").append(nodeReference).append(")-[").append(":")
                                .append(nodeReference.toUpperCase()).append("_").append(attributeName.toUpperCase())
                                .append("]->(").append(attributeName).append(")").toString());

            } else if (attributeValue instanceof List) {

                List<Object> attributeValueList = (List<Object>) attributeValue;

                if (attributeValueList.size() > 0) {

                    if (attributeValueList.get(0) instanceof Map) {

                        for (int i = 0; i < attributeValueList.size(); i++) {

                            Object attributeValueElement = attributeValueList.get(i);

                            if (attributeValueElement instanceof Map) {

                                childNodes.add(transform(documentId, StringUtils.capitalize(attributeName),
                                        (Map<String, Object>) attributeValueElement, objectDescriptorHelper, i));

                                childRelationships.add(new StringBuffer().append("MERGE (").append(nodeReference)
                                        .append(")-[").append(":").append(nodeReference.toUpperCase()).append("_")
                                        .append(attributeName.toUpperCase()).append("]->(")
                                        .append(attributeName + i).append(")").toString());
                            }
                        }
                    } else {

                        if (firstAttr) {
                            nodeAttributes.append("ON CREATE SET ");

                            if (documentId != null) {
                                nodeAttributes.append(nodeReference).append(".").append("_documentId = '")
                                        .append(documentId).append("', ");
                            }

                            firstAttr = false;
                        } else {
                            nodeAttributes.append(", ");
                        }

                        nodeAttributes.append(nodeReference).append(".").append(attributeName).append(" = [");

                        for (int i = 0; i < attributeValueList.size(); i++) {

                            Object attributeValueElement = attributeValueList.get(i);

                            if (attributeValueElement != null) {

                                if (i != 0)
                                    nodeAttributes.append(", ");

                                if (attributeValueElement instanceof String) {
                                    nodeAttributes.append("'").append(attributeValueElement).append("'");
                                } else {
                                    nodeAttributes.append(attributeValueElement);
                                }
                            }
                        }

                        nodeAttributes.append("]");
                    }
                }
            } else {

                if (objectDescriptorHelper.isAttributeInUniqueKey(nodeLabel, attributeName)) {

                    if (firstUniqueAttr) {
                        rootNode.append(" { ");

                        firstUniqueAttr = false;
                    } else {
                        rootNode.append(", ");
                    }

                    rootNode.append(attributeName).append(": ");

                    if (attributeValue instanceof String) {
                        rootNode.append("'").append(attributeValue).append("'");
                    } else {
                        rootNode.append(attributeValue);
                    }

                } else {

                    if (attributeValue != null) {

                        if (firstAttr) {
                            nodeAttributes.append("ON CREATE SET ");

                            if (documentId != null) {
                                nodeAttributes.append(nodeReference).append(".").append("_documentId = '")
                                        .append(documentId).append("', ");
                            }

                            firstAttr = false;
                        } else {
                            nodeAttributes.append(", ");
                        }

                        nodeAttributes.append(nodeReference).append(".").append(attributeName).append(" = ");

                        if (attributeValue instanceof String) {
                            nodeAttributes.append("'").append(attributeValue).append("'");
                        } else {
                            nodeAttributes.append(attributeValue);
                        }
                    }
                }
            }
        }

        if (firstAttr == firstUniqueAttr) {
            rootNode.append("}");
        }
        rootNode.append(")").append(System.lineSeparator()).append(nodeAttributes);

        StringBuffer cypher = new StringBuffer();
        cypher.append(rootNode);

        for (String childNode : childNodes) {
            cypher.append(System.lineSeparator()).append(childNode);
        }

        for (String childRelationship : childRelationships) {
            cypher.append(System.lineSeparator()).append(childRelationship);
        }

        return cypher.toString();
    }

    private String buildNodeReference(Integer position, String nodeLabel) {
        return nodeLabel.toLowerCase() + ((position != null) ? position : "");
    }

    private String buildNodeLabel(String documentType, Map<String, Object> documentMap,
            JsonObjectDescriptorHelper objectDescriptorHelper) {

        String typeAttribute = (String) documentMap.get(objectDescriptorHelper.getTypeAttribute(documentType));

        if (StringUtils.isBlank(typeAttribute)) {
            typeAttribute = StringUtils.lowerCase(documentType);
        }

        return StringUtils.capitalize(typeAttribute);
    }
}