I have this Json Strucute Mapped and persisted as a Java Object:
[
{
"name": "users",
"activationUrl": "users/activation",
"initialPage": "users/manageUsers",
"newUntilDate": "2017-01-01",
"requireActivation": true,
"menu": {
"mainMenu": {
"items": {
"users": {
"state": "users.dashboard",
"i18n": "DASHBOARD",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"dashboard": {
"state": "invoices.dashboard",
"i18n": "DASHBOARD",
"index": 1,
"iconClass": "fa-question-circle",
"featuresToShown": [
"editUsers",
"createUser"
]
}
}
}
}
},
"secondaryMenu": {
"items": {
"configuration": {
"state": null,
"i18n": "CONFIGURATION",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"manageUsers": {
"state": "users.manageUsers",
"i18n": "USER_MANAGER",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"listUsers",
"editUsers",
"createUser"
]
},
"anotherManageUsers": {
"state": "users.manageUsers",
"i18n": "USER_MANAGER",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"editUsers",
"createUser"
]
}
}
},
"anotherConfiguration": {
"state": null,
"i18n": "CONFIGURATION",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"manageUsers": {
"state": "users.manageUsers",
"i18n": "USER_MANAGER",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"editUsers",
"createUser"
]
},
"anotherManageUsers": {
"state": "users.manageUsers",
"i18n": "USER_MANAGER",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"editUsers",
"createUser"
]
}
}
}
}
},
"usersMenu": {
"items": {
"default": {
"state": null,
"i18n": null,
"index": null,
"iconClass": null,
"subItems": {
"signOut": {
"state": "sign-out",
"i18n": "Cerrar Sesión",
"index": 1,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
}
}
}
},
"defaultActivation": {
"accounts": [
"500026",
"500027"
],
"paymentsModel": {
"TSP": [
"CO",
"AR"
],
"PSP": [
"CO"
]
}
}
},
{
"name": "invoices",
"activationUrl": "invoices/activation",
"initialPage": "invoices/dashboard",
"newUntilDate": "2017-01-01",
"requireActivation": true,
"menu": {
"mainMenu": {
"items": {
"invoices": {
"state": null,
"i18n": "INVOICES",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"dashboard": {
"state": "invoices.dashboard",
"i18n": "DASHBOARD",
"index": 1,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload"
]
},
"configuration": {
"state": "invoices.configuration",
"i18n": "CONFIGURATION",
"index": 2,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.merchants"
]
},
"upload": {
"state": "invoices.upload",
"i18n": "UPLOAD_INVOICES",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.accounts",
"consult",
"configure.merchants"
]
},
"queries": {
"state": "invoices.queries",
"i18n": "QUERIES",
"index": 4,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
},
"formats": {
"state": "invoices.formats",
"i18n": "FORMAT_MANAGEMENT",
"index": 5,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.invoices",
"configure.accounts",
"consult"
]
},
"reports": {
"state": "invoices.reports",
"i18n": "SCHEDULE_REPORTS",
"index": 6,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.invoices",
"configure.accounts",
"graphics"
]
}
}
}
}
},
"secondaryMenu": {
"items": {
"help": {
"state": null,
"i18n": "HELP",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"reports": {
"state": "invoices.help",
"i18n": "INVOICES_REPORTS_HELP",
"index": 5,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
},
"configuration": {
"state": null,
"i18n": "CONFIGURATION",
"index": 2,
"iconClass": "fa-question-circle",
"subItems": {}
},
"developers": {
"state": null,
"i18n": "DEVELOPERS",
"index": 2,
"iconClass": "fa-question-circle",
"subItems": {}
},
"notification": {
"state": null,
"i18n": "CONFIGURATION",
"index": 2,
"iconClass": "fa-question-circle",
"subItems": {
"reports": {
"state": "invoices.notification",
"i18n": "INVOICES_NOTIFICATIONS",
"index": 1,
"iconClass": null,
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
}
}
},
"usersMenu": {
"items": {
"default": {
"state": null,
"i18n": null,
"index": null,
"iconClass": null,
"subItems": {
"signOut": {
"state": "sign-out",
"i18n": "Cerrar Sesión",
"index": 1,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
}
}
}
},
"defaultActivation": {
"accounts": [
"500026",
"500027"
],
"paymentsModel": {
"TSP": [
"CO",
"AR"
],
"PSP": [
"CO"
]
}
}
}
]
The way I persist it with a post:
public Module create(@Valid Module module, String moduleUrl)
throws RestAuthenticationException, JSONException, IOException, BusinessException {
...
dao.save(module);
return module;
}
The module structure:
@Document(collection = "menus")
public class Module {
@Indexed(unique = true)
private String name;
private String activationUrl;
private String initialPage;
private String newUntilDate;
private Boolean requireActivation;
private Map<String, Menu> menu;
private DefaultActivation defaultActivation;
...
}
And so on.
I need to return the same structure but filter by profile permissions, obtained from another service, is just a Map and its representation in json is like this:
api/permissions?profile="ADMIN"
{
"invoices.configure.merchants": true,
"invoices.configure.invoices": true,
"invoices.configure.accounts": true,
"invoices.consult": true,
"invoices.upload": true,
"invoices.graphics": true,
"users.listUsers": true,
"users.editUsers": true,
"users.createUser": true
}
api/permissions?profile="CONSULT"
{
"invoices.configure.merchants": false,
"invoices.configure.invoices": false,
"invoices.configure.accounts": true,
"invoices.consult": true,
"invoices.upload": false,
"invoices.graphics": false,
"users.listUsers": true,
"users.editUsers": false,
"users.createUser": false
}
The idea is delete from the original structure those elements that do not match based on the field "featuresToShown" if al least one of it features is defined in "features", for profile "ADMIN" for example the structure remain the same because all permissions are setted to 'true', but for "CONSULT" it has to be filtered like:
[
{
"name": "users",
"activationUrl": "users/activation",
"initialPage": "users/manageUsers",
"newUntilDate": "2017-01-01",
"requireActivation": true,
"menu": {
"secondaryMenu": {
"items": {
"configuration": {
"state": null,
"i18n": "CONFIGURATION",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"manageUsers": {
"state": "users.manageUsers",
"i18n": "USER_MANAGER",
"index": 3,
"iconClass": "fa-question-circle",
"featuresToShown": [
"listUsers",
"editUsers",
"createUser"
]
}
}
},
}
}
},
"defaultActivation": {
"accounts": [
"500026",
"500027"
],
"paymentsModel": {
"TSP": [
"CO",
"AR"
],
"PSP": [
"CO"
]
}
}
},
{
"name": "invoices",
"activationUrl": "invoices/activation",
"initialPage": "invoices/dashboard",
"newUntilDate": "2017-01-01",
"requireActivation": true,
"menu": {
"mainMenu": {
"items": {
"invoices": {
"state": null,
"i18n": "INVOICES",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"queries": {
"state": "invoices.queries",
"i18n": "QUERIES",
"index": 4,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
},
"formats": {
"state": "invoices.formats",
"i18n": "FORMAT_MANAGEMENT",
"index": 5,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.invoices",
"configure.accounts",
"consult"
]
},
"reports": {
"state": "invoices.reports",
"i18n": "SCHEDULE_REPORTS",
"index": 6,
"iconClass": "fa-question-circle",
"featuresToShown": [
"configure.invoices",
"configure.accounts",
"graphics"
]
}
}
}
}
},
"secondaryMenu": {
"items": {
"help": {
"state": null,
"i18n": "HELP",
"index": 1,
"iconClass": "fa-question-circle",
"subItems": {
"reports": {
"state": "invoices.help",
"i18n": "INVOICES_REPORTS_HELP",
"index": 5,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
},
"notification": {
"state": null,
"i18n": "CONFIGURATION",
"index": 2,
"iconClass": "fa-question-circle",
"subItems": {
"reports": {
"state": "invoices.notification",
"i18n": "INVOICES_NOTIFICATIONS",
"index": 1,
"iconClass": null,
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
}
}
},
"usersMenu": {
"items": {
"default": {
"state": null,
"i18n": null,
"index": null,
"iconClass": null,
"subItems": {
"signOut": {
"state": "sign-out",
"i18n": "Cerrar Sesión",
"index": 1,
"iconClass": "fa-question-circle",
"featuresToShown": [
"upload",
"configure.accounts",
"consult"
]
}
}
}
}
}
},
"defaultActivation": {
"accounts": [
"500026",
"500027"
],
"paymentsModel": {
"TSP": [
"CO",
"AR"
],
"PSP": [
"CO"
]
}
}
}
]
The way I'm doing it is iterating over all the structure and creating auxiliar strucutres to assemble the final Module with validations, but this is a lot of work for the levels in the document and so many for statements.
A piece of this nasty code:
// filters the all the menus by the permissions incoming
for (Map.Entry<String, Boolean> permission : permissions.entrySet()) {
// returns features with permission for the profile and merchant
if (permissions.get(permission.getKey())) {
profilePermissions.add(permission.getKey());
}
}
// keeps the menu for a merchant and profile
Map<String, Map<String, Menu>> menusProfileMerchant = new HashMap<String, Map<String, Menu>>();
// available modules
List<Module> modules = getAllModules();
// defines the list of modules with the menus for the profile
List<Module> modulesByProfile = new ArrayList<Module>();
// iterate the module definition
for (Module module : modules) {
Map<String, Menu> menusProfile = new HashMap<String, Menu>();
for (Map.Entry<String, Menu> menu : module.getMenu().entrySet()) {
Map<String, ModuleItem> items = menu.getValue().getItems();
// keeps the item with features for the profile
Map<String, ModuleItem> itemsProfile = new HashMap<String, ModuleItem>();
// iterates over the items and features for a profile
for (Map.Entry<String, ModuleItem> item : items.entrySet()) {
/** the variable to validate if the features is contained for the profile */
boolean contains = false;
for (String permission : profilePermissions) {
// keeps the module name from profile permissions
String permissionModule = permission.substring(0,
permission.indexOf(dotSeparator));
// keeps the permissions from profile permissions
String permissionFeature = permission
.substring(permission.indexOf(dotSeparator) + initialIndex);
// defines the containing feature for the module and profile
Map<String, ModuleSubItem> subItems = item.getValue().getSubItems();
Map<String, ModuleSubItem> subItemsProfile = new HashMap<String, ModuleSubItem>();
if (subItems != null) {
for (Map.Entry<String, ModuleSubItem> subItem : subItems.entrySet()) {
if (permissionModule.equals(module.getName()) && subItem.getValue()
.getFeaturesToShown().contains(permissionFeature)) {
contains = true;
}
}
// adds the features for the menus by profile
if (contains) {
itemsProfile.put(item.getKey(), item.getValue());
}
}
}
}
// sets the items defined just for a profile with permissions over them
menu.getValue().setItems(itemsProfile);
menusProfile.put(menu.getKey(), menu.getValue());
}
// add the module menu just for a profile with permissions over it
menusProfileMerchant.put(module.getName(), menusProfile);
modulesByProfile.add(module);
}
// returns the list of modules with the menus for the profile
return modulesByProfile;
}
I have not find something more efficient. It can be done in a cleaner way? I'm using Java 8.