/**
* Copyright (C) 2009 BonitaSoft S.A.
* BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.forms.server.accessor.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bonitasoft.forms.client.model.Expression;
import org.bonitasoft.forms.client.model.FormAction;
import org.bonitasoft.forms.client.model.FormType;
import org.bonitasoft.forms.client.model.FormValidator;
import org.bonitasoft.forms.client.model.FormWidget;
import org.bonitasoft.forms.client.model.TransientData;
import org.bonitasoft.forms.server.accessor.DefaultFormsPropertiesFactory;
import org.bonitasoft.forms.server.accessor.IApplicationFormDefAccessor;
import org.bonitasoft.forms.server.accessor.impl.util.XPathUtil;
import org.bonitasoft.forms.server.accessor.widget.WidgetBuilderFactory;
import org.bonitasoft.forms.server.accessor.widget.impl.XMLExpressionsUtil;
import org.bonitasoft.forms.server.constants.XMLForms;
import org.bonitasoft.forms.server.exception.ApplicationFormDefinitionNotFoundException;
import org.bonitasoft.forms.server.exception.InvalidFormDefinitionException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Implementation of {@link IApplicationFormDefAccessor} allowing to parse the xml form definition file to get the application
* config
*
* @author Anthony Birembaut, Haojie Yuan
*
*/
public class XMLApplicationFormDefAccessorImpl extends XPathUtil implements IApplicationFormDefAccessor {
/**
* Logger
*/
private static Logger LOGGER = Logger.getLogger(XMLApplicationFormDefAccessorImpl.class.getName());
/**
* DOM representation of the XML file
*/
private final Document document;
/**
* The xpath query to get the process node
*/
protected String applicationXpath;
/**
* the user locale
*/
protected String locale;
/**
* the {@link Date} of the process deployment
*/
protected Date applicationDeploymentDate;
/**
* The form node
*/
protected Node formNode;
/**
* The form id
*/
protected String formId;
/**
* indicate if the form is an entry form (true) or a view form (false)
*/
protected boolean isEditMode;
/**
* The tenant ID
*/
protected long tenantID;
/**
* Util class to parse expressions
*/
protected XMLExpressionsUtil xmlExpressionsUtil;
/**
*
* Default constructor.
*
* @param tenantID
* @param document
* @param formId
* @param applicationDeploymentDate
* @throws ApplicationFormDefinitionNotFoundException
*/
public XMLApplicationFormDefAccessorImpl(final long tenantID, final Document document, final String formId, final String locale,
final Date applicationDeploymentDate) throws ApplicationFormDefinitionNotFoundException {
this.tenantID = tenantID;
this.document = document;
this.applicationDeploymentDate = applicationDeploymentDate;
this.locale = locale;
xmlExpressionsUtil = XMLExpressionsUtil.getInstance();
final StringBuilder applicationXpathBuilder = new StringBuilder();
applicationXpathBuilder.append("//");
applicationXpathBuilder.append(XMLForms.APPLICATION);
applicationXpath = applicationXpathBuilder.toString();
formNode = getFormNode(formId);
String formType = null;
if (formNode != null) {
formType = getStringByXpath(formNode, XMLForms.FORM_TYPE);
}
if (FormType.entry.name().equals(formType)) {
isEditMode = true;
} else {
isEditMode = false;
}
if (formNode == null) {
final String message = "The node for the form " + formId + " was not found in the forms definition file";
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, message);
}
throw new ApplicationFormDefinitionNotFoundException(message);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<String> getPages() {
final List<String> pages = new ArrayList<String>();
final Node applicationNode = getNodeByXpath(document, applicationXpath);
if (applicationNode == null) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Failed to parse the forms definition file. query : " + applicationXpath);
}
} else {
final NodeList pageNodes = getNodeListByXpath(formNode, XMLForms.PAGES + "/" + XMLForms.PAGE);
if (pageNodes != null) {
for (int i = 0; i < pageNodes.getLength(); i++) {
final String id = getStringByXpath(pageNodes.item(i), "@" + XMLForms.ID);
pages.add(unescapeSingleQuote(id));
}
}
}
return pages;
}
/**
* {@inheritDoc}
*/
@Override
public Expression getFirstPageExpression() throws InvalidFormDefinitionException {
Expression formFirstPage = null;
final Node formFirstPageNode = getNodeByXpath(formNode, XMLForms.FIRST_PAGE);
if (formFirstPageNode != null) {
formFirstPage = xmlExpressionsUtil.parseExpression(formFirstPageNode);
}
return formFirstPage;
}
/**
* {@inheritDoc}
*/
@Override
public String getFormPermissions() throws InvalidFormDefinitionException {
String permissions = null;
final Node permissionsNode = getNodeByXpath(formNode, XMLForms.PERMISSIONS);
if (permissionsNode == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Failed to retrieve form permissions. Default permissions will be used.");
}
} else {
permissions = permissionsNode.getTextContent();
}
return permissions;
}
/**
* {@inheritDoc}
*/
@Override
public String getNextForm() throws InvalidFormDefinitionException {
String nextForm = null;
final Node nextFormNode = getNodeByXpath(formNode, XMLForms.NEXT_FORM);
if (nextFormNode == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "No next form is specified for form " + formId);
}
} else {
nextForm = nextFormNode.getTextContent();
}
return nextForm;
}
/**
* {@inheritDoc}
*/
@Override
public String getFormPageLayout(final String pageId) throws InvalidFormDefinitionException {
String templatePath = null;
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
final Node pageTemplateNode = getNodeByXpath(pageNode, XMLForms.PAGE_LAYOUT);
if (pageTemplateNode == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Failed to parse the form definition file. The default page template will be used.");
}
templatePath = null;
} else {
templatePath = pageTemplateNode.getTextContent();
}
}
return templatePath;
}
/**
* Retrieve the page node for a given page id
*
* @param pageId
* @return the {@link Node} for the page
*/
protected Node getPageNode(final String pageId) {
final String xpath = getPageXpath(escapeSingleQuote(pageId));
return getNodeByXpath(formNode, xpath);
}
/**
* Build the xpath query to get a application page
*
* @param pageId
* @return an xpath query under the form of a String
*/
protected String getPageXpath(final String pageId) {
final StringBuilder pageXpathBuilder = new StringBuilder();
pageXpathBuilder.append(XMLForms.PAGES);
pageXpathBuilder.append("/");
pageXpathBuilder.append(XMLForms.PAGE);
pageXpathBuilder.append("[@");
pageXpathBuilder.append(XMLForms.ID);
pageXpathBuilder.append("='");
pageXpathBuilder.append(pageId);
pageXpathBuilder.append("']");
return pageXpathBuilder.toString();
}
/**
* Retrieve the page node for a given page id
*
* @param formId
* the formId
* @return the {@link Node} for the page
*/
protected Node getFormNode(final String formId) {
final String xpath = getFormPageXpath(escapeSingleQuote(formId));
return getNodeByXpath(document, xpath);
}
/**
* Build the xpath query to get a application page
*
* @param formId
* the formId
* @return an xpath query under the form of a String
*/
protected String getFormPageXpath(final String formId) {
final StringBuilder pageXpathBuilder = new StringBuilder();
pageXpathBuilder.append(applicationXpath);
pageXpathBuilder.append("/");
pageXpathBuilder.append(XMLForms.FORMS);
pageXpathBuilder.append("/");
pageXpathBuilder.append(XMLForms.FORM);
pageXpathBuilder.append("[@");
pageXpathBuilder.append(XMLForms.ID);
pageXpathBuilder.append("='");
pageXpathBuilder.append(formId);
pageXpathBuilder.append("']");
return pageXpathBuilder.toString();
}
/**
* {@inheritDoc}
*/
@Override
public List<FormWidget> getPageWidgets(final String pageId) throws InvalidFormDefinitionException, ApplicationFormDefinitionNotFoundException {
List<FormWidget> widgets = new ArrayList<FormWidget>();
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
widgets = WidgetBuilderFactory.getXMLWidgetBuilder().getPageWidgets(pageNode, isEditMode);
}
return widgets;
}
/**
* {@inheritDoc}
*/
@Override
public List<FormValidator> getPageValidators(final String pageId) throws InvalidFormDefinitionException, ApplicationFormDefinitionNotFoundException {
List<FormValidator> pageValidators = new ArrayList<FormValidator>();
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
pageValidators = WidgetBuilderFactory.getXMLWidgetBuilder().getPageValidators(pageNode);
}
return pageValidators;
}
/**
* {@inheritDoc}
*/
@Override
public Expression getPageLabelExpression(final String pageId) throws InvalidFormDefinitionException {
Expression label = null;
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
final Node pageLabelNode = getNodeByXpath(pageNode, XMLForms.PAGE_LABEL);
if (pageLabelNode == null) {
final String errorMessage = "The label for page " + pageId + " for process instantiation was not found in the forms definition file";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
label = xmlExpressionsUtil.parseExpression(pageId, pageLabelNode);
}
}
return label;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isHTMLAllowedInLabel(final String pageId) throws InvalidFormDefinitionException {
boolean allowHTMLInLabel = false;
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
final Node pageAllowHTMLNode = getNodeByXpath(pageNode, XMLForms.ALLOW_HTML_IN_LABEL);
if (pageAllowHTMLNode != null) {
final String allowHTMLInLabelStr = pageAllowHTMLNode.getTextContent();
allowHTMLInLabel = Boolean.parseBoolean(allowHTMLInLabelStr);
}
}
return allowHTMLInLabel;
}
/**
* {@inheritDoc}
*/
@Override
public Expression getNextPageExpression(final String pageId) throws InvalidFormDefinitionException {
Expression nextPageExpression = null;
final Node pageNode = getPageNode(pageId);
if (pageNode == null) {
final String errorMessage = "Failed to parse the forms definition file. Page " + pageId + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
final Node nextPageNode = getNodeByXpath(pageNode, XMLForms.NEXT_PAGE);
if (nextPageNode != null) {
nextPageExpression = xmlExpressionsUtil.parseExpression(nextPageNode);
}
}
return nextPageExpression;
}
/**
* {@inheritDoc}
*/
@Override
public List<TransientData> getTransientData() throws InvalidFormDefinitionException {
final List<TransientData> transientData = new ArrayList<TransientData>();
final NodeList dataNodes = getNodeListByXpath(formNode, XMLForms.TRANSIENT_DATA + "/" + XMLForms.DATA);
if (dataNodes != null) {
for (int i = 0; i < dataNodes.getLength(); i++) {
final Node dataNode = dataNodes.item(i);
final String name = getStringByXpath(dataNode, "@" + XMLForms.NAME);
if (name == null || name.trim().length() == 0) {
final String errorMessage = "Failed to parse the forms definition file for the application " + applicationXpath
+ ". name for transient data missing.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
}
final Node classNameNode = getNodeByXpath(dataNode, XMLForms.CLASSNAME);
String className = null;
if (classNameNode != null) {
className = classNameNode.getTextContent();
}
if (className == null || className.trim().length() == 0) {
final String errorMessage = "Failed to parse the forms definition file for the applicationXpath " + applicationXpath
+ ". classname for transient data " + name + " not found.";
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
}
final Node valueNode = getNodeByXpath(dataNode, XMLForms.VALUE);
Expression value = null;
if (valueNode != null) {
value = xmlExpressionsUtil.parseExpression(name, valueNode);
}
transientData.add(new TransientData(name, className, value));
}
}
return transientData;
}
/**
* {@inheritDoc}
*/
@Override
public List<FormAction> getActions(final String pageId) throws InvalidFormDefinitionException, ApplicationFormDefinitionNotFoundException {
return WidgetBuilderFactory.getXMLWidgetBuilder().getActions(formNode, pageId);
}
/**
* {@inheritDoc}
*/
@Override
public String getConfirmationLayout() throws InvalidFormDefinitionException {
String path = null;
final Node confirmationTemplateNode = getNodeByXpath(formNode, XMLForms.CONFIRMATION_LAYOUT);
if (confirmationTemplateNode == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "No confirmation template was found. The default confirmation page will be used.");
}
path = DefaultFormsPropertiesFactory.getDefaultFormProperties(tenantID).getPageConfirmationTemplate();
} else {
path = confirmationTemplateNode.getTextContent();
}
return path;
}
/**
* {@inheritDoc}
*/
@Override
public Expression getConfirmationMessageExpression() throws InvalidFormDefinitionException {
Expression message = null;
final Node confirmationMessageNode = getNodeByXpath(formNode, XMLForms.CONFIRMATION_MESSAGE);
if (confirmationMessageNode == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "No confirmation message was found. The default confirmation message will be used.");
}
} else {
message = xmlExpressionsUtil.parseExpression(confirmationMessageNode);
}
return message;
}
/**
* {@inheritDoc}
*/
@Override
public FormType getFormType() throws InvalidFormDefinitionException {
String formType = null;
final Node formTypeNode = getNodeByXpath(formNode, XMLForms.FORM_TYPE);
if (formTypeNode == null) {
final String errorMessage = "No form type is specified for form " + formId;
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, errorMessage);
}
throw new InvalidFormDefinitionException(errorMessage);
} else {
formType = formTypeNode.getTextContent();
}
return FormType.valueOf(formType);
}
}