1 /******************************************************************************* 2 * Copyright (c) 2015, 2019 Raymond Augé and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Raymond Augé - bug fixes and enhancements 13 ******************************************************************************/ 14 15 package org.eclipse.equinox.http.servlet.internal.util; 16 17 import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*; 18 19 import java.lang.reflect.Array; 20 import java.util.*; 21 import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO; 22 import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO.ErrorCodeType; 23 import org.eclipse.equinox.http.servlet.internal.error.HttpWhiteboardFailureException; 24 import org.osgi.dto.DTO; 25 import org.osgi.framework.Constants; 26 import org.osgi.framework.ServiceReference; 27 import org.osgi.service.http.runtime.dto.*; 28 29 /** 30 * @author Raymond Augé 31 */ 32 public class DTOUtil { 33 assembleErrorPageDTO(ServiceReference<?> serviceReference, long contextId, boolean validated)34 public static ExtendedErrorPageDTO assembleErrorPageDTO(ServiceReference<?> serviceReference, long contextId, boolean validated) { 35 Object errorPageObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ERROR_PAGE); 36 37 if (errorPageObj == null) { 38 return null; 39 } 40 41 ExtendedErrorPageDTO errorPageDTO = new ExtendedErrorPageDTO(); 42 43 errorPageDTO.asyncSupported = false; 44 Object asyncSupportedObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); 45 if (asyncSupportedObj == null) { 46 // ignored 47 } 48 else if (Boolean.class.isInstance(asyncSupportedObj)) { 49 errorPageDTO.asyncSupported = ((Boolean)asyncSupportedObj).booleanValue(); 50 } 51 else if (String.class.isInstance(asyncSupportedObj)) { 52 errorPageDTO.asyncSupported = Boolean.valueOf((String)asyncSupportedObj); 53 } 54 // There is no validation for this scenario, truthiness of any other input is false 55 56 List<String> errorPages = StringPlus.from(errorPageObj); 57 if (errorPages.isEmpty()) { 58 throw new HttpWhiteboardFailureException("'errorPage' expects String, String[] or Collection<String>", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 59 } 60 61 List<String> exceptions = new ArrayList<String>(); 62 Set<Long> errorCodeSet = new LinkedHashSet<Long>(); 63 64 for(String errorPage : errorPages) { 65 try { 66 if ("4xx".equals(errorPage)) { //$NON-NLS-1$ 67 errorPageDTO.errorCodeType = ErrorCodeType.RANGE_4XX; 68 for (long code = 400; code < 500; code++) { 69 errorCodeSet.add(code); 70 } 71 } else if ("5xx".equals(errorPage)) { //$NON-NLS-1$ 72 errorPageDTO.errorCodeType = ErrorCodeType.RANGE_5XX; 73 for (long code = 500; code < 600; code++) { 74 errorCodeSet.add(code); 75 } 76 } else if (errorPage.matches("\\d{3}")) { //$NON-NLS-1$ 77 errorPageDTO.errorCodeType = ErrorCodeType.SPECIFIC; 78 long code = Long.parseLong(errorPage); 79 errorCodeSet.add(code); 80 } else { 81 exceptions.add(errorPage); 82 } 83 } 84 catch (NumberFormatException nfe) { 85 exceptions.add(errorPage); 86 } 87 } 88 89 errorPageDTO.errorCodes = new long[errorCodeSet.size()]; 90 int i = 0; 91 for(Long code : errorCodeSet) { 92 errorPageDTO.errorCodes[i] = code; 93 i++; 94 } 95 96 errorPageDTO.exceptions = exceptions.toArray(new String[0]); 97 98 errorPageDTO.initParams = ServiceProperties.parseInitParams( 99 serviceReference, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); 100 101 Object servletNameObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_NAME); 102 if (servletNameObj == null) { 103 // ignore 104 } 105 else if (String.class.isInstance(servletNameObj)) { 106 errorPageDTO.name = (String)servletNameObj; 107 } 108 else if (validated) { 109 throw new HttpWhiteboardFailureException("'name' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 110 } 111 112 errorPageDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); 113 errorPageDTO.servletContextId = contextId; 114 115 return errorPageDTO; 116 } 117 118 @SuppressWarnings("deprecation") assembleServletDTO(ServiceReference<?> serviceReference, long contextId, boolean validated)119 public static org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO assembleServletDTO(ServiceReference<?> serviceReference, long contextId, boolean validated) { 120 org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO servletDTO = new org.eclipse.equinox.http.servlet.dto.ExtendedServletDTO(); 121 122 servletDTO.asyncSupported = false; 123 Object asyncSupportedObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED); 124 if (asyncSupportedObj == null) { 125 // ignored 126 } 127 else if (Boolean.class.isInstance(asyncSupportedObj)) { 128 servletDTO.asyncSupported = ((Boolean)asyncSupportedObj).booleanValue(); 129 } 130 else if (String.class.isInstance(asyncSupportedObj)) { 131 servletDTO.asyncSupported = Boolean.valueOf((String)asyncSupportedObj); 132 } 133 // There is no validation for this scenario, truthiness of any other input is false 134 135 servletDTO.initParams = ServiceProperties.parseInitParams( 136 serviceReference, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX); 137 138 servletDTO.multipartEnabled = false; 139 Object multipartEnabledObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_ENABLED); 140 if (multipartEnabledObj == null) { 141 multipartEnabledObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_ENABLED); 142 } 143 if (multipartEnabledObj == null) { 144 // ignore 145 } 146 else if (Boolean.class.isInstance(multipartEnabledObj)) { 147 servletDTO.multipartEnabled = ((Boolean)multipartEnabledObj).booleanValue(); 148 } 149 else if (String.class.isInstance(multipartEnabledObj)) { 150 servletDTO.multipartEnabled = Boolean.valueOf((String)multipartEnabledObj); 151 } 152 // There is no validation for this scenario, truthiness of any other input is false 153 154 servletDTO.multipartFileSizeThreshold = 0; 155 servletDTO.multipartLocation = Const.BLANK; 156 servletDTO.multipartMaxFileSize = -1L; 157 servletDTO.multipartMaxRequestSize = -1L; 158 159 if (servletDTO.multipartEnabled) { 160 Object multipartFileSizeThresholdObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_FILESIZETHRESHOLD); 161 if (multipartFileSizeThresholdObj == null) { 162 multipartFileSizeThresholdObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_FILESIZETHRESHOLD); 163 } 164 if (multipartFileSizeThresholdObj == null) { 165 // ignore 166 } 167 else if (Integer.class.isInstance(multipartFileSizeThresholdObj)) { 168 servletDTO.multipartFileSizeThreshold = ((Integer)multipartFileSizeThresholdObj).intValue(); 169 } 170 else if (validated) { 171 throw new HttpWhiteboardFailureException("'multipartFileSizeThreshold' expects int or Integer", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 172 } 173 174 Object multipartLocationObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_LOCATION); 175 if (multipartLocationObj == null) { 176 multipartLocationObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_LOCATION); 177 } 178 if (multipartLocationObj == null) { 179 // ignore 180 } 181 else if (String.class.isInstance(multipartLocationObj)) { 182 servletDTO.multipartLocation = (String)multipartLocationObj; 183 } 184 else if (validated) { 185 throw new HttpWhiteboardFailureException("'multipartLocation' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 186 } 187 188 Object multipartMaxFileSizeObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXFILESIZE); 189 if (multipartMaxFileSizeObj == null) { 190 multipartMaxFileSizeObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_MAXFILESIZE); 191 } 192 if (multipartMaxFileSizeObj == null) { 193 // ignore 194 } 195 else if (Long.class.isInstance(multipartMaxFileSizeObj)) { 196 servletDTO.multipartMaxFileSize = ((Long)multipartMaxFileSizeObj).longValue(); 197 } 198 else if (validated) { 199 throw new HttpWhiteboardFailureException("'multipartMaxFileSize' expects [L|l]ong", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 200 } 201 202 Object multipartMaxRequestSizeObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_MULTIPART_MAXREQUESTSIZE); 203 if (multipartMaxRequestSizeObj == null) { 204 multipartMaxRequestSizeObj = serviceReference.getProperty(Const.EQUINOX_HTTP_MULTIPART_MAXREQUESTSIZE); 205 } 206 if (multipartMaxRequestSizeObj == null) { 207 // ignore 208 } 209 else if (Long.class.isInstance(multipartMaxRequestSizeObj)) { 210 servletDTO.multipartMaxRequestSize = ((Long)multipartMaxRequestSizeObj).longValue(); 211 } 212 else if (validated) { 213 throw new HttpWhiteboardFailureException("'multipartMaxRequestSize' expects [L|l]ong", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 214 } 215 } 216 217 Object servletNameObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_NAME); 218 if (servletNameObj == null) { 219 // ignore 220 } 221 else if (String.class.isInstance(servletNameObj)) { 222 servletDTO.name = (String)servletNameObj; 223 } 224 else if (validated) { 225 throw new HttpWhiteboardFailureException("'name' expects String", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 226 } 227 228 Object patternObj = serviceReference.getProperty(HTTP_WHITEBOARD_SERVLET_PATTERN); 229 if (patternObj == null) { 230 servletDTO.patterns = new String[0]; 231 } 232 else { 233 servletDTO.patterns = sort(StringPlus.from(patternObj).toArray(new String[0])); 234 235 if (validated && (servletDTO.patterns.length > 0)) { 236 for (String pattern : servletDTO.patterns) { 237 checkPattern(pattern); 238 } 239 } 240 } 241 242 servletDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID); 243 servletDTO.servletContextId = contextId; 244 245 return servletDTO; 246 } 247 clone(ErrorPageDTO original)248 public static ErrorPageDTO clone(ErrorPageDTO original) { 249 ErrorPageDTO clone = new ErrorPageDTO(); 250 251 clone.asyncSupported = copy(original.asyncSupported); 252 clone.errorCodes = copy(original.errorCodes); 253 clone.exceptions = copy(original.exceptions); 254 clone.initParams = copyStringMap(original.initParams); 255 clone.name = copy(original.name); 256 clone.serviceId = copy(original.serviceId); 257 clone.servletContextId = copy(original.servletContextId); 258 clone.servletInfo = copy(original.servletInfo); 259 260 return clone; 261 } 262 clone(FailedErrorPageDTO original)263 public static FailedErrorPageDTO clone(FailedErrorPageDTO original) { 264 FailedErrorPageDTO clone = new FailedErrorPageDTO(); 265 266 clone.asyncSupported = copy(original.asyncSupported); 267 clone.errorCodes = copy(original.errorCodes); 268 clone.exceptions = copy(original.exceptions); 269 clone.failureReason = copy(original.failureReason); 270 clone.initParams = copyStringMap(original.initParams); 271 clone.name = copy(original.name); 272 clone.serviceId = copy(original.serviceId); 273 clone.servletContextId = copy(original.servletContextId); 274 clone.servletInfo = copy(original.servletInfo); 275 276 return clone; 277 } 278 clone(FailedFilterDTO original)279 public static FailedFilterDTO clone(FailedFilterDTO original) { 280 FailedFilterDTO clone = new FailedFilterDTO(); 281 282 clone.asyncSupported = copy(original.asyncSupported); 283 clone.dispatcher = copy(original.dispatcher); 284 clone.failureReason = copy(original.failureReason); 285 clone.initParams = copyStringMap(original.initParams); 286 clone.name = copy(original.name); 287 clone.patterns = copy(original.patterns); 288 clone.regexs = copy(original.regexs); 289 clone.serviceId = copy(original.serviceId); 290 clone.servletContextId = copy(original.servletContextId); 291 clone.servletNames = copy(original.servletNames); 292 293 return clone; 294 } 295 clone(FailedListenerDTO original)296 public static FailedListenerDTO clone(FailedListenerDTO original) { 297 FailedListenerDTO clone = new FailedListenerDTO(); 298 299 clone.failureReason = copy(original.failureReason); 300 clone.serviceId = copy(original.serviceId); 301 clone.servletContextId = copy(original.servletContextId); 302 clone.types = copy(original.types); 303 304 return clone; 305 } 306 clone(FailedPreprocessorDTO original)307 public static FailedPreprocessorDTO clone(FailedPreprocessorDTO original) { 308 FailedPreprocessorDTO clone = new FailedPreprocessorDTO(); 309 310 clone.failureReason = copy(original.failureReason); 311 clone.initParams = copyStringMap(original.initParams); 312 clone.serviceId = copy(original.serviceId); 313 314 return clone; 315 } 316 clone(FailedResourceDTO original)317 public static FailedResourceDTO clone(FailedResourceDTO original) { 318 FailedResourceDTO clone = new FailedResourceDTO(); 319 320 clone.failureReason = copy(original.failureReason); 321 clone.patterns = copy(original.patterns); 322 clone.prefix = copy(original.prefix); 323 clone.serviceId = copy(original.serviceId); 324 clone.servletContextId = copy(original.servletContextId); 325 326 return clone; 327 } 328 clone(FailedServletContextDTO original)329 public static FailedServletContextDTO clone(FailedServletContextDTO original) { 330 FailedServletContextDTO clone = new FailedServletContextDTO(); 331 332 clone.attributes = copyGenericMap(original.attributes); 333 clone.contextPath = copy(original.contextPath); 334 clone.errorPageDTOs = copy(original.errorPageDTOs); 335 clone.failureReason = copy(original.failureReason); 336 clone.filterDTOs = copy(original.filterDTOs); 337 clone.initParams = copyStringMap(original.initParams); 338 clone.listenerDTOs = copy(original.listenerDTOs); 339 clone.name = copy(original.name); 340 clone.resourceDTOs = copy(original.resourceDTOs); 341 clone.serviceId = copy(original.serviceId); 342 clone.servletDTOs = copy(original.servletDTOs); 343 344 return clone; 345 } 346 clone(FailedServletDTO original)347 public static FailedServletDTO clone(FailedServletDTO original) { 348 FailedServletDTO clone = new FailedServletDTO(); 349 350 clone.asyncSupported = copy(original.asyncSupported); 351 clone.failureReason = copy(original.failureReason); 352 clone.initParams = copyStringMap(clone.initParams); 353 clone.multipartEnabled = copy(original.multipartEnabled); 354 clone.multipartFileSizeThreshold = copy(original.multipartFileSizeThreshold); 355 clone.multipartLocation = copy(original.multipartLocation); 356 clone.multipartMaxFileSize = copy(original.multipartMaxFileSize); 357 clone.multipartMaxRequestSize = copy(original.multipartMaxRequestSize); 358 clone.name = copy(original.name); 359 clone.patterns = copy(original.patterns); 360 clone.serviceId = copy(original.serviceId); 361 clone.servletContextId = copy(original.servletContextId); 362 clone.servletInfo = copy(original.servletInfo); 363 364 return clone; 365 } 366 clone(FilterDTO original)367 public static FilterDTO clone(FilterDTO original) { 368 FilterDTO clone = new FilterDTO(); 369 370 clone.asyncSupported = copy(original.asyncSupported); 371 clone.dispatcher = copy(original.dispatcher); 372 clone.initParams = copyStringMap(original.initParams); 373 clone.name = copy(original.name); 374 clone.patterns = copy(original.patterns); 375 clone.regexs = copy(original.regexs); 376 clone.serviceId = copy(original.serviceId); 377 clone.servletContextId = copy(original.servletContextId); 378 clone.servletNames = copy(original.servletNames); 379 380 return clone; 381 } 382 clone(ListenerDTO original)383 public static ListenerDTO clone(ListenerDTO original) { 384 ListenerDTO clone = new ListenerDTO(); 385 386 clone.serviceId = copy(original.serviceId); 387 clone.servletContextId = copy(original.servletContextId); 388 clone.types = copy(original.types); 389 390 return clone; 391 } 392 clone(ResourceDTO original)393 public static ResourceDTO clone(ResourceDTO original) { 394 ResourceDTO clone = new ResourceDTO(); 395 396 clone.patterns = copy(original.patterns); 397 clone.prefix = copy(original.prefix); 398 clone.serviceId = copy(original.serviceId); 399 clone.servletContextId = copy(original.servletContextId); 400 401 return clone; 402 } 403 clone(ServletDTO original)404 public static ServletDTO clone(ServletDTO original) { 405 ServletDTO clone = new ServletDTO(); 406 407 clone.asyncSupported = copy(original.asyncSupported); 408 clone.initParams = copyStringMap(original.initParams); 409 clone.multipartEnabled = copy(original.multipartEnabled); 410 clone.multipartFileSizeThreshold = copy(original.multipartFileSizeThreshold); 411 clone.multipartLocation = copy(original.multipartLocation); 412 clone.multipartMaxFileSize = copy(original.multipartMaxFileSize); 413 clone.multipartMaxRequestSize = copy(original.multipartMaxRequestSize); 414 clone.name = copy(original.name); 415 clone.patterns = copy(original.patterns); 416 clone.serviceId = copy(original.serviceId); 417 clone.servletContextId = copy(original.servletContextId); 418 clone.servletInfo = copy(original.servletInfo); 419 420 return clone; 421 } 422 copy(long[] array)423 private static long[] copy(long[] array) { 424 if (array == null) { 425 return new long[0]; 426 } 427 if (array.length == 0) { 428 return array; 429 } 430 return Arrays.copyOf(array, array.length); 431 } 432 433 copy(String[] array)434 private static String[] copy(String[] array) { 435 if (array == null) { 436 return new String[0]; 437 } 438 if (array.length == 0) { 439 return array; 440 } 441 return Arrays.copyOf(array, array.length); 442 } 443 copy(T[] array)444 private static <T> T[] copy(T[] array) { 445 if (array == null) { 446 return null; 447 } 448 if (array.length == 0) { 449 return array; 450 } 451 return Arrays.copyOf(array, array.length); 452 } 453 copy(int value)454 private static int copy(int value) { 455 return value; 456 } 457 copy(long value)458 private static long copy(long value) { 459 return value; 460 } 461 copy(boolean value)462 private static boolean copy(boolean value) { 463 return value; 464 } 465 copy(String value)466 private static String copy(String value) { 467 return value; 468 } 469 copyStringMap(Map<String, String> initParams)470 private static Map<String, String> copyStringMap(Map<String, String> initParams) { 471 if (initParams == null) { 472 return Collections.emptyMap(); 473 } 474 return new HashMap<String, String>(initParams); 475 } 476 copyGenericMap(Map<String, V> value)477 public static <V> Map<String, Object> copyGenericMap(Map<String, V> value) { 478 if ((value == null) || value.isEmpty()) { 479 return Collections.emptyMap(); 480 } 481 HashMap<String, Object> result = new HashMap<String, Object>(); 482 for (Map.Entry<String, V> entry : value.entrySet()) { 483 result.put(entry.getKey(), mapValue(entry.getValue())); 484 } 485 return result; 486 } 487 mapValue(Object v)488 public static Object mapValue(Object v) { 489 if ((v == null) 490 || v instanceof Number 491 || v instanceof Boolean 492 || v instanceof Character 493 || v instanceof String 494 || v instanceof DTO) { 495 return v; 496 } 497 if (v instanceof Map) { 498 Map<?, ?> m = (Map<?, ?>) v; 499 Map<Object, Object> map = newMap(m.size()); 500 for (Map.Entry<?, ?> e : m.entrySet()) { 501 map.put(mapValue(e.getKey()), mapValue(e.getValue())); 502 } 503 return map; 504 } 505 if (v instanceof List) { 506 List<?> c = (List<?>) v; 507 List<Object> list = newList(c.size()); 508 for (Object o : c) { 509 list.add(mapValue(o)); 510 } 511 return list; 512 } 513 if (v instanceof Set) { 514 Set<?> c = (Set<?>) v; 515 Set<Object> set = newSet(c.size()); 516 for (Object o : c) { 517 set.add(mapValue(o)); 518 } 519 return set; 520 } 521 if (v.getClass().isArray()) { 522 final int length = Array.getLength(v); 523 final Class<?> componentType = mapComponentType(v.getClass().getComponentType()); 524 Object array = Array.newInstance(componentType, length); 525 for (int i = 0; i < length; i++) { 526 Array.set(array, i, mapValue(Array.get(v, i))); 527 } 528 return array; 529 } 530 return String.valueOf(v); 531 } 532 checkPattern(String pattern)533 private static void checkPattern(String pattern) { 534 if (pattern == null) { 535 throw new HttpWhiteboardFailureException("Pattern cannot be null", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ 536 } 537 538 if (pattern.indexOf("*.") == 0) { //$NON-NLS-1$ 539 return; 540 } 541 542 if (Const.BLANK.equals(pattern)) { 543 return; 544 } 545 546 if (Const.SLASH.equals(pattern)) { 547 return; 548 } 549 550 if (!pattern.startsWith(Const.SLASH) || 551 (pattern.endsWith(Const.SLASH) && !pattern.equals(Const.SLASH)) || 552 pattern.contains("**")) { //$NON-NLS-1$ 553 554 throw new HttpWhiteboardFailureException( 555 "Invalid pattern '" + pattern + "'", DTOConstants.FAILURE_REASON_VALIDATION_FAILED); //$NON-NLS-1$ //$NON-NLS-2$ 556 } 557 } 558 mapComponentType(Class<?> componentType)559 private static Class<?> mapComponentType(Class<?> componentType) { 560 if (componentType.isPrimitive() 561 || componentType.isArray() 562 || Object.class.equals(componentType) 563 || Number.class.isAssignableFrom(componentType) 564 || Boolean.class.isAssignableFrom(componentType) 565 || Character.class.isAssignableFrom(componentType) 566 || String.class.isAssignableFrom(componentType) 567 || DTO.class.isAssignableFrom(componentType)) { 568 return componentType; 569 } 570 if (Map.class.isAssignableFrom(componentType)) { 571 return Map.class; 572 } 573 if (List.class.isAssignableFrom(componentType)) { 574 return List.class; 575 } 576 if (Set.class.isAssignableFrom(componentType)) { 577 return Set.class; 578 } 579 return String.class; 580 } 581 newList(int size)582 private static <E> List<E> newList(int size) { 583 return new ArrayList<E>(size); 584 } 585 newSet(int size)586 private static <E> Set<E> newSet(int size) { 587 return new HashSet<E>(size); 588 } 589 newMap(int size)590 private static <K, V> Map<K, V> newMap(int size) { 591 return new HashMap<K, V>(size); 592 } 593 sort(String[] values)594 private static String[] sort(String[] values) { 595 if (values == null) { 596 return null; 597 } 598 599 Arrays.sort(values); 600 601 return values; 602 } 603 604 } 605