Advertisement
Guest User

Untitled

a guest
Jul 24th, 2019
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.19 KB | None | 0 0
  1. package com.elypia.commandler.adapters;
  2.  
  3. import com.elypia.commandler.CommandlerEvent;
  4. import com.elypia.commandler.annotations.Adapter;
  5. import com.elypia.commandler.interfaces.ParamAdapter;
  6. import com.elypia.commandler.metadata.MetaParam;
  7.  
  8. import javax.inject.Inject;
  9. import java.text.*;
  10. import java.time.Duration;
  11. import java.util.*;
  12. import java.util.concurrent.TimeUnit;
  13.  
  14. /**
  15. * Adapt user input into Java {@link Duration} objects.
  16. * (This will allow users to specify a duration of time.)
  17. */
  18. @Adapter(Duration.class)
  19. public class DurationAdapter implements ParamAdapter<Duration> {
  20.  
  21. /** The TimeUnits this is compatible with. */
  22. private static final TimeUnit[] units = {
  23. TimeUnit.DAYS,
  24. TimeUnit.HOURS,
  25. TimeUnit.MINUTES,
  26. TimeUnit.SECONDS,
  27. TimeUnit.MILLISECONDS,
  28. TimeUnit.NANOSECONDS
  29. };
  30.  
  31. /** Java NumberFormatter instance, this has a locale set so we know how to parse it. */
  32. private final NumberFormat format;
  33.  
  34. /** Uses the default {@link TimeUnitAdapter} to get the units after numbers. */
  35. private final TimeUnitAdapter timeUnitAdapter;
  36.  
  37.  
  38. /**
  39. * TODO: Make a means to dictate if duplicate of same value is allowed or ASC/DESC
  40. * Instantiate the DurationAdapter with a NumberFormat with the default Locale.
  41. */
  42. public DurationAdapter() {
  43. this(NumberFormat.getInstance());
  44. }
  45.  
  46. /** Instantiate the DurationAdapter with the default TimeUnitAdapter. */
  47. public DurationAdapter(NumberFormat format) {
  48. this(format, new TimeUnitAdapter(units));
  49. }
  50.  
  51. @Inject
  52. public DurationAdapter(NumberFormat format, TimeUnitAdapter timeUnitAdapter) {
  53. this.format = Objects.requireNonNull(format);
  54. this.timeUnitAdapter = Objects.requireNonNull(timeUnitAdapter);
  55. }
  56.  
  57. /**
  58. * Uses the NumberFormat to parse the number from the start,
  59. * then look for characters matching <code>(?i)[A-Z ]+</code>
  60. * to discover the timeunit, and repeat.
  61. *
  62. * @param input The input from the user.
  63. * @param type The type of data required.
  64. * @param data The parameter this is returning too.
  65. * @param event The event that required this parameter adapted.
  66. * @return The Duration object this represents, or null if it failed to parse.
  67. */
  68. @Override
  69. public Duration adapt(String input, Class<? extends Duration> type, MetaParam data, CommandlerEvent<?> event) {
  70. Map<TimeUnit, Long> units = new HashMap<>();
  71. ParsePosition position = new ParsePosition(0);
  72. char[] sequence = input.toCharArray();
  73.  
  74. while (!isFinished(input, position)) {
  75. Number number = format.parse(input, position);
  76. int start = position.getIndex();
  77. int end = start;
  78.  
  79. while (end < sequence.length) {
  80. char c = sequence[end];
  81.  
  82. if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == ' ')
  83. end++;
  84. else
  85. break;
  86. }
  87.  
  88. position.setIndex(end);
  89. String unitString = input.substring(start, end);
  90. TimeUnit unit = timeUnitAdapter.adapt(unitString);
  91.  
  92. if (unit == null)
  93. return null;
  94.  
  95. units.put(unit, number.longValue());
  96. }
  97.  
  98. if (units.size() == 0)
  99. return null;
  100.  
  101. return buildDuration(units);
  102. }
  103.  
  104. /**
  105. * Returns true if an error occured in parsing, or it just went through all
  106. * of the input and finished.
  107. *
  108. * @param input The string being parsed.
  109. * @param position The parse position being used against this string.
  110. * @return If this input and parse position are done parsing regardless of reason.
  111. */
  112. private boolean isFinished(String input, ParsePosition position) {
  113. return position.getErrorIndex() != -1 || position.getIndex() == input.length();
  114. }
  115.  
  116. /**
  117. * Take the map if timeunits to units and put it together into a
  118. * Duration object which reflects the total time.
  119. *
  120. * @param units Each timeunit mapped against the value of time.
  121. * @return A duration object which puts all timeunits and values together.
  122. */
  123. private Duration buildDuration(Map<TimeUnit, Long> units) {
  124. Duration duration = Duration.ZERO;
  125.  
  126. for (Map.Entry<TimeUnit, Long> entry : units.entrySet()) {
  127. long time = entry.getValue();
  128.  
  129. switch (entry.getKey()) {
  130. case DAYS:
  131. duration = duration.plusDays(time);
  132. break;
  133. case HOURS:
  134. duration = duration.plusHours(time);
  135. break;
  136. case MINUTES:
  137. duration = duration.plusMinutes(time);
  138. break;
  139. case SECONDS:
  140. duration = duration.plusSeconds(time);
  141. break;
  142. case MILLISECONDS:
  143. duration = duration.plusMillis(time);
  144. break;
  145. case NANOSECONDS:
  146. duration = duration.plusNanos(time);
  147. break;
  148. default:
  149. throw new IllegalStateException("Invalid timeunit provided.");
  150. }
  151. }
  152.  
  153. return duration;
  154. }
  155. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement