/* * Copyright 2011 JBoss Inc * * 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.jbpm.formbuilder.client; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jbpm.formapi.client.effect.FBFormEffect; import org.jbpm.formapi.client.menu.FBMenuItem; import org.jbpm.formapi.client.validation.FBValidationItem; import org.jbpm.formapi.common.reflect.ReflectionHelper; import org.jbpm.formapi.shared.api.FormItemRepresentation; import org.jbpm.formapi.shared.api.FormRepresentation; import org.jbpm.formapi.shared.form.FormEncodingException; import org.jbpm.formapi.shared.form.FormEncodingFactory; import org.jbpm.formapi.shared.form.FormRepresentationDecoder; import org.jbpm.formapi.shared.form.FormRepresentationEncoder; import org.jbpm.formbuilder.client.command.BaseCommand; import org.jbpm.formbuilder.client.menu.items.CustomMenuItem; import org.jbpm.formbuilder.client.menu.items.ErrorMenuItem; import org.jbpm.formbuilder.client.messages.I18NConstants; import org.jbpm.formbuilder.client.options.MainMenuOption; import org.jbpm.formbuilder.client.validation.OtherValidationsAware; import org.jbpm.formbuilder.shared.task.TaskPropertyRef; import org.jbpm.formbuilder.shared.task.TaskRef; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Element; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.XMLParser; /** * This class is to help {@link FormBuilderModel} to parse response messages * and transform request bodies. */ public class XmlParseHelper { private final I18NConstants i18n = FormBuilderGlobals.getInstance().getI18n(); /** * Method to output xml from a form item and is name with the following format: * <code> * <formItem name="${formItemName}"><br> *   <content>${formItem.asJson()}</content><br> * </formItem><br> * </code> * * @param formItemName name of the form item * @param formItem the form item to format * @return XML request body */ public String asXml(String formItemName, FormItemRepresentation formItem) throws FormEncodingException { StringBuilder builder = new StringBuilder(); String json = FormEncodingFactory.getEncoder().encode(formItem); builder.append("<formItem name=\"").append(formItemName).append("\">"); builder.append("<content><![CDATA[").append(json).append("]]></content>"); builder.append("</formItem>"); return builder.toString(); } /** * Method to output xml from a menu item and its group's name with the following format: * <code> * <menuItem><br> *   <groupName>${groupName}</groupName><br> *   <name>${item.description.text}</name><br> *   <clone><![CDATA[${item.asJson()}]]></clone><br> *   <effect>${item.formEffects[0].class.name}</effect><br> *   <effect>${item.formEffects[1].class.name}</effect><br> *   ...<br> *   <effect>${item.formEffects[n].class.name}</effect><br> * </menuItem><br> * </code> * * @param groupName the menu item group's name * @param item the menu item * @return XML request body */ public String asXml(String groupName, FBMenuItem item) { StringBuilder builder = new StringBuilder(); builder.append("<menuItem>"); builder.append("<groupName>").append(groupName).append("</groupName>"); builder.append("<name>").append(item.getDescription().getText()).append("</name>"); try { String json = FormEncodingFactory.getEncoder().encode(item.buildWidget().getRepresentation()); String jsonTag = new StringBuilder("<clone><![CDATA[").append(json).append("]]></clone>").toString(); builder.append(jsonTag); } catch (FormEncodingException e) { builder.append("<clone error=\"true\">Exception:").append(e.getMessage()).append("</clone>"); } for (String key : item.getAllowedEvents()) { builder.append("<allowedEvent>").append(key).append("</allowedEvent>"); } for (FBFormEffect effect : item.getFormEffects()) { builder.append("<effect className=\"").append(effect.getClass().getName()).append("\" />"); } builder.append("</menuItem>"); return builder.toString(); } /** * Ment to parse an XML response with the following format: * <code> * <tasks><br> *   <task processId="${task.processId}" taskName="${task.taskId}"><br> * <br> *     <input name="${task.inputs[0].name}" source="${task.inputs[0].sourceExpression}"/><br> *     <input name="${task.inputs[1].name}" source="${task.inputs[1].sourceExpression}"/><br> *     ...<br> *     <input name="${task.inputs[n].name}" source="${task.inputs[n].sourceExpression}"/><br> * <br> *     <output name="${task.outputs[0].name}" source="${task.outputs[0].sourceExpression}"/><br> *     <output name="${task.outputs[1].name}" source="${task.outputs[1].sourceExpression}"/><br> *     ...<br> *     <output name="${task.outputs[n].name}" source="${task.outputs[n].sourceExpression}"/><br> * <br> *     <metaData key="${task.metaData.entrySet[0].key}" value="${task.metaData.entrySet[0].value}"/><br> *     <metaData key="${task.metaData.entrySet[1].key}" value="${task.metaData.entrySet[1].value}"/><br> *     ...<br> *     <metaData key="${task.metaData.entrySet[n].key}" value="${task.metaData.entrySet[n].value}"/><br> * <br> *   </task><br> *   ...<br> * </tasks><br> * </code> * * @param responseText The XML response. * @return a list of task definition references. */ public List<TaskRef> readTasks(String responseText) { Document xml = XMLParser.parse(responseText); List<TaskRef> retval = null; NodeList list = xml.getElementsByTagName("task"); if (list != null) { retval = new ArrayList<TaskRef>(list.getLength()); for (int index = 0; index < list.getLength(); index++) { Element elem = (Element) list.item(index); TaskRef ref = new TaskRef(); ref.setProcessId(elem.getAttribute("processId")); ref.setTaskId(elem.getAttribute("taskName")); ref.setInputs(extractTaskIO(elem.getElementsByTagName("input"))); ref.setOutputs(extractTaskIO(elem.getElementsByTagName("output"))); NodeList mdList = elem.getElementsByTagName("metaData"); if (mdList != null) { Map<String, String> metaData = new HashMap<String, String>(); for (int i = 0; i < mdList.getLength(); i++) { Element mdElem = (Element) mdList.item(i); metaData.put(mdElem.getAttribute("key"), mdElem.getAttribute("value")); } ref.setMetaData(metaData); } retval.add(ref); } } return retval; } /** * Ment to parse an XML response with the following format: * <code> * <menuOptions><br> *   <menuOption name="${option[0].html}" (commandClass="${option[0].command.class.name}")><br> *     <menuOption name="${option[0].subMenu[0].html}" commandClass="${option[0].subMenu[0].command.class.name}"/><br> *     ...<br> *     <menuOption name="${option[0].subMenu[n].html}" (commandClass="${option[0].subMenu[n].command.class.name}")><br> *       <menuOption name="${option[0].subMenu[n].subMenu[0].html}" commandClass="${option[0].subMenu[n].subMenu[0].command.class.name}"/><br> *     </menuOption><br> *   </menuOption><br> *   ...<br> *   <menuOption name="${option[m].html}" commandClass="${option[m].command.class.name}"/><br> * </menuOptions><br> * </code> * * @param responseText The XML response. * @return a list of menuOptions. */ public List<MainMenuOption> readMenuOptions(String responseText) { Document xml = XMLParser.parse(responseText); NodeList menuOptions = xml.getElementsByTagName("menuOptions").item(0).getChildNodes(); return readMenuOptions(menuOptions); } /** * Ment to parse an XML response with the following format: * <code> * <listForms><br> *   <form><json>${jsonFromFormRepresentation}</json></form><br> * </listForms><br> * </code> * * @param responseText the XML response. * @return a list of FormRepresentation items. */ public List<FormRepresentation> readForms(String responseText) { Document xml = XMLParser.parse(responseText); NodeList list = xml.getElementsByTagName("json"); List<FormRepresentation> retval = new ArrayList<FormRepresentation>(); FormRepresentationDecoder decoder = FormEncodingFactory.getDecoder(); if (list != null) { for (int index = 0; index < list.getLength(); index++) { Node node = list.item(index); String json = getText(node); try { FormRepresentation form = decoder.decode(json); retval.add(form); } catch (FormEncodingException e) { FormRepresentation error = new FormRepresentation(); error.setName(i18n.Error(e.getLocalizedMessage())); retval.add(error); } } } return retval; } /** * Ment to parse an XML response with the following format: * <code> * <menuGroups><br> *   <menuGroup name="???"><br> *     <menuItem className="???" optionName="???"><br> *       <itemJson>???</itemJson><br> *       <effect className="???"/><br> *     </menuItem><br> *     ...<br> *     <menuItem ...><br> *       ...<br> *     </menuItem><br> *   </menuGroup><br> *   ...<br> *   <menuGroup name="???"><br> *     ...<br> *   </menuGroup><br> * </menuGroups><br> * </code> * * @param responseText the XML response. * @return a map of lists of FBMenuItem instances. */ public Map<String, List<FBMenuItem>> readMenuMap(String responseText) { Document xml = XMLParser.parse(responseText); Map<String, List<FBMenuItem>> menuItems = new HashMap<String, List<FBMenuItem>>(); NodeList groups = xml.getElementsByTagName("menuGroup"); for (int index = 0; index < groups.getLength(); index++) { Node groupNode = groups.item(index); String groupName = ((Element) groupNode).getAttribute("name"); NodeList items = ((Element) groupNode).getElementsByTagName("menuItem"); menuItems.put(groupName, readMenuItems(items, groupName)); } return menuItems; } /** * Parses and returns a formId from an XML response of the following format: * <code><formId>${response}</formId></code> * * @param responseText XML response to parse * @return a formId */ public String getFormItemId(String responseText) { return textOfFirstNode(responseText, "formItemId"); } /** * Parses and returns a formItemId from an XML response of the following format: * <code><formItemId>${response}</formItemId></code> * * @param responseText XML response to parse * @return a formItemId */ public String getFormId(String responseText) { return textOfFirstNode(responseText, "formId"); } /** * Parses and returns a file name from an XML response of the following format: * <code><fileName>${response}</fileName></code> * * @param responseText XML response to parse * @return a file name on the server */ public String getFileName(String responseText) { return textOfFirstNode(responseText, "fileName"); } /** * Parses and returns a map of strings with string keys from an XML response of the * following format: * * <code> * <properties><br> *   <property key="${key[0]}" value="${value[0]}"/><br> *   <property key="${key[1]}" value="${value[1]}"/><br> *   ...<br> *   <property key="${key[n]}" value="${value[n]}"/><br> * </properties><br> * </code> * @param responseText XML response to parse * @return a map of the string values indexed by property name */ public Map<String, String> readPropertyMap(String responseText) { Document xml = XMLParser.parse(responseText); Map<String, String> retval = new HashMap<String, String>(); NodeList list = xml.getElementsByTagName("property"); for (int index = 0; index < list.getLength(); index++) { Element propElement = (Element) list.item(index); String key = propElement.getAttribute("key"); String value = propElement.getAttribute("value"); retval.put(key, value); } return retval; } /** * Method to output xml from a form preview and its group of test input variables with the following format: * <code> * <formPreview><br> *   <representation>${form.toJson()}</representation><br> *   <input key="${inputs[0].key}" value="${inputs[0].value}"/><br> *   <input key="${inputs[1].key}" value="${inputs[1].value}"/><br> *   ...<br> *   <input key="${inputs[n].key}" value="${inputs[n].value}"/><br> * </formPreview><br> * </code> * * @param form the form representation to transform on server side to a given language * @param inputs the data inputs of the form representation to test it * @return XML request body * @throws FormEncodingException in case of error parsing the form representation */ public String asXml(FormRepresentation form, Map<String, Object> inputs) throws FormEncodingException { StringBuilder builder = new StringBuilder(); builder.append("<formPreview>"); FormRepresentationEncoder encoder = FormEncodingFactory.getEncoder(); String json = encoder.encode(form); builder.append("<representation><![CDATA[").append(json).append("]]></representation>"); if (inputs != null) { for (Map.Entry<String, Object> entry : inputs.entrySet()) { String key = entry.getKey(); Object obj = entry.getValue(); builder.append("<input key=\"").append(key).append("\" value=\"").append(obj).append("\"/>"); } } builder.append("</formPreview>"); return builder.toString(); } /** * Parses and returns a validation dto list from an XML response of the * following format: * * <code> * <validations><br> *   <validation className="${fbValidationItem[0].class.name}"><br> *     <property key="${key[0]}" value="${value[0]}"/><br> *     <property key="${key[1]}" value="${value[1]}"/><br> *     ...<br> *     <property key="${key[n]}" value="${value[n]}"/><br> *   </validation><br> *   ...<br> *   <validation className="${fbValidationItem[m].class.name}"><br> *     <property key="${key[0]}" value="${value[0]}"/><br> *     <property key="${key[1]}" value="${value[1]}"/><br> *     ...<br> *     <property key="${key[p]}" value="${value[p]}"/><br> *   </validation><br> * </validations><br> * </code> * @param responseText XML response to parse * @return a list of validation items */ public List<FBValidationItem> readValidations(String responseText) throws Exception { Document xml = XMLParser.parse(responseText); NodeList validationList = xml.getElementsByTagName("validation"); List<FBValidationItem> retval = new ArrayList<FBValidationItem>(); for (int index = 0; index < validationList.getLength(); index++) { Element valElement = (Element) validationList.item(index); String klass = valElement.getAttribute("className"); Object obj = ReflectionHelper.newInstance(klass); if (obj instanceof FBValidationItem) { FBValidationItem validItem = (FBValidationItem) obj; validItem.populatePropertiesMap(readValidationMap(valElement.getElementsByTagName("property"))); retval.add(validItem); } } for (FBValidationItem item : retval) { if (item instanceof OtherValidationsAware) { OtherValidationsAware aware = (OtherValidationsAware) item; aware.setExistingValidations(retval); } } return retval; } private Map<String, HasValue<String>> readValidationMap(NodeList properties) { Map<String, HasValue<String>> retval = new HashMap<String, HasValue<String>>(); for (int index = 0; index < properties.getLength(); index++) { Element propElement = (Element) properties.item(index); String key = propElement.getAttribute("key"); final String value = propElement.getAttribute("value"); TextBox text = new TextBox(); text.setValue(value); retval.put(key, text); } return retval; } private List<MainMenuOption> readMenuOptions(NodeList menuOptions) { List<MainMenuOption> options = new ArrayList<MainMenuOption>(); for (int index = 0; index < menuOptions.getLength(); index++) { Node menuNode = menuOptions.item(index); Element menuElement = (Element) menuNode; String name = menuElement.getAttribute("name"); MainMenuOption option = new MainMenuOption(); option.setHtml(name); if (menuElement.hasAttribute("commandClass")) { String className = menuElement.getAttribute("commandClass"); try { Object obj = ReflectionHelper.newInstance(className); if (obj instanceof BaseCommand) { option.setCommand((BaseCommand) obj); } else { option.setHtml(option.getHtml()+ "(" + i18n.NotOfType(className, "BaseCommand") + ")"); option.setEnabled(false); } } catch (Exception e) { option.setHtml(option.getHtml() + i18n.Error(e.getLocalizedMessage())); option.setEnabled(false); } } else { option.setSubMenu(readMenuOptions(menuElement.getChildNodes())); } options.add(option); } return options; } private String textOfFirstNode(String responseText, String tagName) { Document xml = XMLParser.parse(responseText); Node node = xml.getElementsByTagName(tagName).item(0); return getText(node); } private List<TaskPropertyRef> extractTaskIO(NodeList ioList) { List<TaskPropertyRef> retval = null; if (ioList != null) { retval = new ArrayList<TaskPropertyRef>(ioList.getLength()); for (int i = 0; i < ioList.getLength(); i++) { Element inElem = (Element) ioList.item(i); TaskPropertyRef prop = new TaskPropertyRef(); String name = inElem.getAttribute("name"); prop.setName(name); String sourceExpression = inElem.getAttribute("source"); prop.setSourceExpresion(sourceExpression); retval.add(prop); } } return retval; } private List<FBMenuItem> readMenuItems(NodeList items, String groupName) { List<FBMenuItem> menuItems = new ArrayList<FBMenuItem>(); for (int index = 0; index < items.getLength(); index ++) { Node itemNode = items.item(index); String itemClassName = ((Element) itemNode).getAttribute("className"); try { Object obj = ReflectionHelper.newInstance(itemClassName); FBMenuItem menuItem = null; if (obj instanceof CustomMenuItem) { CustomMenuItem customItem = (CustomMenuItem) obj; String optionName = ((Element) itemNode).getAttribute("optionName"); customItem.setRepresentation(makeRepresentation(itemNode)); customItem.setOptionName(optionName); customItem.setGroupName(groupName); menuItem = customItem; } else if (obj instanceof FBMenuItem) { menuItem = (FBMenuItem) obj; } else { throw new Exception(i18n.NotOfType(itemClassName, "FBMenuItem")); } NodeList effects = ((Element) itemNode).getElementsByTagName("effect"); for (FBFormEffect effect : readItemEffects(effects)) { menuItem.addEffect(effect); } NodeList allowedEvents = ((Element) itemNode).getElementsByTagName("allowedEvent"); for (String allowedEventName : readAllowedEvents(allowedEvents)) { menuItem.addAllowedEvent(allowedEventName); } menuItems.add(menuItem); } catch (Exception e) { menuItems.add(new ErrorMenuItem(e.getMessage())); } } return menuItems; } private List<String> readAllowedEvents(NodeList allowedEvents) { List<String> retval = new ArrayList<String>(); for (int index = 0; index < allowedEvents.getLength(); index++) { Node node = allowedEvents.item(index); retval.add(getText(node)); } return retval; } private FormItemRepresentation makeRepresentation(Node itemNode) throws FormEncodingException { NodeList list = ((Element) itemNode).getElementsByTagName("itemJson"); FormItemRepresentation rep = null; if (list.getLength() > 0) { Node node = list.item(0); String json = getText(node); FormRepresentationDecoder decoder = FormEncodingFactory.getDecoder(); rep = (FormItemRepresentation) decoder.decodeItem(json); } return rep; } private String getText(Node node) { NodeList list = node.getChildNodes(); StringBuilder builder = new StringBuilder(); for (int index = 0; index < list.getLength(); index++) { builder.append(list.item(index).getNodeValue()); } return builder.toString(); } private List<FBFormEffect> readItemEffects(NodeList effects) throws Exception { List<FBFormEffect> itemEffects = new ArrayList<FBFormEffect>(); for (int i = 0; i < effects.getLength(); i++) { Node effectNode = effects.item(i); String effectClassName = ((Element) effectNode).getAttribute("className"); Object efobj = ReflectionHelper.newInstance(effectClassName); if (efobj instanceof FBFormEffect) { itemEffects.add((FBFormEffect) efobj); } else { throw new Exception(i18n.NotOfType(effectClassName, "FBFormEffect")); } } return itemEffects; } public List<String> readRoles(String response) { String[] rolesArray = response.split(","); List<String> retval = new ArrayList<String>(rolesArray.length); for (String role : rolesArray) { retval.add(role); } return retval; } /** * Ment to parse an XML response with the following format: * <code> * <files><br> *   <file>${url}</file><br> * </files><br> * </code> * * @param responseText the XML response. * @return a list of Strings representing names of files. */ public List<String> readFiles(String responseText) { Document xml = XMLParser.parse(responseText); NodeList list = xml.getElementsByTagName("file"); List<String> retval = new ArrayList<String>(); if (list != null) { for (int index = 0; index < list.getLength(); index++) { Node node = list.item(index); String url = getText(node); retval.add(url); } } return retval; } }