001/* 002 * Copyright 2014 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.runtime.parameter; 017 018import java.io.InputStream; 019import java.time.ZonedDateTime; 020import java.time.chrono.IsoChronology; 021import java.time.format.DateTimeFormatter; 022import java.time.format.ResolverStyle; 023import java.util.ArrayList; 024import java.util.Collection; 025import java.util.Date; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import org.apache.cocoon.ProcessingException; 031import org.apache.cocoon.xml.AttributesImpl; 032import org.apache.cocoon.xml.XMLUtils; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035import org.xml.sax.ContentHandler; 036import org.xml.sax.SAXException; 037 038import org.ametys.core.util.DateUtils; 039import org.ametys.runtime.i18n.I18nizableText; 040import org.ametys.runtime.model.DefinitionContext; 041import org.ametys.runtime.model.ElementDefinition; 042import org.ametys.runtime.model.DefaultElementDefinition; 043import org.ametys.runtime.model.type.ElementType; 044 045 046/** 047 * This class handles all needed to use typed parameters 048 * @deprecated All of this helper methods are now in the new Parameter API classes 049 */ 050@Deprecated 051public final class ParameterHelper 052{ 053 /** 054 * Enumeration of supported types 055 * @deprecated Use {@link ElementType} 056 */ 057 @Deprecated 058 public static enum ParameterType 059 { 060 /** boolean values */ 061 BOOLEAN, 062 /** string values */ 063 STRING, 064 /** password values */ 065 PASSWORD, 066 /** long values */ 067 LONG, 068 /** double values */ 069 DOUBLE, 070 /** date values */ 071 DATE, 072 /** binary values */ 073 BINARY, 074 /** datasource values */ 075 DATASOURCE 076 } 077 078 /** 079 * The ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30.000+01:00'. 080 */ 081 private static DateTimeFormatter __ISO_OFFSET_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX").withResolverStyle(ResolverStyle.STRICT).withChronology(IsoChronology.INSTANCE); 082 083 // Logger for traces 084 private static Logger _logger = LoggerFactory.getLogger(ParameterHelper.class); 085 086 private ParameterHelper () 087 { 088 // empty 089 } 090 091 /** 092 * Get the ISO date-time formatter that formats or parses a date-time with an offset, such as '2011-12-03T10:15:30.000+01:00'. 093 * This formatter is similar to {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME} but force 3-digits milliseconds. 094 * @return ISO date-time formatter 095 */ 096 public static DateTimeFormatter getISODateTimeFormatter() 097 { 098 return __ISO_OFFSET_DATE_TIME; 099 } 100 101 /** 102 * Return the readable name of a type 103 * 104 * @param type Type to convert 105 * @return Returns the name of the type 106 * @throws IllegalArgumentException If the type is unknwon 107 */ 108 public static String typeToString(ParameterType type) 109 { 110 return type.name().toLowerCase(); 111 } 112 113 /** 114 * Convert a string containing a type to its value 115 * 116 * @param type Name of the type 117 * @return Type 118 * @throws IllegalArgumentException if the type is unknown 119 */ 120 public static ParameterType stringToType(String type) 121 { 122 try 123 { 124 return ParameterType.valueOf(type.toUpperCase()); 125 } 126 catch (IllegalArgumentException e) 127 { 128 throw new IllegalArgumentException("The type '" + type + "' is unknown for config parameters"); 129 } 130 } 131 132 /** 133 * Cast a untyped value (string) to an object of the type 134 * 135 * @param value Value to cast 136 * @param type Type to cast value in 137 * @return An object of the type 'type' with value 'value', or null if type 138 * is unknown or value cannot be cast 139 */ 140 public static Object castValue(String value, ParameterType type) 141 { 142 143 if (value == null) 144 { 145 return null; 146 } 147 148 try 149 { 150 if (type == ParameterType.BOOLEAN) 151 { 152 return new Boolean(value); 153 } 154 else if (type == ParameterType.STRING) 155 { 156 return value; 157 } 158 else if (type == ParameterType.PASSWORD) 159 { 160 return value; 161 } 162 else if (type == ParameterType.DATASOURCE) 163 { 164 return value; 165 } 166 else if (type == ParameterType.LONG) 167 { 168 return new Long(value); 169 } 170 else if (type == ParameterType.DOUBLE) 171 { 172 return new Double(value); 173 } 174 else if (type == ParameterType.DATE) 175 { 176 return DateUtils.parse(value); 177 } 178 else if (type == ParameterType.BINARY) 179 { 180 return null; 181 } 182 } 183 catch (Exception nfe) 184 { 185 if (value.length() != 0) 186 { 187 _logger.error("Cannot cast value '" + value + "' into type '" + typeToString(type) + "'. Null object will be used.", nfe); 188 } 189 else if (_logger.isDebugEnabled()) 190 { 191 _logger.debug("Failed to cast empty string to type '" + typeToString(type) + "'. Null object will be used.", nfe); 192 } 193 } 194 return null; 195 } 196 197 198 /** 199 * Converts known types to string 200 * 201 * @param value Typed value 202 * @return String readable by the config bean 203 * @throws IllegalArgumentException if the object is a InputStream 204 */ 205 public static String valueToString(Object value) 206 { 207 if (value == null) 208 { 209 return null; 210 } 211 212 if (value instanceof Date) 213 { 214 ZonedDateTime zdt = DateUtils.asZonedDateTime((Date) value, null); 215 return zdt.format(getISODateTimeFormatter()); 216 } 217 218 if (value instanceof InputStream) 219 { 220 throw new IllegalArgumentException("The object to convert is an input stream"); 221 } 222 223 return value.toString(); 224 } 225 226 /** 227 * SAX a parameter 228 * @param handler The content handler where to SAX 229 * @param parameter The parameter to SAX 230 * @param value The parameter value. Can be null. 231 * @throws SAXException If an error occurred while SAXing 232 * @throws ProcessingException If an error occurred 233 */ 234 public static void toSAXParameter (ContentHandler handler, Parameter parameter, Object value) throws SAXException, ProcessingException 235 { 236 AttributesImpl parameterAttr = new AttributesImpl(); 237 parameterAttr.addAttribute("", "plugin", "plugin", "CDATA", parameter.getPluginName()); 238 XMLUtils.startElement(handler, parameter.getId(), parameterAttr); 239 240 toSAXParameterInternal(handler, parameter, value); 241 242 XMLUtils.endElement(handler, parameter.getId()); 243 } 244 245 /** 246 * SAX a parameter except the root tag 247 * @param handler The content handler where to SAX 248 * @param parameter The parameter to SAX 249 * @param value The parameter value. Can be null. 250 * @throws SAXException If an error occurred while SAXing 251 * @throws ProcessingException If an error occurred 252 */ 253 public static void toSAXParameterInternal(ContentHandler handler, Parameter parameter, Object value) throws SAXException, ProcessingException 254 { 255 parameter.getLabel().toSAX(handler, "label"); 256 parameter.getDescription().toSAX(handler, "description"); 257 258 XMLUtils.createElement(handler, "type", ParameterHelper.typeToString((ParameterType) parameter.getType())); 259 260 Object defaultValue = parameter.getDefaultValue(); 261 262 if (defaultValue != null) 263 { 264 XMLUtils.createElement(handler, "default-value", ParameterHelper.valueToString(defaultValue)); 265 } 266 267 if (value != null) 268 { 269 XMLUtils.createElement(handler, "value", ParameterHelper.valueToString(value)); 270 } 271 272 if (parameter.getWidget() != null) 273 { 274 XMLUtils.createElement(handler, "widget", parameter.getWidget()); 275 } 276 277 Map<String, I18nizableText> widgetParameters = parameter.getWidgetParameters(); 278 if (widgetParameters.size() > 0) 279 { 280 XMLUtils.startElement(handler, "widget-params"); 281 for (String paramName : widgetParameters.keySet()) 282 { 283 XMLUtils.startElement(handler, paramName); 284 widgetParameters.get(paramName).toSAX(handler); 285 XMLUtils.endElement(handler, paramName); 286 } 287 XMLUtils.endElement(handler, "widget-params"); 288 } 289 290 Enumerator enumerator = parameter.getEnumerator(); 291 if (enumerator != null) 292 { 293 toSAXEnumerator(handler, enumerator); 294 } 295 296 Validator validator = parameter.getValidator(); 297 toSAXValidator(handler, validator); 298 } 299 300 /** 301 * SAX parameter enumerator 302 * @param handler The content handler where to SAX 303 * @param enumerator The enumerator to SAX 304 * @throws SAXException If an error occurred to SAX 305 * @throws ProcessingException If an error occurred 306 */ 307 public static void toSAXEnumerator (ContentHandler handler, Enumerator enumerator) throws SAXException, ProcessingException 308 { 309 XMLUtils.startElement(handler, "enumeration"); 310 311 try 312 { 313 for (Map.Entry<Object, I18nizableText> entry : enumerator.getEntries().entrySet()) 314 { 315 String valueAsString = ParameterHelper.valueToString(entry.getKey()); 316 I18nizableText label = entry.getValue(); 317 318 // Generate option 319 AttributesImpl attrs = new AttributesImpl(); 320 attrs.addCDATAAttribute("value", valueAsString); 321 322 XMLUtils.startElement(handler, "option", attrs); 323 324 if (label != null) 325 { 326 label.toSAX(handler); 327 } 328 else 329 { 330 XMLUtils.data(handler, valueAsString); 331 } 332 333 XMLUtils.endElement(handler, "option"); 334 } 335 } 336 catch (Exception e) 337 { 338 throw new ProcessingException("Unable to enumerate entries with enumerator: " + enumerator, e); 339 } 340 341 XMLUtils.endElement(handler, "enumeration"); 342 } 343 344 /** 345 * SAX parameter validator 346 * @param handler The content handler where to SAX 347 * @param validator The validator to SAX 348 * @throws SAXException If an error occurred while SAXing 349 */ 350 public static void toSAXValidator (ContentHandler handler, Validator validator) throws SAXException 351 { 352 if (validator != null) 353 { 354 XMLUtils.startElement(handler, "validation"); 355 356 Map<String, Object> configuration = validator.getConfiguration(); 357 358 for (Map.Entry<String, Object> entry : configuration.entrySet()) 359 { 360 _saxConfigurationObject(handler, entry.getKey(), entry.getValue()); 361 } 362 363 XMLUtils.endElement(handler, "validation"); 364 } 365 } 366 367 @SuppressWarnings("unchecked") 368 private static void _saxConfigurationObject(ContentHandler handler, String name, Object value) throws SAXException 369 { 370 if (value instanceof I18nizableText) 371 { 372 ((I18nizableText) value).toSAX(handler, name); 373 } 374 else if (value instanceof Collection) 375 { 376 for (Object item : (Collection) value) 377 { 378 if (item != null) 379 { 380 _saxConfigurationObject(handler, name, item); 381 } 382 } 383 } 384 else if (value instanceof Map) 385 { 386 XMLUtils.startElement(handler, name); 387 for (Map.Entry<String, Object> subEntry : ((Map<String, Object>) value).entrySet()) 388 { 389 _saxConfigurationObject(handler, subEntry.getKey(), subEntry.getValue()); 390 } 391 XMLUtils.endElement(handler, name); 392 } 393 else if (value instanceof Object[]) 394 { 395 for (Object item : (Object[]) value) 396 { 397 if (item != null) 398 { 399 _saxConfigurationObject(handler, name, item); 400 } 401 } 402 } 403 else 404 { 405 XMLUtils.createElement(handler, name, String.valueOf(value)); 406 } 407 } 408 409 /** 410 * Convert the parameter in a JSON map 411 * @param parameter The parameter to convert 412 * @return The Parameter as a map 413 * @throws ProcessingException If an error occurred when converting the parameter 414 */ 415 public static Map<String, Object> toJSON(Parameter parameter) throws ProcessingException 416 { 417 ElementDefinition definition = new DefaultElementDefinition(); 418 definition.setName(parameter.getId()); 419 definition.setLabel(parameter.getLabel()); 420 definition.setDescription(parameter.getDescription()); 421 definition.setPluginName(parameter.getPluginName()); 422 definition.setValidator(parameter.getValidator()); 423 definition.setWidget(parameter.getWidget()); 424 definition.setWidgetParameters(parameter.getWidgetParameters()); 425 426 Map<String, Object> result = definition.toJSON(DefinitionContext.newInstance()); 427 428 // Put type from ParameterHelper.ParameterType to not convert from the old to the new API 429 result.put("type", parameter.getType().name().replaceAll("_", "-")); 430 if (parameter.getDefaultValue() != null) 431 { 432 result.put("default-value", parameter.getDefaultValue()); 433 } 434 435 // Manage enumerator from ParameterHelper because enumerator class is not the same from Parameter to ElementDefintion 436 if (parameter.getEnumerator() != null) 437 { 438 Enumerator enumerator = parameter.getEnumerator(); 439 List<Map<String, Object>> enumeration = new ArrayList<>(); 440 441 try 442 { 443 Map<Object, I18nizableText> entries = enumerator.getEntries(); 444 for (Object entryKey : entries.keySet()) 445 { 446 Map<String, Object> option = new HashMap<>(); 447 option.put("value", ParameterHelper.valueToString(entryKey)); 448 option.put("label", entries.get(entryKey)); 449 enumeration.add(option); 450 } 451 } 452 catch (Exception e) 453 { 454 throw new ProcessingException("Unable to enumerate entries with enumerator: " + enumerator, e); 455 } 456 457 result.put("enumeration", enumeration); 458 result.put("enumerationConfig", enumerator.getConfiguration()); 459 } 460 461 return result; 462 } 463}