/*
* Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved.
*
* This file is part of the Jspresso framework.
*
* Jspresso is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jspresso 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Jspresso. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jspresso.framework.application.security;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import org.jspresso.framework.application.frontend.IFrontendController;
import org.jspresso.framework.application.model.BeanCollectionModule;
import org.jspresso.framework.application.model.Module;
import org.jspresso.framework.application.model.Workspace;
import org.jspresso.framework.model.descriptor.ICollectionDescriptorProvider;
import org.jspresso.framework.model.descriptor.ICollectionPropertyDescriptor;
import org.jspresso.framework.model.descriptor.IComponentDescriptor;
import org.jspresso.framework.model.descriptor.IComponentDescriptorProvider;
import org.jspresso.framework.model.descriptor.IPropertyDescriptor;
import org.jspresso.framework.model.descriptor.IReferencePropertyDescriptor;
import org.jspresso.framework.model.descriptor.IRelationshipEndPropertyDescriptor;
import org.jspresso.framework.security.ISecurable;
import org.jspresso.framework.security.ISecurityContextBuilder;
import org.jspresso.framework.security.ISecurityHandler;
import org.jspresso.framework.view.action.ActionList;
import org.jspresso.framework.view.action.ActionMap;
import org.jspresso.framework.view.action.IDisplayableAction;
import org.jspresso.framework.view.descriptor.IComponentViewDescriptor;
import org.jspresso.framework.view.descriptor.ICompositeViewDescriptor;
import org.jspresso.framework.view.descriptor.ITableViewDescriptor;
import org.jspresso.framework.view.descriptor.IViewDescriptor;
/**
* A Directory builder to list the application various application elements
* available along with their permId.
*
* @author Vincent Vandenschrick
*/
public class ApplicationDirectoryBuilder {
private String[] excludePatterns;
/**
* {@code MODEL}.
*/
public static final String MODEL = "MODEL";
/**
* {@code NAVIGATION}.
*/
public static final String NAVIGATION = "NAVIGATION";
/**
* {@code VIEW}.
*/
public static final String VIEW = "VIEW";
/**
* {@code ACTION}.
*/
public static final String ACTION = "ACTION";
private final Set<String> modelPermIds;
private final Set<String> navigationPermIds;
private final Set<String> viewPermIds;
private final Set<String> actionPermIds;
/**
* Constructs a new {@code ApplicationDirectoryBuilder} instance.
*/
public ApplicationDirectoryBuilder() {
modelPermIds = new TreeSet<>();
navigationPermIds = new TreeSet<>();
viewPermIds = new TreeSet<>();
actionPermIds = new TreeSet<>();
excludePatterns = new String[] {
"org\\.jspresso\\.framework\\..*"
};
}
/**
* Processes a workspace recursively to register all reachable application
* elements into the directory.
*
* @param frontendController
* the application front controller to analyse.
* @return this.
*/
public ApplicationDirectoryBuilder process(IFrontendController<?, ?, ?> frontendController) {
if (frontendController.getActionMap() != null) {
process(frontendController.getActionMap());
}
if (frontendController.getSecondaryActionMap() != null) {
process(frontendController.getSecondaryActionMap());
}
for (String workspaceName : frontendController.getWorkspaceNames(true)) {
Workspace workspace = frontendController.getWorkspace(workspaceName);
String wsPermId = workspace.getPermId();
if (wsPermId != null) {
if (isPermIdExcluded(wsPermId) || navigationPermIds.contains(wsPermId)) {
return this;
}
navigationPermIds.add(wsPermId);
}
for (Module module : workspace.getModules()) {
process(module, wsPermId);
}
}
return this;
}
private void process(IComponentDescriptor<?> componentDescriptor) {
String compPermId = componentDescriptor.getPermId();
if (compPermId != null) {
if (isPermIdExcluded(compPermId) || modelPermIds.contains(compPermId)) {
return;
}
modelPermIds.add(compPermId);
}
for (IPropertyDescriptor propertyDescriptor : componentDescriptor
.getPropertyDescriptors()) {
process(propertyDescriptor, compPermId, modelPermIds);
if (propertyDescriptor instanceof IRelationshipEndPropertyDescriptor) {
if (propertyDescriptor instanceof IReferencePropertyDescriptor<?>) {
process(((IReferencePropertyDescriptor<?>) propertyDescriptor)
.getReferencedDescriptor());
} else if (propertyDescriptor instanceof ICollectionPropertyDescriptor<?>) {
process(((ICollectionPropertyDescriptor<?>) propertyDescriptor)
.getReferencedDescriptor().getElementDescriptor());
}
}
}
}
private void process(IPropertyDescriptor propertyDescriptor, String path,
Set<String> permIdsSet) {
String propertyPermId = propertyDescriptor.getPermId();
if (propertyPermId != null) {
if (path != null) {
permIdsSet.add(path + "." + propertyPermId);
} else {
permIdsSet.add(propertyPermId);
}
}
}
private void process(Module module, String path) {
String modulePermId = module.getPermId();
if (modulePermId != null) {
if (path != null) {
modulePermId = path + "." + modulePermId;
}
if (isPermIdExcluded(modulePermId)
|| navigationPermIds.contains(modulePermId)) {
return;
}
navigationPermIds.add(modulePermId);
}
if (module.getViewDescriptor() != null) {
process(module.getViewDescriptor(), null);
}
if (module instanceof BeanCollectionModule
&& ((BeanCollectionModule) module).getElementViewDescriptor() != null) {
process(((BeanCollectionModule) module).getElementViewDescriptor(), null);
}
if (module.getSubModules() != null) {
for (Module subModule : module.getSubModules()) {
process(subModule, modulePermId);
}
}
}
private void process(IViewDescriptor viewDescriptor, String path) {
String viewPermId = viewDescriptor.getPermId();
if (viewPermId != null) {
if (path != null) {
viewPermId = path + "." + viewPermId;
}
if (isPermIdExcluded(viewPermId) || viewPermIds.contains(viewPermId)) {
return;
}
viewPermIds.add(viewPermId);
}
if (viewDescriptor.getModelDescriptor() instanceof IComponentDescriptorProvider<?>) {
process(((IComponentDescriptorProvider<?>) viewDescriptor.getModelDescriptor()).getComponentDescriptor());
} else if (viewDescriptor.getModelDescriptor() instanceof ICollectionDescriptorProvider<?>) {
process(((ICollectionDescriptorProvider<?>) viewDescriptor
.getModelDescriptor()).getCollectionDescriptor().getElementDescriptor());
}
if (viewDescriptor.getActionMap() != null) {
process(viewDescriptor.getActionMap());
}
if (viewDescriptor.getSecondaryActionMap() != null) {
process(viewDescriptor.getSecondaryActionMap());
}
if (viewDescriptor instanceof ICompositeViewDescriptor) {
for (IViewDescriptor childViewDescriptor : ((ICompositeViewDescriptor) viewDescriptor)
.getChildViewDescriptors()) {
process(childViewDescriptor, /* viewPermId */null);
}
} else if (viewDescriptor instanceof ITableViewDescriptor
&& viewPermId != null) {
for (IViewDescriptor columnViewDescriptor : ((ITableViewDescriptor) viewDescriptor)
.getColumnViewDescriptors()) {
process(
(IPropertyDescriptor) columnViewDescriptor.getModelDescriptor(),
viewPermId, viewPermIds);
}
} else if (viewDescriptor instanceof IComponentViewDescriptor
&& viewPermId != null) {
for (IViewDescriptor propertyViewDescriptor : ((IComponentViewDescriptor) viewDescriptor)
.getPropertyViewDescriptors()) {
process(
(IPropertyDescriptor) propertyViewDescriptor.getModelDescriptor(),
viewPermId, viewPermIds);
}
}
}
private void process(ActionMap actionMap) {
String amPermId = actionMap.getPermId();
if (amPermId != null) {
if (isPermIdExcluded(amPermId) || actionPermIds.contains(amPermId)) {
return;
}
actionPermIds.add(amPermId);
}
for (ActionList actionList : actionMap
.getActionLists(new ISecurityHandler() {
@Override
public ISecurityContextBuilder restoreLastSecurityContextSnapshot() {
return this;
}
@Override
public ISecurityContextBuilder pushToSecurityContext(
Object contextElement) {
return this;
}
@Override
public Map<String, Object> getSecurityContext() {
return null;
}
@Override
public boolean isAccessGranted(ISecurable securable) {
return true;
}
})) {
process(actionList, amPermId);
}
}
private void process(ActionList actionList, String path) {
String alPermId = actionList.getPermId();
if (alPermId != null) {
if (path != null) {
alPermId = path + "." + alPermId;
}
if (isPermIdExcluded(alPermId) || actionPermIds.contains(alPermId)) {
return;
}
actionPermIds.add(alPermId);
}
for (IDisplayableAction action : actionList.getActions()) {
process(action, alPermId);
}
}
private void process(IDisplayableAction action, String path) {
String actionPermId = action.getPermId();
if (actionPermId != null) {
if (path != null) {
actionPermId = path + "." + actionPermId;
}
if (isPermIdExcluded(actionPermId)
|| actionPermIds.contains(actionPermId)) {
return;
}
actionPermIds.add(actionPermId);
}
}
/**
* Extracts the permId store from this directory builder.
*
* @return the application elements directory.
*/
public Map<String, Set<String>> toApplicationDirectory() {
Map<String, Set<String>> applicationDirectory = new HashMap<>();
applicationDirectory.put(NAVIGATION, navigationPermIds);
applicationDirectory.put(VIEW, viewPermIds);
applicationDirectory.put(MODEL, modelPermIds);
applicationDirectory.put(ACTION, actionPermIds);
return applicationDirectory;
}
private boolean isPermIdExcluded(String permId) {
if (excludePatterns != null && permId != null) {
for (String excludePattern : excludePatterns) {
if (Pattern.matches(excludePattern, permId)) {
return true;
}
}
}
return false;
}
/**
* Sets the excludePatterns.
*
* @param excludePatterns
* the excludePatterns to set.
*/
public void setExcludePatterns(String... excludePatterns) {
this.excludePatterns = excludePatterns;
}
}