/**
* Copyright (C) 2010-2017 Structr GmbH
*
* This file is part of Structr <http://structr.org>.
*
* Structr is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Structr 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Structr. If not, see <http://www.gnu.org/licenses/>.
*/
package org.structr.schema.importer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.structr.api.graph.Label;
import org.structr.api.graph.Node;
/**
*
*
*/
public class NodeInfo {
private final Map<String, Class> properties = new LinkedHashMap<>();
private final Set<String> types = new LinkedHashSet<>();
private int hashCode = 0;
public NodeInfo(final Node node) {
extractProperties(node);
extractTypes(node);
calcHashCode();
}
private void calcHashCode() {
this.hashCode = 13;
hashCode += types.hashCode();
hashCode += properties.hashCode() * 31;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object other) {
if (other instanceof NodeInfo) {
return hashCode() == other.hashCode();
}
return false;
}
public boolean hasType(final String type) {
return types.contains(type);
}
public Map<String, Class> getProperties() {
return properties;
}
public Set<String> getTypes() {
return types;
}
// ----- private methods -----
private void extractProperties(final Node node) {
for (final String key : node.getPropertyKeys()) {
final Object value = node.getProperty(key);
if (value != null) {
properties.put(key, value.getClass());
}
}
}
private void extractTypes(final Node node) {
// first try: labels
// AM 2015-06-26: Changed the behaviour here: In case of multiple labels, don't put them all
// into the set of potential types but rather create a combined type.
// E.g. a node with the two labels 'Person' and 'Entity' will get a type 'EntityPerson'
final List<String> labelStrings = new ArrayList<>();
for (final Label label : node.getLabels()) {
labelStrings.add(label.name());
}
//Collections.sort(labelStrings);
addType(StringUtils.join(labelStrings, ""));
// second try: type attribute
if (node.hasProperty("type")) {
final String type = node.getProperty("type").toString();
addType(type.replaceAll("[\\W]+", ""));
}
// deactivate relationship type nodes for now..
/*
// third try: incoming relationships
final Set<String> incomingTypes = new LinkedHashSet<>();
for (final Relationship incoming : node.getRelationships(Direction.INCOMING)) {
incomingTypes.add(incoming.getType().name());
}
// (if all incoming relationships are of the same type,
// it is very likely that this is a type-defining trait)
if (incomingTypes.size() == 1) {
return CaseHelper.toUpperCamelCase(incomingTypes.iterator().next().toLowerCase());
}
// forth try: outgoing relationships
final Set<String> outgoingTypes = new LinkedHashSet<>();
for (final Relationship outgoing : node.getRelationships(Direction.OUTGOING)) {
outgoingTypes.add(outgoing.getType().name());
}
// (if all outgoing relationships are of the same type,
// it is very likely that this is a type-defining trait)
if (outgoingTypes.size() == 1) {
return CaseHelper.toUpperCamelCase(outgoingTypes.iterator().next().toLowerCase());
}
*/
if (types.isEmpty() && !properties.keySet().isEmpty()) {
// fifth try: analyze properties
final StringBuilder buf = new StringBuilder("NodeWith");
for (final String key : properties.keySet()) {
buf.append(StringUtils.capitalize(key));
}
types.add(buf.toString());
}
}
private void addType (final String type) {
if (type != null && !type.equals("")) {
types.add(type);
}
}
}