All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.appng.api.support.ElementHelper Maven / Gradle / Ivy

There is a newer version: 1.24.5
Show newest version
/*
 * Copyright 2011-2019 the original author or authors.
 *
 * 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.
 */
package org.appng.api.support;

import static org.appng.api.Scope.REQUEST;
import static org.appng.api.Scope.SESSION;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;

import org.apache.commons.lang3.StringUtils;
import org.appng.api.ApplicationConfigProvider;
import org.appng.api.DataContainer;
import org.appng.api.Environment;
import org.appng.api.FieldProcessor;
import org.appng.api.MessageParam;
import org.appng.api.Options;
import org.appng.api.ParameterSupport;
import org.appng.api.Path;
import org.appng.api.PermissionOwner;
import org.appng.api.PermissionProcessor;
import org.appng.api.Platform;
import org.appng.api.ProcessingException;
import org.appng.api.Session;
import org.appng.api.model.Application;
import org.appng.api.model.Site;
import org.appng.api.support.environment.EnvironmentKeys;
import org.appng.el.ExpressionEvaluator;
import org.appng.xml.platform.BeanOption;
import org.appng.xml.platform.Condition;
import org.appng.xml.platform.Config;
import org.appng.xml.platform.Data;
import org.appng.xml.platform.DataConfig;
import org.appng.xml.platform.FieldDef;
import org.appng.xml.platform.Link;
import org.appng.xml.platform.Linkmode;
import org.appng.xml.platform.Linkpanel;
import org.appng.xml.platform.Messages;
import org.appng.xml.platform.MetaData;
import org.appng.xml.platform.Navigation;
import org.appng.xml.platform.NavigationItem;
import org.appng.xml.platform.OptionGroup;
import org.appng.xml.platform.PageConfig;
import org.appng.xml.platform.Param;
import org.appng.xml.platform.Params;
import org.appng.xml.platform.Result;
import org.appng.xml.platform.Resultset;
import org.appng.xml.platform.Selection;
import org.appng.xml.platform.SelectionGroup;
import org.appng.xml.platform.Template;
import org.appng.xml.platform.ValidationGroups;
import org.springframework.context.MessageSource;
import org.springframework.data.domain.Page;
import org.springframework.util.ClassUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * Utility class offering methods for proper initialization of {@link Linkpanel}s, {@link Link}s, {@link Navigation}/
 * {@link NavigationItem}s, {@link BeanOption}s, {@link Param}s etc.
 * 
 * @author Matthias Müller
 * 
 */
@Slf4j
public class ElementHelper {

	private static final String SLASH = "/";

	public static final String INTERNAL_ERROR = "internal.error";

	private Application application;

	private Site site;

	private ExpressionEvaluator expressionEvaluator;

	public ElementHelper(Site site, Application application) {
		this.application = application;
		this.site = site;
	}

	public ElementHelper(Site site, Application application, ExpressionEvaluator expressionEvaluator) {
		this.application = application;
		this.site = site;
		this.expressionEvaluator = expressionEvaluator;
	}

	void initLinkpanel(ApplicationRequest applicationRequest, Path pathInfo, DataConfig dsConfig,
			ParameterSupport parameterSupport) {
		List linkpanel = dsConfig.getLinkpanel();
		if (null != linkpanel) {
			List out = null;
			if (null != linkpanel) {
				out = new ArrayList<>();
				for (Linkpanel panel : linkpanel) {
					Linkpanel outPanel = initLinkpanel(applicationRequest, pathInfo, panel, parameterSupport);
					if (null != outPanel) {
						out.add(outPanel);
					}
				}
				linkpanel.clear();
				linkpanel.addAll(out);
			}
		}
	}

	private Linkpanel initLinkpanel(ApplicationRequest request, Path pathInfo, Linkpanel panel,
			ParameterSupport parameterSupport) {
		Linkpanel outPanel = null;
		PermissionProcessor permissionProcessor = request.getPermissionProcessor();
		if (null != panel && permissionProcessor.hasPermissions(new PermissionOwner(panel))) {
			outPanel = new Linkpanel();
			String panelId = panel.getId();
			outPanel.setId(panelId);
			outPanel.setLocation(panel.getLocation());
			List links = panel.getLinks();
			int linkCount = 1;
			String servicePath = pathInfo.getServicePath();
			String guiPath = pathInfo.getGuiPath();
			for (Link link : links) {
				boolean hasPermission = request.getPermissionProcessor().hasPermissions(new PermissionOwner(link));
				if (hasPermission) {
					Condition condition = link.getCondition();
					ExpressionEvaluator linkExpressionEvaluator = parameterSupport.getExpressionEvaluator();
					boolean doInclude = expressionMatchesOrContainsCurrent(condition, linkExpressionEvaluator);
					boolean showDisabled = Boolean.TRUE.equals(link.isShowDisabled());

					if (doInclude || showDisabled) {
						link.setCondition(condition);
						if (link.getId() == null) {
							link.setId(panelId + "[" + linkCount + "]");
						}
						request.setLabel(link.getLabel());
						request.setLabel(link.getConfirmation());
						outPanel.getLinks().add(link);
						String currentTarget = link.getTarget();
						String newTarget = parameterSupport.replaceParameters(currentTarget);
						if (Linkmode.WEBSERVICE.equals(link.getMode())) {
							newTarget = servicePath + SLASH + site.getName() + SLASH + application.getName() + SLASH
									+ Platform.SERVICE_TYPE_WEBSERVICE + SLASH + newTarget;
						}
						if (Linkmode.REST.equals(link.getMode())) {
							newTarget = servicePath + SLASH + site.getName() + SLASH + application.getName() + SLASH
									+ Platform.SERVICE_TYPE_REST + SLASH + newTarget;
						}
						StringBuilder proposedPath = new StringBuilder();
						proposedPath.append(guiPath).append(pathInfo.getOutputPrefix()).append(SLASH);
						proposedPath.append(site.getName()).append(SLASH).append(application.getName());
						proposedPath.append(newTarget);
						if (pathInfo.isPathSelected(proposedPath.toString())) {
							link.setActive(Boolean.TRUE.toString());
						}
						link.setTarget(newTarget);
					}
				}
				linkCount++;
			}
		}
		return outPanel;
	}

	private boolean expressionMatchesOrContainsCurrent(Condition condition,
			ExpressionEvaluator conditionExpressionEvaluator) {
		if (null != condition) {
			String expression = condition.getExpression();
			if (StringUtils.isNotBlank(expression) && !expression.contains(AdapterBase.CURRENT)) {
				return conditionExpressionEvaluator.evaluate(expression);
			}
		}
		return true;
	}

	public void initNavigation(ApplicationRequest applicationRequest, Path pathInfo, PageConfig pageConfig) {
		ParameterSupport parameterSupport = applicationRequest.getParameterSupportDollar();
		Linkpanel pageLinks = initLinkpanel(applicationRequest, pathInfo, pageConfig.getLinkpanel(), parameterSupport);

		Linkpanel navigation = applicationRequest.getApplicationConfig().getApplicationRootConfig().getNavigation();
		if (null != navigation) {
			navigation = initLinkpanel(applicationRequest, pathInfo, navigation, parameterSupport);
			if (!(null == pageLinks || null == navigation)) {
				List links = navigation.getLinks();
				for (Link link : links) {
					pageLinks.getLinks().add(link);
				}
				pageConfig.setLinkpanel(pageLinks);
			} else {
				pageConfig.setLinkpanel(navigation);
			}
		}
	}

	/**
	 * Builds {@link Options} from the given list of {@link BeanOption}s, without evaluation of parameter placeholders.
	 * 
	 * @param beanOptions
	 *            some {@link BeanOption}s
	 * @return the {@link Options}
	 * @see #initOptions(List)
	 */
	Options getOptions(List beanOptions) {
		OptionsImpl options = new OptionsImpl();
		if (null != beanOptions) {
			for (BeanOption beanOption : beanOptions) {
				OptionImpl opt = new OptionImpl(beanOption.getName());
				Map attributes = beanOption.getOtherAttributes();
				for (Entry entry : attributes.entrySet()) {
					String optionName = entry.getKey().getLocalPart();
					opt.addAttribute(optionName, entry.getValue());
				}
				options.addOption(opt);
			}
		}
		return options;
	}

	/**
	 * Performs parameter-replacement for the given {@link BeanOption}s
	 * 
	 * @param beanOptions
	 *            some {@link BeanOption}s
	 */
	void initOptions(List beanOptions) {
		if (null != beanOptions) {
			for (BeanOption beanOption : beanOptions) {
				Map attributes = beanOption.getOtherAttributes();
				for (Entry entry : attributes.entrySet()) {
					String value = expressionEvaluator.evaluate(entry.getValue(), String.class);
					entry.setValue(value);
				}
			}
		}
	}

	void setSelectionTitles(Data data, ApplicationRequest applicationRequest) {
		setSelectionTitles(data.getSelections(), applicationRequest);
		for (SelectionGroup group : data.getSelectionGroups()) {
			setSelectionTitles(group.getSelections(), applicationRequest);
		}
	}

	private void setSelectionTitles(List selections, ApplicationRequest applicationRequest) {
		for (Selection selection : selections) {
			applicationRequest.setLabel(selection.getTitle());
			for (OptionGroup optionGroup : selection.getOptionGroups()) {
				applicationRequest.setLabel(optionGroup.getLabel());
			}
		}
	}

	void processConfig(ApplicationConfigProvider applicationConfigProvider, ApplicationRequest applicationRequest,
			DataConfig config, Map parameters) {
		MetaData metaData = getFilteredMetaData(applicationRequest, config.getMetaData(), false);
		config.setMetaData(metaData);
		// DO NOT evaluate hidden and readOnly here!!
		Path path = applicationRequest.getEnvironment().getAttribute(REQUEST, EnvironmentKeys.PATH_INFO);
		initLinkpanel(applicationRequest, path, config, new DollarParameterSupport(parameters));
		addTemplates(applicationConfigProvider, config);
	}

	MetaData getFilteredMetaData(ApplicationRequest request, MetaData metaData, boolean write) {
		MetaData result = new MetaData();
		if (null != metaData) {
			result.setBinding(metaData.getBinding());
			result.setResultSelector(metaData.getResultSelector());
			result.setBindClass(metaData.getBindClass());
			result.setValidation(metaData.getValidation());
			List fieldDefinitions = metaData.getFields();
			List fields = filterFieldDefinitions(request, fieldDefinitions, write);
			result.getFields().addAll(fields);
		}
		return result;
	}

	/**
	 * removes those {@link FieldDef}s from the given fieldDefinitions for whom the user has no permissions and returns
	 * a new list containing only the allowed {@link FieldDef}s
	 */
	private List filterFieldDefinitions(ApplicationRequest request, List fieldDefinitions,
			boolean write) {
		List fields = new ArrayList<>();
		PermissionProcessor permissionProcessor = request.getPermissionProcessor();
		if (null != fieldDefinitions) {
			for (FieldDef fieldDef : fieldDefinitions) {
				boolean hasPermission = false;
				if (write) {
					hasPermission = permissionProcessor.hasWritePermission(fieldDef);
				} else {
					hasPermission = permissionProcessor.hasReadPermission(fieldDef);
				}
				if (hasPermission) {
					if (!write) {
						request.setLabel(fieldDef.getLabel());
					}
					Condition condition = fieldDef.getCondition();
					boolean isValid = expressionMatchesOrContainsCurrent(condition, expressionEvaluator);
					if (isValid) {
						String format = fieldDef.getFormat();
						if (null != format) {
							format = expressionEvaluator.evaluate(format, String.class);
							fieldDef.setFormat(format);
						}
						filterFieldDefinitions(request, fieldDef.getFields(), write);
						fields.add(fieldDef);
					}
				}
			}
		}
		return fields;
	}

	void addTemplates(ApplicationConfigProvider applicationConfigProvider, Config config) {
		List