001/* 002 * Copyright 2021 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.forms.question.types; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Map; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.cocoon.xml.AttributesImpl; 025import org.apache.cocoon.xml.XMLUtils; 026import org.apache.commons.lang.StringUtils; 027import org.xml.sax.ContentHandler; 028import org.xml.sax.SAXException; 029 030import org.ametys.plugins.forms.helper.FormElementDefinitionHelper; 031import org.ametys.plugins.forms.question.computing.ComputingType; 032import org.ametys.plugins.forms.question.computing.ComputingTypeExtensionPoint; 033import org.ametys.plugins.forms.repository.FormEntry; 034import org.ametys.plugins.forms.repository.FormQuestion; 035import org.ametys.runtime.config.DisableCondition; 036import org.ametys.runtime.config.DisableCondition.OPERATOR; 037import org.ametys.runtime.config.DisableConditions; 038import org.ametys.runtime.i18n.I18nizableText; 039import org.ametys.runtime.model.ElementDefinition; 040import org.ametys.runtime.model.ModelItem; 041import org.ametys.runtime.model.SimpleViewItemGroup; 042import org.ametys.runtime.model.StaticEnumerator; 043import org.ametys.runtime.model.ViewElement; 044import org.ametys.runtime.model.ViewItemGroup; 045import org.ametys.runtime.model.type.ModelItemTypeConstants; 046 047/** 048 * Class for creating computed question 049 */ 050public class ComputedQuestionType extends AbstractStaticFormQuestionType implements ConfidentialAwareQuestionType 051{ 052 /** Constant for computing attribute. */ 053 public static final String ATTRIBUTE_COMPUTING_TYPE = "computing-type"; 054 055 /** Constant for default title */ 056 public static final String DEFAULT_TITLE = "PLUGIN_FORMS_QUESTION_DEFAULT_TITLE_COMPUTED"; 057 058 /** The computing type extension point */ 059 private ComputingTypeExtensionPoint _computingTypeExtensionPoint; 060 061 @Override 062 public void service(ServiceManager manager) throws ServiceException 063 { 064 super.service(manager); 065 _computingTypeExtensionPoint = (ComputingTypeExtensionPoint) manager.lookup(ComputingTypeExtensionPoint.ROLE); 066 } 067 068 @Override 069 protected List<ModelItem> _getModelItems() 070 { 071 List<ModelItem> modelItems = super._getModelItems(); 072 073 ElementDefinition<String> computingType = FormElementDefinitionHelper.getElementDefinition(ATTRIBUTE_COMPUTING_TYPE, ModelItemTypeConstants.STRING_TYPE_ID, "PLUGINS_FORMS_QUESTIONS_DIALOG_COMPUTED_COMPUTING_TYPE", "PLUGINS_FORMS_QUESTIONS_DIALOG_COMPUTED_COMPUTING_TYPE_DESC", null); 074 StaticEnumerator<String> typesStaticEnumerator = new StaticEnumerator<>(); 075 for (ComputingType type : _getAllComputingType()) 076 { 077 typesStaticEnumerator.add(type.getLabel(), type.getId()); 078 079 DisableConditions disableConditions = new DisableConditions(); 080 DisableCondition condition = new DisableCondition(ATTRIBUTE_COMPUTING_TYPE, OPERATOR.NEQ, type.getId()); 081 disableConditions.getConditions().add(condition); 082 083 Map<String, ModelItem> typeModelItems = type.getModelItems(); 084 for (ModelItem item : typeModelItems.values()) 085 { 086 item.setDisableConditions(disableConditions); 087 } 088 modelItems.addAll(typeModelItems.values()); 089 } 090 computingType.setEnumerator(typesStaticEnumerator); 091 modelItems.add(computingType); 092 093 modelItems.add(getConfidentialityModelItem()); 094 095 return modelItems; 096 } 097 098 @Override 099 protected List<ViewItemGroup> _getTabs() 100 { 101 return List.of( 102 _getMainTab(), 103 _getAdvancedTab(), 104 _getRulesTab() 105 ); 106 } 107 108 /** 109 * Define the content of the main tab 110 * @return the main tab definition 111 */ 112 protected SimpleViewItemGroup _getMainTab() 113 { 114 SimpleViewItemGroup fieldset = super._createMainTab(); 115 116 ViewElement computingCombobox = new ViewElement(); 117 computingCombobox.setDefinition((ElementDefinition< ? >) getModel().getModelItem(ATTRIBUTE_COMPUTING_TYPE)); 118 fieldset.addViewItem(computingCombobox); 119 120 for (ComputingType type : _getAllComputingType()) 121 { 122 if (!type.getViewElements().isEmpty()) 123 { 124 fieldset.addViewItems(type.getViewElements()); 125 } 126 } 127 128 return fieldset; 129 } 130 131 /** 132 * Define the content of the advanced tab 133 * @return the advanced tab definition 134 */ 135 protected SimpleViewItemGroup _getAdvancedTab() 136 { 137 SimpleViewItemGroup advancedFieldset = super._createAdvancedTab(); 138 139 ViewElement title = new ViewElement(); 140 title.setDefinition((ElementDefinition< ? >) getModel().getModelItem(FormQuestion.ATTRIBUTE_TITLE)); 141 advancedFieldset.addViewItem(title); 142 143 advancedFieldset.addViewItem(getConfidentialityViewElement(getModel())); 144 145 return advancedFieldset; 146 } 147 148 public String getStorageType(FormQuestion question) 149 { 150 ComputingType computingType = getComputingType(question); 151 if (computingType != null) 152 { 153 return computingType.getStorageType(question); 154 } 155 156 // Return string by default but it not supposed to have no computing type 157 return ModelItemTypeConstants.STRING_TYPE_ID; 158 } 159 160 @Override 161 public void saxAdditionalInfos(ContentHandler contentHandler, FormQuestion question) throws SAXException 162 { 163 super.saxAdditionalInfos(contentHandler, question); 164 for (ComputingType type : _getAllComputingType()) 165 { 166 AttributesImpl attr = new AttributesImpl(); 167 String xslEnabled = StringUtils.isBlank(type.getXSLT()) ? "false" : "true"; 168 attr.addCDATAAttribute("xsl-enabled", xslEnabled); 169 attr.addCDATAAttribute("id", type.getId()); 170 XMLUtils.createElement(contentHandler, "computing-type", attr); 171 } 172 } 173 174 /** 175 * Get all computing types 176 * @return a list of {@link ComputingType} 177 */ 178 private List<ComputingType> _getAllComputingType() 179 { 180 List<ComputingType> computingTypes = new ArrayList<>(); 181 for (String id: _computingTypeExtensionPoint.getExtensionsIds()) 182 { 183 computingTypes.add(_computingTypeExtensionPoint.getExtension(id)); 184 } 185 return computingTypes; 186 } 187 188 @Override 189 public boolean isQuestionConfigured(FormQuestion question) 190 { 191 return StringUtils.isNotBlank(question.getValue(ATTRIBUTE_COMPUTING_TYPE)); 192 } 193 194 /** 195 * Get the computing type 196 * @param question the question 197 * @return the computing type 198 */ 199 public ComputingType getComputingType(FormQuestion question) 200 { 201 String value = question.getValue(ATTRIBUTE_COMPUTING_TYPE); 202 return StringUtils.isNotBlank(value) ? _computingTypeExtensionPoint.getExtension(value) : null; 203 } 204 205 @Override 206 public boolean onlyForDisplay(FormQuestion question) 207 { 208 ComputingType computingType = getComputingType(question); 209 if (computingType != null) 210 { 211 return !computingType.hasComputedValue(); 212 } 213 return true; 214 } 215 216 @Override 217 public boolean canBeAnsweredByUser(FormQuestion question) 218 { 219 return false; 220 } 221 222 public I18nizableText getDefaultTitle() 223 { 224 return new I18nizableText("plugin.forms", DEFAULT_TITLE); 225 } 226 227 @Override 228 public void saxEntryValue(ContentHandler contentHandler, FormQuestion question, FormEntry entry) throws SAXException 229 { 230 super.saxEntryValue(contentHandler, question, entry); 231 AttributesImpl attrs = new AttributesImpl(); 232 ComputingType computingType = getComputingType(question); 233 attrs.addCDATAAttribute("computed-type", computingType.getId()); 234 235 XMLUtils.startElement(contentHandler, "additional-infos", attrs); 236 237 computingType.saxAdditionalValue(contentHandler, question, entry); 238 239 XMLUtils.endElement(contentHandler, "additional-infos"); 240 241 } 242 243 @Override 244 public List<String> getFieldToDisableIfFormPublished(FormQuestion question) 245 { 246 List<String> fieldNames = super.getFieldToDisableIfFormPublished(question); 247 fieldNames.add(ATTRIBUTE_COMPUTING_TYPE); 248 249 ComputingType computingType = getComputingType(question); 250 if (computingType != null) 251 { 252 for (String fieldName : computingType.getFieldToDisableIfFormPublished()) 253 { 254 fieldNames.add(fieldName); 255 } 256 } 257 258 fieldNames.add(ConfidentialAwareQuestionType.ATTRIBUTE_CONFIDENTIALITY); 259 260 return fieldNames; 261 } 262 263 @Override 264 public String getJSRenderer(FormQuestion question) 265 { 266 ComputingType computingType = getComputingType(question); 267 return computingType.getJSRenderer(); 268 } 269 270 public Object valueToJSONForClient(Object value, FormQuestion question, FormEntry entry, ModelItem modelItem) throws Exception 271 { 272 Object valueToJSONForClient = super.valueToJSONForClient(value, question, entry, modelItem); 273 ComputingType computingType = getComputingType(question); 274 return computingType.valueToJSONForClient(valueToJSONForClient, question, entry, modelItem); 275 } 276}