org.appng.api.support.CallableDataSource Maven / Gradle / Ivy
/*
* 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 java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.appng.api.DataContainer;
import org.appng.api.DataProvider;
import org.appng.api.Environment;
import org.appng.api.Options;
import org.appng.api.ParameterSupport;
import org.appng.api.PermissionOwner;
import org.appng.api.PermissionProcessor;
import org.appng.api.ProcessingException;
import org.appng.api.SiteProperties;
import org.appng.api.model.Application;
import org.appng.api.model.Site;
import org.appng.el.ExpressionEvaluator;
import org.appng.xml.platform.Action;
import org.appng.xml.platform.Bean;
import org.appng.xml.platform.Condition;
import org.appng.xml.platform.Data;
import org.appng.xml.platform.DataConfig;
import org.appng.xml.platform.Datasource;
import org.appng.xml.platform.DatasourceRef;
import org.appng.xml.platform.MetaData;
import org.appng.xml.platform.PageDefinition;
import org.appng.xml.platform.PageReference;
import org.appng.xml.platform.Permissions;
import org.appng.xml.platform.SectionelementDef;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import lombok.extern.slf4j.Slf4j;
/**
*
* A {@code CallableDataSource} is responsible for preparing and performing an {@link Datasource}, based on a
* {@link DatasourceRef}. This {@link DatasourceRef} is provided either by a {@link PageDefinition}'s
* {@link SectionelementDef} or by an {@link Action}.
*
* @author Matthias Müller
*
*/
@Slf4j
public class CallableDataSource {
private ApplicationRequest applicationRequest;
private Site site;
private Application application;
private DatasourceRef datasourceRef;
private boolean include = false;
private ElementHelper elementHelper;
private Datasource datasource;
private Integer defaultPageSize;
/**
* Creates a new {@code CallableDataSource} and also determines the return value for {@link #doInclude()}, based on
* {@link Permissions} and {@link Condition}s.
*
* @param site
* the current {@link Site}
* @param application
* the current {@link Application}
* @param applicationRequest
* the current {@link ApplicationRequest}
* @param parameterSupport
* the {@link ParameterSupport} holding the parameters for the {@link Datasource}
* @param datasourceRef
* the {@link DatasourceRef} as given in the {@link SectionelementDef} of a {@link PageDefinition} or by
* an {@link Action}.
* @throws ProcessingException
* if an error occurs while assembling the {@code CallableDataSource}
*/
public CallableDataSource(Site site, Application application, ApplicationRequest applicationRequest,
ParameterSupport parameterSupport, DatasourceRef datasourceRef) throws ProcessingException {
this.site = site;
this.application = application;
this.applicationRequest = applicationRequest;
this.datasourceRef = datasourceRef;
if (null == datasourceRef.getPageSize()) {
this.defaultPageSize = site.getProperties().getInteger(SiteProperties.DEFAULT_PAGE_SIZE);
} else {
this.defaultPageSize = datasourceRef.getPageSize();
}
PermissionProcessor permissionProcessor = applicationRequest.getPermissionProcessor();
if (permissionProcessor.hasPermissions(new PermissionOwner(datasourceRef))) {
ExpressionEvaluator includeEvaluator = new ExpressionEvaluator(parameterSupport.getParameters());
this.elementHelper = new ElementHelper(site, application, includeEvaluator);
Condition includeCondition = datasourceRef.getCondition();
if (elementHelper.conditionMatches(includeEvaluator, includeCondition)) {
this.datasource = applicationRequest.getApplicationConfig().getDatasource(datasourceRef.getId());
if (null == datasource) {
throw new ProcessingException("no such datasource: " + datasourceRef.getId(),
new FieldProcessorImpl(datasourceRef.getId()));
}
if (permissionProcessor.hasPermissions(new PermissionOwner(datasource))) {
this.include = true;
datasource.setMode(datasourceRef.getMode());
DataConfig config = getDatasource().getConfig();
Map dataSourceParameters = elementHelper.initializeParameters("datasource '"
+ datasourceRef.getId() + "'", applicationRequest, parameterSupport,
datasourceRef.getParams(), config.getParams());
LOGGER.trace("parameters for datasource '{}': {}", datasourceRef.getId(), dataSourceParameters);
elementHelper.processConfig(applicationRequest.getApplicationConfig(), applicationRequest,
datasource.getConfig(), dataSourceParameters);
Bean bean = getDatasource().getBean();
if (null != bean) {
elementHelper.initOptions(bean.getOptions());
}
applicationRequest.setLabels(datasource.getConfig());
LOGGER.debug("including datasource '{}'", datasource.getId());
} else {
LOGGER.debug("no permission for datasource '{}'", datasource.getId());
}
} else {
LOGGER.debug("include condition for datasource '{}' did not match - {}", datasourceRef.getId(),
includeCondition.getExpression());
}
} else {
LOGGER.debug("no permission(s) for datasourceRef '{}'", datasourceRef.getId());
}
}
public Datasource getDatasource() {
return datasource;
}
/**
* Performs this {@link CallableDataSource}, setting the {@link Bean} {@code null} afterwards.
*
* @see #perform(String, boolean, boolean)
*/
public Data perform(String pageId) throws ProcessingException {
return perform(pageId, true, false);
}
/**
* Performs the {@link CallableDataSource}.
* Note that the caller needs to check if the {@link Datasource} should be included by itself (by calling
* {@link #doInclude()}), as this method doesn't check that condition.
*
* @param pageId
* the ID of the current page
* @param setBeanNull
* whether or not to set the {@link Bean} of the {@link Datasource} to {@code null} after performing
* @param addValidation
* whether or not to add validation metadata
* @return the {@link Data} retrieved from the {@link Datasource} by calling
* {@link DataProvider#getData(Site, Application, org.appng.api.Environment, Options, org.appng.api.Request, org.appng.api.FieldProcessor)}
* @throws ProcessingException
* if an error occurs while retrieving the {@code Data}
*/
public Data perform(String pageId, boolean setBeanNull, boolean addValidation) throws ProcessingException {
Bean bean = datasource.getBean();
if (null != bean) {
FieldProcessorImpl fieldProcessor = null;
try {
String beanId = bean.getId();
LOGGER.trace("retrieving datasource '{}'", beanId);
DataProvider dataProvider = this.application.getBean(beanId, DataProvider.class);
LOGGER.trace("datasource '{}' is of Type '{}'", beanId, dataProvider.getClass().getName());
String id = datasource.getId();
// datasource.setSource(dataProvider.getClass().getName());
Options options = elementHelper.getOptions(bean.getOptions());
MetaData metaData = getDatasource().getConfig().getMetaData();
fieldProcessor = new FieldProcessorImpl(id, metaData);
fieldProcessor.addLinkPanels(datasource.getConfig().getLinkpanel());
SortParamSupport sortParamSupport = getSortParams(pageId, id);
if (null != sortParamSupport) {
String sortParam = applicationRequest.getParameter(sortParamSupport.getRequestKey());
fieldProcessor.setPageable(sortParamSupport.getPageable(sortParam));
} else {
fieldProcessor.setPageable(null);
}
LOGGER.trace("options for datasource '{}': {}", datasourceRef.getId(), options);
DataContainer container = dataProvider.getData(site, application, applicationRequest.getEnvironment(),
options, applicationRequest, fieldProcessor);
if (null == container) {
throw new ProcessingException(dataProvider.getClass() + " returned null", fieldProcessor);
}
Page> page = container.getPage();
if (null != page) {
if (page.getTotalPages() > 0 && page.getNumber() >= page.getTotalPages()) {
String requestKey = sortParamSupport.getRequestKey();
PageRequest pageable = new PageRequest(0, page.getSize(), page.getSort());
String sortString = sortParamSupport.getSortString(pageable);
String servletPath = applicationRequest.getHttpServletRequest().getServletPath();
String target = servletPath + "?" + requestKey + "=" + sortString;
LOGGER.debug("invalid page for datasource {} requested, redirecting to {}", id, target);
site.sendRedirect(applicationRequest.getEnvironment(), target, HttpServletResponse.SC_FOUND);
}
} else if (addValidation && null != container.getItem()) {
applicationRequest.addValidationMetaData(metaData, site.getSiteClassLoader(),
elementHelper.getValidationGroups(metaData, container.getItem()));
}
ElementHelper.addMessages(applicationRequest.getEnvironment(), fieldProcessor.getMessages());
Data data = container.getWrappedData();
getDatasource().setData(data);
elementHelper.setSelectionTitles(data, applicationRequest);
elementHelper.processDataContainer(applicationRequest, container, dataProvider.getClass().getName());
if (setBeanNull) {
getDatasource().setBean(null);
}
} catch (Exception e) {
String id = String.valueOf(e.hashCode());
if (!elementHelper.isMessageParam(e) && null != fieldProcessor) {
fieldProcessor.clearMessages();
String message = applicationRequest.getMessage(ElementHelper.INTERNAL_ERROR, id);
fieldProcessor.addErrorMessage(message);
}
throw new ProcessingException("error retrieving datasource '" + datasource.getId() + "', ID: " + id, e,
fieldProcessor);
}
} else {
LOGGER.info("{} is static!", getDatasource().getId());
}
return getDatasource().getData();
}
private SortParamSupport getSortParams(String pageId, String dsId) {
if (null != pageId) {
Environment env = applicationRequest.getEnvironment();
Map sessionParams = application.getSessionParams(site, env);
return new SortParamSupport(sessionParams, pageId, dsId, defaultPageSize);
}
return null;
}
/**
* Checks whether or not to include this {@code CallableDataSource} on the referencing {@link PageReference} or
* {@link Action}.
*
* @return {@code true} if this {@code CallableDataSource} should be included, {@code false} otherwise
*/
public boolean doInclude() {
return include;
}
@Override
public String toString() {
return datasourceRef.getId();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy