Skip to content

Commit c76bc8f

Browse files
committed
minor form updates (Issue #35)
1 parent f3457a0 commit c76bc8f

8 files changed

Lines changed: 258 additions & 56 deletions

File tree

src/main/java/org/imixs/application/model/ModelController.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.imixs.workflow.engine.ModelService;
4949
import org.imixs.workflow.engine.WorkflowService;
5050
import org.imixs.workflow.exceptions.AccessDeniedException;
51+
import org.imixs.workflow.exceptions.InvalidAccessException;
5152
import org.imixs.workflow.exceptions.ModelException;
5253
import org.imixs.workflow.exceptions.PluginException;
5354
import org.imixs.workflow.faces.fileupload.FileUploadController;
@@ -123,8 +124,8 @@ public List<String> getGroups(String version) {
123124
Set<String> groups = modelManager.findAllGroupsByModel(model);
124125
// Convert the Set to a List
125126
return new ArrayList<>(groups);
126-
} catch (ModelException e) {
127-
logger.warning("Unable to load groups:" + e.getMessage());
127+
} catch (ModelException | InvalidAccessException e) {
128+
logger.severe("Unable to load groups:" + e.getMessage());
128129
}
129130
// return empty result
130131
return new ArrayList<String>();
@@ -154,8 +155,13 @@ public List<String> getWorkflowGroups() throws ModelException {
154155
* @return
155156
* @throws ModelException
156157
*/
157-
public String getVersionByGroup(String group) throws ModelException {
158-
return modelService.findVersionByGroup(group);
158+
public String getVersionByGroup(String group) {
159+
try {
160+
return modelService.findVersionByGroup(group);
161+
} catch (ModelException e) {
162+
logger.severe(e.getMessage());
163+
}
164+
return null;
159165
}
160166

161167
/**
@@ -174,7 +180,7 @@ public List<ItemCollection> findAllTasksByGroup(String group) {
174180
BPMNModel model = modelManager.getModel(version);
175181
result = modelManager.findTasks(model, group);
176182
} catch (ModelException e) {
177-
logger.warning("Failed to call findAllTasksByGroup for '" + group + "'");
183+
logger.severe("Failed to call findAllTasksByGroup for '" + group + "'");
178184
}
179185

180186
return result;
@@ -231,8 +237,14 @@ public List<String> getVersions() {
231237
* @return
232238
* @throws ModelException
233239
*/
234-
public ItemCollection getModelEntity(String version) throws ModelException {
235-
return modelService.loadModelMetaData(version);
240+
public ItemCollection getModelEntity(String version) {
241+
try {
242+
return modelService.loadModelMetaData(version);
243+
} catch (ModelException e) {
244+
logger.severe(
245+
"Failed to find model version '" + version + "' : " + e.getMessage());
246+
}
247+
return null;
236248
}
237249

238250
/**
@@ -272,7 +284,7 @@ public void doUploadModel(ActionEvent event)
272284
model = BPMNModelFactory.read(inputStream);
273285
modelService.saveModel(model);
274286
continue;
275-
} catch (BPMNModelException e) {
287+
} catch (BPMNModelException | InvalidAccessException e) {
276288
throw new ModelException(ModelException.INVALID_MODEL,
277289
"Unable to read model file: " + file.getName(), e);
278290
}
@@ -311,7 +323,7 @@ public ItemCollection getProcessEntity(int processid, String modelversion) {
311323
try {
312324
BPMNModel model = modelManager.getModel(modelversion);
313325
return modelManager.findTaskByID(model, processid);
314-
} catch (ModelException e) {
326+
} catch (ModelException | InvalidAccessException e) {
315327
logger.warning("Unable to load task " + processid + " in model version '" + modelversion + "' - "
316328
+ e.getMessage());
317329
}
@@ -332,7 +344,7 @@ public String getProcessDescription(int processid, String modelversion, ItemColl
332344
try {
333345
BPMNModel model = modelManager.getModel(modelversion);
334346
pe = modelManager.findTaskByID(model, processid);
335-
} catch (ModelException e1) {
347+
} catch (ModelException | InvalidAccessException e1) {
336348
logger.warning("Unable to load task " + processid + " in model version '" + modelversion + "' - "
337349
+ e1.getMessage());
338350
}

src/main/java/org/imixs/application/ui/form/CustomFormController.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public class CustomFormController implements Serializable {
9797
private ModelManager modelManager = null;
9898
private List<CustomFormSection> sections;
9999
private String supportedExpressions = "";
100+
private String errorMessage = "";
100101

101102
@Inject
102103
WorkflowService workflowService;
@@ -121,6 +122,14 @@ public List<CustomFormSection> getSections() {
121122
return sections;
122123
}
123124

125+
public String getErrorMessage() {
126+
return errorMessage;
127+
}
128+
129+
public void setErrorMessage(String error) {
130+
this.errorMessage = error;
131+
}
132+
124133
/**
125134
* WorkflowEvent listener to update the current FormDefinition.
126135
*
@@ -200,7 +209,10 @@ public void computeFieldDefinition(ItemCollection workitem) throws ModelExceptio
200209
sections = parseSectionList(rootElement, false, workitem);
201210
}
202211
} catch (ParserConfigurationException | SAXException | IOException e) {
203-
logger.warning("Unable to parse custom form definition: " + e.getMessage());
212+
errorMessage = "Invalid form definition! - Model=" + workitem.getModelVersion()
213+
+ " TaskID=" + workitem.getTaskID() + " Error="
214+
+ e.getMessage();
215+
logger.warning(errorMessage);
204216
return;
205217
}
206218

@@ -209,8 +221,8 @@ public void computeFieldDefinition(ItemCollection workitem) throws ModelExceptio
209221
}
210222

211223
/**
212-
* This method overwrite the 'readOnly' status flag for all sections.
213-
* Note: sections can be embedded in optional subForms.
224+
* This method overwrite the 'readOnly' status flag for all sections. Note:
225+
* sections can be embedded in optional subForms.
214226
*
215227
* @param readOnly
216228
*/
@@ -238,8 +250,8 @@ public void setReadOnly(boolean readOnly) {
238250
}
239251

240252
/**
241-
* This helper method pareses a parent-node for 'imixs-form-section'
242-
* tags and returns a list of CustomFormSections
253+
* This helper method pareses a parent-node for 'imixs-form-section' tags and
254+
* returns a list of CustomFormSections
243255
*
244256
* @param parentNode - the parent node to be parsed
245257
* @param readOnly - if true, all items will become readonly independent from
@@ -272,7 +284,8 @@ private List<CustomFormSection> parseSectionList(Element parentNode, boolean rea
272284
eSectionElement.getAttribute("label"),
273285
eSectionElement.getAttribute("columns"),
274286
eSectionElement.getAttribute("path"),
275-
defaultReadOnly);
287+
defaultReadOnly,
288+
eSectionElement.getAttribute("options"));
276289
customSection.setItems(findItems(eSectionElement,
277290
customSection.getColumns(), defaultReadOnly, workitem));
278291
result.add(customSection);
@@ -428,7 +441,7 @@ private boolean evaluateBoolean(String expression) throws ModelException {
428441
} else {
429442
throw new ModelException(ModelException.INVALID_MODEL_ENTRY,
430443
"The custom-form expression is not allowed: "
431-
+ expression);
444+
+ expression + " - expression missing in 'customform.expressions' ");
432445
}
433446

434447
} else {
@@ -484,8 +497,8 @@ private InputStream getFileFromResourceAsStream(String fileName) {
484497
/**
485498
* This method updates the custom Field Definition based on a given workitem.
486499
* The method first looks if the task associated with the workitem contains a
487-
* bpmn:DataObject containing a custom definition.
488-
* The result is stored into the item <code>txtWorkflowEditorCustomForm</code>.
500+
* bpmn:DataObject containing a custom definition. The result is stored into the
501+
* item <code>txtWorkflowEditorCustomForm</code>.
489502
* <p>
490503
* In case the model does not provide a custom Field Definition but the workitem
491504
* has stored one the method returns the existing one and did not update the
@@ -508,25 +521,28 @@ public String updateCustomFieldDefinition(ItemCollection workitem)
508521

509522
/**
510523
* Helper method that reads a form definition from an optional
511-
* <code>bpmn:DataObject</code> associated with the current task element.
512-
* A <code>bpmn:DataObject</code> must contain a `form-tag` containing the form
513-
* definition.
514-
* If not matching <code>bpmn:DataObject</code> is defined the method returns an
515-
* empty
516-
* string.
524+
* <code>bpmn:DataObject</code> associated with the current task element. A
525+
* <code>bpmn:DataObject</code> must contain a `form-tag` containing the form
526+
* definition. If not matching <code>bpmn:DataObject</code> is defined the
527+
* method returns an empty string.
517528
*
518529
* @param workitem
519530
* @return
520531
*/
521532
@SuppressWarnings("unchecked")
522533
private String fetchFormDefinitionFromModel(ItemCollection workitem) {
534+
535+
// return if no modelversion is defined
536+
if (workitem == null || workitem.getModelVersion().isBlank()) {
537+
return "";
538+
}
523539
ItemCollection task;
524540
try {
525541
BPMNModel model = modelManager.getModelByWorkitem(workitem);
526542
task = modelManager.loadTask(workitem, model);
527543

528544
} catch (ModelException e) {
529-
logger.warning("unable to parse data object in model: " + e.getMessage());
545+
logger.fine("unable to parse data object in model: " + e.getMessage());
530546
return "";
531547
}
532548

src/main/java/org/imixs/application/ui/form/CustomFormSection.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ public class CustomFormSection {
4242
String label;
4343
String columns;
4444
String path;
45+
String options;
4546
boolean readonly;
4647
List<CustomFormItem> items;
4748

48-
public CustomFormSection(String label, String columns, String path, boolean readonly) {
49+
public CustomFormSection(String label, String columns, String path, boolean readonly, String options) {
4950
super();
5051
this.label = label;
5152
this.readonly = readonly;
5253
this.columns = columns;
54+
this.options = options;
5355
if (path != null) {
5456
this.path = path.trim();
5557
}
@@ -95,4 +97,12 @@ public void setReadonly(boolean readonly) {
9597
this.readonly = readonly;
9698
}
9799

100+
public String getOptions() {
101+
return options;
102+
}
103+
104+
public void setOptions(String options) {
105+
this.options = options;
106+
}
107+
98108
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.imixs.application.ui.form;
2+
3+
import java.io.Serializable;
4+
import java.text.DateFormat;
5+
import java.text.ParseException;
6+
import java.text.SimpleDateFormat;
7+
import java.util.Date;
8+
import java.util.MissingResourceException;
9+
import java.util.ResourceBundle;
10+
import java.util.TimeZone;
11+
12+
import jakarta.faces.component.UIComponent;
13+
import jakarta.faces.context.FacesContext;
14+
import jakarta.faces.convert.Converter;
15+
import jakarta.faces.convert.FacesConverter;
16+
17+
/**
18+
* HTML5 Date Converter
19+
*/
20+
@SuppressWarnings("rawtypes")
21+
@FacesConverter("imixsHTML5DateConverter")
22+
public class HTML5DateConverter implements Converter, Serializable {
23+
24+
private static final String HTML5_DATE_FORMAT_PATTERN = "yyyy-MM-dd";
25+
private static final String DEFAULT_TIME_ZONE = "UTC"; // Set the timezone to CET
26+
27+
@Override
28+
public Object getAsObject(FacesContext context, UIComponent component, String value) {
29+
30+
if (value == null || value.trim().isEmpty()) {
31+
return ""; // Convert null to empty string
32+
}
33+
34+
try {
35+
value = value.trim();
36+
String pattern = HTML5_DATE_FORMAT_PATTERN;
37+
38+
String timezone = (String) component.getAttributes().get("org.imixs.date.timeZone");
39+
if (timezone == null || timezone.isEmpty()) {
40+
timezone = getTimeZoneFromBundle(context);
41+
}
42+
DateFormat dateFormat = new SimpleDateFormat(pattern);
43+
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
44+
return dateFormat.parse(value);
45+
} catch (ParseException e) {
46+
throw new RuntimeException("Error converting date", e);
47+
}
48+
}
49+
50+
@Override
51+
public String getAsString(FacesContext context, UIComponent component, Object value) {
52+
if (value == null || "".equals(value)) {
53+
return ""; // Convert null to empty string
54+
}
55+
56+
if (value instanceof Date) {
57+
String pattern = HTML5_DATE_FORMAT_PATTERN;
58+
String timezone = (String) component.getAttributes().get("org.imixs.date.timeZone");
59+
if (timezone == null || timezone.isEmpty()) {
60+
timezone = getTimeZoneFromBundle(context);
61+
}
62+
63+
DateFormat dateFormat = new SimpleDateFormat(pattern);
64+
dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
65+
return dateFormat.format((Date) value);
66+
}
67+
return value.toString();
68+
}
69+
70+
private String getTimeZoneFromBundle(FacesContext context) {
71+
// Load the timezone from the message bundle
72+
ResourceBundle bundle = context.getApplication()
73+
.getResourceBundle(context, "message");
74+
75+
try {
76+
return bundle.getString("timeZone");
77+
} catch (MissingResourceException e) {
78+
return DEFAULT_TIME_ZONE; // fallback to UTC
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)