package org.ff4j.neo4j.store;
import static org.ff4j.neo4j.FF4jNeo4jConstants.NODEFEATURE_ATT_UID;
import static org.ff4j.neo4j.FF4jNeo4jConstants.NODEGROUP_ATT_NAME;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_ADDTO_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_ADD_ROLE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_ALIAS;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_COUNT_FEATURE_OF_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_ALLFEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_ALLSINGLEFEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_FEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_GROUP_FEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_PROPERTIES_FEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DELETE_STRATEGY_FEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DISABLE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_DISABLE_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_ENABLE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_ENABLE_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_EXISTS;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_EXISTS_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_GETGROUPNAME;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_GET_FLIPPINGSTRATEGY;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_NORELATIONSHIPS;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_READ_ALL;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_READ_FEATURE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_READ_FEATURES_OF_GROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_READ_SINGLE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_REMOVEFROMGROUP;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_CYPHER_UPDATE_ROLE;
import static org.ff4j.neo4j.FF4jNeo4jConstants.QUERY_READ_GROUPS;
/*
* #%L
* ff4j-store-neo4j
* %%
* Copyright (C) 2013 - 2015 Ff4J
* %%
* 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.
* #L%
*/
import static org.ff4j.neo4j.mapper.Neo4jMapper.fromNode2Feature;
import static org.ff4j.neo4j.mapper.Neo4jMapper.fromNode2FlippingStrategy;
import static org.ff4j.neo4j.mapper.Neo4jMapper.fromNode2Property;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.ff4j.core.Feature;
import org.ff4j.core.FlippingStrategy;
import org.ff4j.exception.FeatureAlreadyExistException;
import org.ff4j.exception.FeatureNotFoundException;
import org.ff4j.neo4j.FF4jNeo4jLabels;
import org.ff4j.neo4j.FF4jNeo4jRelationShips;
import org.ff4j.property.Property;
import org.ff4j.store.AbstractFeatureStore;
import org.ff4j.utils.Util;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Result;
import org.neo4j.graphdb.Transaction;
/**
* Implementatino of NEO4J Store.
*
* @author <a href="mailto:cedrick.lunven@gmail.com">Cedrick LUNVEN</a>
*/
public class FeatureStoreNeo4J extends AbstractFeatureStore {
public static final String GROUPNAME = "GROUPNAME";
public static final String GROUP_NAME = "groupName";
/** Persistent storage. */
private GraphDatabaseService graphDb;
/**
* Default to create instances.
*/
public FeatureStoreNeo4J() {
}
/**
* Initialization of store
*/
public FeatureStoreNeo4J(GraphDatabaseService myDb) {
this.graphDb = myDb;
}
/** {@inheritDoc} */
@Override
public boolean exist(String featId) {
Util.assertHasLength(featId);
Map < String, Object > queryParameters = new HashMap<>();
queryParameters.put("uid", featId);
Result result = graphDb.execute(QUERY_CYPHER_EXISTS, queryParameters);
Object count = null;
if (result.hasNext()) {
count = result.next().get(QUERY_CYPHER_ALIAS);
}
return (null != count) && (((long) count) > 0);
}
/** {@inheritDoc} */
@Override
public void enable(String uid) {
assertFeatureExist(uid);
Transaction tx = graphDb.beginTx();
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("uid", uid);
graphDb.execute(QUERY_CYPHER_ENABLE, queryParameters);
tx.success();
}
/** {@inheritDoc} */
@Override
public void disable(String uid) {
assertFeatureExist(uid);
Transaction tx = graphDb.beginTx();
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("uid", uid);
graphDb.execute(QUERY_CYPHER_DISABLE, queryParameters);
tx.success();
}
/** {@inheritDoc} */
@Override
public Feature read(String featId) {
assertFeatureExist(featId);
Feature targetFeature = null;
Transaction tx = graphDb.beginTx();
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("uid", featId);
Result result = graphDb.execute(QUERY_CYPHER_READ_FEATURE, queryParameters);
if (!result.hasNext()) {
// Exist but as no relation ship not return by first query
result = graphDb.execute(QUERY_CYPHER_NORELATIONSHIPS, queryParameters);
}
while (result.hasNext()) {
Map<String, Object> response = result.next();
if (targetFeature == null) {
Node nodeFeature = (Node) response.get("f");
targetFeature = fromNode2Feature(nodeFeature);
}
addNeighBour2Feature(targetFeature, (Node) response.get("all"));
}
tx.success();
return targetFeature;
}
/** {@inheritDoc} */
@Override
public Map<String, Feature> readAll() {
Map<String, Feature> allFeatures = new HashMap<>();
Transaction tx = graphDb.beginTx();
// Node with relationships
Result result = graphDb.execute(QUERY_CYPHER_READ_ALL);
while (result.hasNext()) {
addToFeatureList(result.next(), allFeatures);
}
// Single nodes
result = graphDb.execute(QUERY_CYPHER_READ_SINGLE);
while (result.hasNext()) {
addToFeatureList(result.next(), allFeatures);
}
tx.success();
return allFeatures;
}
/** {@inheritDoc} */
@Override
public void delete(String uid) {
Util.assertHasLength(uid);
if (!exist(uid)) {
throw new FeatureNotFoundException(uid);
}
// Parameter
Map<String, Object> paramUID = new HashMap<>();
paramUID.put("uid", uid);
Transaction tx = graphDb.beginTx();
// Delete Flipping Strategy if it exists
graphDb.execute(QUERY_CYPHER_DELETE_STRATEGY_FEATURE, paramUID);
// Delete Related Property if exist
graphDb.execute(QUERY_CYPHER_DELETE_PROPERTIES_FEATURE, paramUID);
// Check group
Result result = graphDb.execute(QUERY_CYPHER_GETGROUPNAME, paramUID);
if (result.hasNext()) {
String groupName = (String) result.next().get(GROUPNAME);
Map<String, Object> paramGroupName = new HashMap<>();
paramGroupName.put(GROUP_NAME, groupName);
result = graphDb.execute(QUERY_CYPHER_COUNT_FEATURE_OF_GROUP, paramGroupName);
if (result.hasNext()) {
long nbFeature = (long) result.next().get(QUERY_CYPHER_ALIAS);
if (nbFeature == 1) {
// This is the last feature of this Group => delete the GROUP
graphDb.execute(QUERY_CYPHER_DELETE_GROUP_FEATURE, paramUID);
}
}
}
// Delete feature
graphDb.execute(QUERY_CYPHER_DELETE_FEATURE, paramUID);
tx.success();
}
/** {@inheritDoc} */
@Override
public void grantRoleOnFeature(String uid, String roleName) {
Util.assertHasLength(roleName);
Feature feat = read(uid);
if (feat.getPermissions() != null && !feat.getPermissions().contains(roleName)) {
Transaction tx = graphDb.beginTx();
Map<String, Object> paramUID = new HashMap<>();
paramUID.put("uid", uid);
paramUID.put("roleName", roleName);
graphDb.execute(QUERY_CYPHER_ADD_ROLE, paramUID);
tx.success();
}
}
/** {@inheritDoc} */
@Override
public void removeRoleFromFeature(String uid, String roleName) {
Util.assertHasLength(roleName);
Feature feat = read(uid);
if (feat.getPermissions() != null && feat.getPermissions().contains(roleName)) {
feat.getPermissions().remove(roleName);
String[] roles = feat.getPermissions().toArray(new String[0]);
Transaction tx = graphDb.beginTx();
Map<String, Object> paramUID = new HashMap<>();
paramUID.put("uid", uid);
paramUID.put("roles", roles);
graphDb.execute(QUERY_CYPHER_UPDATE_ROLE, paramUID);
tx.success();
}
}
/**
* Create, update or delete Flipping Strategy
*/
private void updateFlippingStrategy(Feature fp) {
Transaction tx2 = graphDb.beginTx();
// Create or update FlippingStrategy (as provided)
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("uid", fp.getUid());
if (fp.getFlippingStrategy() != null) {
Result flippingNode = graphDb.execute(QUERY_CYPHER_GET_FLIPPINGSTRATEGY, queryParameters);
if (flippingNode.hasNext()) {
graphDb.execute(createUpdateFlippingStrategy(fp));
} else {
graphDb.execute(createQueryFlippingStrategy(fp));
}
} else {
// Delete flipping strategy if exist (as null)
graphDb.execute(QUERY_CYPHER_DELETE_STRATEGY_FEATURE, queryParameters);
}
tx2.success();
}
/**
* Update group attribute of feature.
*
* @param fp
* target feature
*/
private void updateGroups(Feature fp) {
// Group
String oldGroupName = getCurrentGroupName(fp.getUid());
if ((oldGroupName != null) && (fp.getGroup() == null)) {
removeFromGroup(fp.getUid(), oldGroupName);
}
if (fp.getGroup() != null && fp.getGroup().length() > 0) {
// group already existed and has been changed
if (oldGroupName != null && !oldGroupName.equalsIgnoreCase(fp.getGroup())) {
removeFromGroup(fp.getUid(), oldGroupName);
}
// No group before or a new group, different from before
if (oldGroupName == null || !oldGroupName.equalsIgnoreCase(fp.getGroup())) {
addToGroup(fp.getUid(), fp.getGroup());
}
}
}
/** {@inheritDoc} */
@Override
public void update(Feature fp) {
Util.assertNotNull(fp);
Util.assertHasLength(fp.getUid());
// Check existence
read(fp.getUid());
// Create or update core Feature as a first TX
Transaction tx = graphDb.beginTx();
graphDb.execute(createUpdateCoreFeature(fp));
tx.success();
// Create, update or delete Flipping Strategy
updateFlippingStrategy(fp);
// Update groups
updateGroups(fp);
// Properties
Transaction tx3 = graphDb.beginTx();
Map<String, Object> paramUID = new HashMap<>();
paramUID.put("uid", fp.getUid());
graphDb.execute(QUERY_CYPHER_DELETE_PROPERTIES_FEATURE, paramUID);
tx3.success();
if (fp.getCustomProperties() != null && fp.getCustomProperties().size() > 0) {
for (String pName : fp.getCustomProperties().keySet()) {
createProperty(fp.getProperty(pName), fp.getUid());
}
}
}
private void createProperty(Property<?> pro, String featureName) {
StringBuilder cypherCreate = new StringBuilder("MATCH (f:FF4J_FEATURE {uid:'" + featureName + "'} ) ");
cypherCreate.append("CREATE (p:" + FF4jNeo4jLabels.FF4J_FEATURE_PROPERTY + " { name :'");
cypherCreate.append(pro.getName());
cypherCreate.append("', type:'");
cypherCreate.append(pro.getType());
cypherCreate.append("', value:'");
cypherCreate.append(pro.getValue());
cypherCreate.append("', fixedValues:[");
if (pro.getFixedValues() != null && !pro.getFixedValues().isEmpty()) {
boolean first = true;
for (Object fix : pro.getFixedValues()) {
if (!first) {
cypherCreate.append(",");
}
cypherCreate.append("'" + fix.toString() + "'");
first = false;
}
}
cypherCreate.append("]");
if (pro.getDescription() != null && pro.getDescription().length() > 0) {
cypherCreate.append(", description:'");
cypherCreate.append(pro.getDescription());
cypherCreate.append("'");
}
cypherCreate.append("})-[:" + FF4jNeo4jRelationShips.PROPERTY_OF + "]->(f);");
Transaction tx = graphDb.beginTx();
graphDb.execute(cypherCreate.toString());
tx.success();
}
private String getCurrentGroupName(String uid) {
String groupName = null;
Transaction tx = graphDb.beginTx();
Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("uid", uid);
Result result = graphDb.execute(QUERY_CYPHER_GETGROUPNAME, queryParameters);
if (result.hasNext()) {
groupName = (String) result.next().get(GROUPNAME);
}
tx.success();
return groupName;
}
private String createQueryFlippingStrategy(Feature fp) {
String fsCreateQuery = "MATCH (f:FF4J_FEATURE {uid:'" + fp.getUid() + "'}) ";
fsCreateQuery += "CREATE (fs:FF4J_FLIPPING_STRATEGY { type:'";
fsCreateQuery += fp.getFlippingStrategy().getClass().getName();
fsCreateQuery += "', initParams: [";
Map < String, String > initParams = fp.getFlippingStrategy().getInitParams();
if (initParams != null && initParams.size() > 0) {
boolean first = true;
for (Map.Entry < String, String > entry : initParams.entrySet()) {
if (!first) {
fsCreateQuery += ",";
}
fsCreateQuery += "'" + entry.getKey() + "=" + entry.getValue() + "'";
first = false;
}
}
fsCreateQuery += "]})-[:" + FF4jNeo4jRelationShips.STRATEGY_OF + "]->(f);";
return fsCreateQuery;
}
private String createQueryNewCoreFeature(Feature fp) {
StringBuilder cypherCreate = new StringBuilder("CREATE (");
cypherCreate.append("f:" + FF4jNeo4jLabels.FF4J_FEATURE + " { uid :'");
cypherCreate.append(fp.getUid());
cypherCreate.append("', enable:");
cypherCreate.append(fp.isEnable());
if (fp.getDescription() != null && fp.getDescription().length() > 0) {
cypherCreate.append(", description:'");
cypherCreate.append(fp.getDescription());
cypherCreate.append("'");
}
if (fp.getPermissions() != null && fp.getPermissions().size() > 0) {
cypherCreate.append(", roles: [");
boolean first = true;
for(String role : fp.getPermissions()) {
if (!first) {
cypherCreate.append(",");
}
cypherCreate.append("'" + role + "'");
first = false;
}
cypherCreate.append("]");
}
cypherCreate.append("});");
return cypherCreate.toString();
}
private String createUpdateCoreFeature(Feature fp) {
StringBuilder cypherUpdate = new StringBuilder("MATCH (f:" + FF4jNeo4jLabels.FF4J_FEATURE + " { uid:'");
cypherUpdate.append(fp.getUid());
cypherUpdate.append("' }) ");
cypherUpdate.append("SET f.enable = " + fp.isEnable());
if (fp.getDescription() != null && fp.getDescription().length() > 0) {
cypherUpdate.append(", f.description = '");
cypherUpdate.append(fp.getDescription());
cypherUpdate.append("'");
}
if (fp.getPermissions() != null && fp.getPermissions().size() > 0) {
cypherUpdate.append(", f.roles = [");
boolean first = true;
for(String role : fp.getPermissions()) {
if (!first) {
cypherUpdate.append(",");
}
cypherUpdate.append("'" + role + "'");
first = false;
}
cypherUpdate.append("]");
} else {
// AS role is null
cypherUpdate.append(", f.roles = []");
}
cypherUpdate.append(";");
return cypherUpdate.toString();
}
private String createUpdateFlippingStrategy(Feature fp) {
String queryUpdate = "MATCH (f:" + FF4jNeo4jLabels.FF4J_FEATURE + " { uid: '";
queryUpdate += fp.getUid() + "' })--(s:FF4J_FLIPPING_STRATEGY) ";
queryUpdate += "SET s.type='";
queryUpdate += fp.getFlippingStrategy().getClass().getName();
queryUpdate += "', s.initParams= [";
Map < String, String > initParams = fp.getFlippingStrategy().getInitParams();
if (initParams != null && initParams.size() > 0) {
boolean first = true;
for (Map.Entry < String, String > entry : initParams.entrySet()) {
if (!first) {
queryUpdate += ",";
}
queryUpdate += "'" + entry.getKey() + "=" + entry.getValue() + "'";
first = false;
}
}
queryUpdate += "];";
return queryUpdate;
}
/** {@inheritDoc} */
@Override
public void create(Feature fp) {
if (fp == null) {
throw new IllegalArgumentException("Feature cannot be null nor empty");
}
if (exist(fp.getUid())) {
throw new FeatureAlreadyExistException(fp.getUid());
}
Transaction tx = graphDb.beginTx();
// Create core
graphDb.execute(createQueryNewCoreFeature(fp));
// Create Flipping Strategy
if (fp.getFlippingStrategy() != null) {
graphDb.execute(createQueryFlippingStrategy(fp));
}
// Create Group
if (fp.getGroup() != null && !"".equals(fp.getGroup())) {
addToGroup(fp.getUid(), fp.getGroup());
}
tx.success();
// Create Properties
if (fp.getCustomProperties() != null && fp.getCustomProperties().size() > 0) {
for (String pName : fp.getCustomProperties().keySet()) {
createProperty(fp.getProperty(pName), fp.getUid());
}
}
}
// ---------------- GROUPS -------------------
/** {@inheritDoc} */
@Override
public boolean existGroup(String groupName) {
Util.assertHasLength(groupName);
Map < String, Object > queryParameters = new HashMap<>();
queryParameters.put(GROUP_NAME, groupName);
Result result = graphDb.execute(QUERY_CYPHER_EXISTS_GROUP, queryParameters);
Object count = null;
if (result.hasNext()) {
count = result.next().get(QUERY_CYPHER_ALIAS);
}
return (null != count) && (((long) count) > 0);
}
/** {@inheritDoc} */
@Override
public Map<String, Feature> readGroup(String groupName) {
assertGroupExist(groupName);
Map<String, Feature> allFeatures = readAll();
Map<String, Feature> groupFeatures = new HashMap<>();
Transaction tx = graphDb.beginTx();
Map<String, Object> paramGroupName = new HashMap<>();
paramGroupName.put(GROUP_NAME, groupName);
Result result = graphDb.execute(QUERY_CYPHER_READ_FEATURES_OF_GROUP, paramGroupName);
while (result.hasNext()) {
String member = (String) result.next().get("UID");
groupFeatures.put(member, allFeatures.get(member));
}
tx.success();
return groupFeatures;
}
/** {@inheritDoc} */
@Override
public void enableGroup(String groupName) {
assertGroupExist(groupName);
Transaction tx = graphDb.beginTx();
Map<String, Object> paramGroupName = new HashMap<>();
paramGroupName.put(GROUP_NAME, groupName);
graphDb.execute(QUERY_CYPHER_ENABLE_GROUP, paramGroupName);
tx.success();
}
/** {@inheritDoc} */
@Override
public void disableGroup(String groupName) {
assertGroupExist(groupName);
Transaction tx = graphDb.beginTx();
Map<String, Object> paramGroupName = new HashMap<>();
paramGroupName.put(GROUP_NAME, groupName);
graphDb.execute(QUERY_CYPHER_DISABLE_GROUP, paramGroupName);
tx.success();
}
/** {@inheritDoc} */
@Override
public void addToGroup(String uid, String groupName) {
assertFeatureExist(uid);
Util.assertHasLength(groupName);
// Create group if not exist
if (!existGroup(groupName)) {
Transaction tx = graphDb.beginTx();
String createGroup = "CREATE (" + groupName + ":" + FF4jNeo4jLabels.FF4J_FEATURE_GROUP;
createGroup += " { name:'" + groupName + "' });";
graphDb.execute(createGroup);
tx.success();
}
// Create relation ship (work with indexes)
Transaction tx = graphDb.beginTx();
Map<String, Object> params = new HashMap<>();
params.put("uid", uid);
params.put(GROUP_NAME, groupName);
graphDb.execute(QUERY_CYPHER_ADDTO_GROUP, params);
tx.success();
}
/** {@inheritDoc} */
@Override
public void removeFromGroup(String uid, String groupName) {
assertFeatureExist(uid);
assertGroupExist(groupName);
Transaction tx = graphDb.beginTx();
Map < String, Object > params = new HashMap<>();
params.put("uid", uid);
graphDb.execute(QUERY_CYPHER_REMOVEFROMGROUP, params);
tx.success();
// Delete node group if not more feature on it
deleteOrphanGroups();
}
/** {@inheritDoc} */
@Override
public Set<String> readAllGroups() {
Result result = graphDb.execute(QUERY_READ_GROUPS);
Set < String > response = new HashSet<>();
while (result.hasNext()) {
response.add((String) result.next().get(GROUPNAME));
}
return response;
}
/**
* Common behaviour to add a result to the feature list.
*
* @param response
* target response
* @param allFeatures
* target feature
*/
private void addToFeatureList(Map < String, Object > response, Map<String, Feature> allFeatures) {
Node nodeFeature = (Node) response.get("f");
String uid = (String) nodeFeature.getProperty(NODEFEATURE_ATT_UID);
// first time meeting this uid, create core Feature object from 'f'
if (!allFeatures.containsKey(uid)) {
Feature currentFeature = fromNode2Feature(nodeFeature);
allFeatures.put(currentFeature.getUid(), currentFeature);
}
if (null != response.get("all")) {
addNeighBour2Feature(allFeatures.get(uid), (Node) response.get("all"));
}
}
/**
* Parse node related to feature and create sub component.
*
* @param targetFeature
* current feature
* @param nodeOther
* current neighbour
*/
private void addNeighBour2Feature(Feature targetFeature, Node nodeOther) {
Util.assertNotNull(targetFeature);
if (nodeOther != null && nodeOther.getLabels().iterator().hasNext()) {
String nodeLabel = nodeOther.getLabels().iterator().next().toString();
FF4jNeo4jLabels lblb = FF4jNeo4jLabels.valueOf(nodeLabel);
switch(lblb) {
case FF4J_FLIPPING_STRATEGY:
FlippingStrategy fs = fromNode2FlippingStrategy(targetFeature.getUid(), nodeOther);
targetFeature.setFlippingStrategy(fs);
break;
case FF4J_FEATURE_PROPERTY:
Property<?> ap = fromNode2Property(nodeOther);
targetFeature.getCustomProperties().put(ap.getName(), ap);
break;
case FF4J_FEATURE_GROUP:
targetFeature.setGroup((String) nodeOther.getProperty(NODEGROUP_ATT_NAME));
break;
default: break;
}
}
}
/**
* Delete orphan groups.
*/
private void deleteOrphanGroups() {
Set < String > groupNames = readAllGroups();
for (String groupName : groupNames) {
Map < String, Object > paramGroupName = new HashMap<>();
paramGroupName.put(GROUP_NAME, groupName);
Result result = graphDb.execute(QUERY_CYPHER_COUNT_FEATURE_OF_GROUP, paramGroupName);
if (result.hasNext()) {
long nbFeature = (long) result.next().get(QUERY_CYPHER_ALIAS);
if (nbFeature == 0) {
// This is the last feature of this Group => delete the GROUP
graphDb.execute(QUERY_CYPHER_DELETE_GROUP, paramGroupName );
}
}
}
}
/** {@inheritDoc} */
@Override
public void clear() {
Transaction tx = graphDb.beginTx();
graphDb.execute(QUERY_CYPHER_DELETE_ALLFEATURE);
graphDb.execute(QUERY_CYPHER_DELETE_ALLSINGLEFEATURE);
tx.success();
}
/** {@inheritDoc} */
@Override
public void createSchema() {
try (Transaction tx = graphDb.beginTx() ) {
if (!graphDb.schema().getConstraints(FF4jNeo4jLabels.FF4J_FEATURE).iterator().hasNext()) {
graphDb.schema().constraintFor(FF4jNeo4jLabels.FF4J_FEATURE)//
.assertPropertyIsUnique(NODEFEATURE_ATT_UID)//
.create();
}
if (!graphDb.schema().getConstraints(FF4jNeo4jLabels.FF4J_FEATURE_GROUP).iterator().hasNext()) {
graphDb.schema().constraintFor(FF4jNeo4jLabels.FF4J_FEATURE_GROUP)//
.assertPropertyIsUnique(NODEGROUP_ATT_NAME )//
.create();
}
tx.success();
}
}
/**
* Getter accessor for attribute 'graphDb'.
*
* @return
* current value of 'graphDb'
*/
public GraphDatabaseService getGraphDb() {
return graphDb;
}
/**
* Setter accessor for attribute 'graphDb'.
* @param graphDb
* new value for 'graphDb '
*/
public void setGraphDb(GraphDatabaseService graphDb) {
this.graphDb = graphDb;
}
}