Time formatter utilities

main
Tim Holloway 11 months ago
parent a76d5cb1ac
commit 0373867875
  1. 1
      .classpath
  2. 2
      src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java
  3. 45
      src/main/java/com/mousetech/gourmetj/UserSession.java
  4. 181
      src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java
  5. 1
      src/main/java/com/mousetech/gourmetj/utils/package-info.java
  6. 10
      src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml
  7. 2
      src/main/resources/META-INF/resources/detailEdit.xhtml
  8. 11
      src/main/resources/META-INF/resources/error/viewExpired.html
  9. 4
      src/main/resources/META-INF/resources/recipeDetails.xhtml
  10. 44
      src/test/java/com/mousetech/gourmetj/utils/TimeFormatterTest.java

@ -99,5 +99,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -215,8 +215,6 @@ public class RecipeDetailBean implements Serializable {
@PostConstruct
private void init() {
this.recipe = userSession.getRecipe();
log.info("Using recipe: " + this.recipe);
/**
* For "create new, this recipe is a blank constructed
* and passed from main page. For Detail display, it's

@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
import com.mousetech.gourmetj.persistence.model.Category;
import com.mousetech.gourmetj.persistence.model.Recipe;
import com.mousetech.gourmetj.utils.TimeFormatter;
@Named
@SessionScoped
@ -123,46 +124,15 @@ public class UserSession implements Serializable {
return sb.toString();
}
//** Util, consider conversion to JSF Converter
public String formatTime(Long ltime) {
if (ltime == null) {
return "";
}
int time = ltime.intValue();
int dd, hh, mm, ss;
ss = time % 60;
time /= 60;
mm = time % 60;
time /= 60;
hh = time % 24;
dd = time / 24;
StringBuffer sb = new StringBuffer(20);
if (dd > 0) {
sb.append(dd).append("d ");
}
if (hh > 0) {
sb.append(hh).append("h ");
}
if (mm > 0) {
sb.append(mm);
if ((ss == 0) && (hh == 0)) {
sb.append(" minutes");
} else {
sb.append("min. ");
}
}
if (ss > 0) {
sb.append(dd).append("sec. ");
}
return sb.toString().trim();
return TimeFormatter.formatTime(ltime);
}
// Primefaces handle session timeout
/**
* Session timeout, msec.
*/
private long sessionTimeoutInterval = 300000;
// Session timeout, ms
long sessionTimeoutInterval = 30000L;
/**
* @return the sessionTimeoutInterval
*/
@ -176,7 +146,8 @@ public class UserSession implements Serializable {
.executeScript("sessionExpiredConfirmation.show()");
}
public void logoutAction() {
public String logoutAction() {
log.warn("Session Idle listener logout");
return "/main.jsf";
}
}

@ -0,0 +1,181 @@
package com.mousetech.gourmetj.utils;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handle conversion of complex time fields where days, hours,
* minutes and seconds may be present as separate entities.
*
* @author timh
* @since Jan 8, 2022
*/
public class TimeFormatter {
/* Logger */
private static final Logger log =
LoggerFactory.getLogger(TimeFormatter.class);
public static String formatTime(Long ltime) {
if (ltime == null) {
return "";
}
int time = ltime.intValue();
int dd, hh, mm, ss;
ss = time % 60;
time /= 60;
mm = time % 60;
time /= 60;
hh = time % 24;
dd = time / 24;
StringBuffer sb = new StringBuffer(20);
if (dd > 0) {
sb.append(dd).append("d ");
}
if (hh > 0) {
sb.append(hh).append("h ");
}
if (mm > 0) {
sb.append(mm);
if ((ss == 0) && (hh == 0)) {
sb.append(" minutes");
} else {
sb.append("min. ");
}
}
if (ss > 0) {
sb.append(dd).append("sec. ");
}
return sb.toString().trim();
}
// private enum MunchUnit {
// mu_NONE, mu_DAY, mu_HOUR, mu_MINUTE, mw_SECOND
// }
private static class TimeMuncher {
public class MunchException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
}
final private String SPAT_DAYS = "days?|d";
final private String SPAT_HOURS = "hours?|h|hr";
final private String SPAT_MINUTES = "minutes?|mins?|m";
final private String SPAT_SECONDS = "seconds?|secs?|s";
final Pattern pat_number;
final Pattern pat_days;
final Pattern pat_hours;
final Pattern pat_mins;
final Pattern pat_secs;
final Scanner scanner;
public TimeMuncher(String timestr) {
pat_number =
Pattern.compile("(\\d[\\,\\.]?\\d*)?(.*)");
// Compile here for future I18N support
pat_days = Pattern.compile(SPAT_DAYS);
pat_hours = Pattern.compile(SPAT_HOURS);
pat_mins = Pattern.compile(SPAT_MINUTES);
pat_secs = Pattern.compile(SPAT_SECONDS);
scanner = new Scanner(timestr);
scanner.useDelimiter("\\W");
}
public Long scan() {
Double sum = null;
Double dvalue = null;
try {
while (scanner.hasNext()) {
if (scanner.hasNextDouble()) {
dvalue = scanner.nextDouble();
} else {
String units = scanner.next();
sum = setSum(sum, dvalue, units);
dvalue = null;
}
}
} catch (MunchException e) {
log.warn("Unparseable time value");
e.printStackTrace();
}
if (sum == null) {
return null;
}
return sum.longValue();
}
private Double setSum(Double sum, Double dvalue,
String units) throws MunchException {
Matcher m;
m = pat_number.matcher(units);
if (!m.matches()) {
throw new MunchException();
}
if (m.group(1) != null) {
String a = m.group(1);
if (dvalue != null) {
throw new MunchException();
}
dvalue = Double
.valueOf(a);
//units = units.substring(m.end());
}
units = m.group(2);
m = pat_days.matcher(units);
if (m.matches()) {
return addToSum(sum, dvalue,
24L * 60L * 60L * 1000L);
}
m = pat_hours.matcher(units);
if (m.matches()) {
return addToSum(sum, dvalue, 60L * 60L * 1000L);
}
m = pat_mins.matcher(units);
if (m.matches()) {
return addToSum(sum, dvalue, 60L * 1000L);
}
m = pat_secs.matcher(units);
if (m.matches()) {
return addToSum(sum, dvalue, 1000L);
}
return sum;
}
private Double addToSum(Double sum, Double dvalue,
long l) throws MunchException {
if (dvalue == null) {
throw new TimeMuncher.MunchException();
}
dvalue *= l;
if (sum == null) {
sum = 0.0;
}
sum += dvalue;
return sum;
}
}
public static Long parseTime(String timestr) {
TimeMuncher muncher = new TimeMuncher(timestr);
Long interval = muncher.scan();
return interval;
}
}

@ -0,0 +1 @@
package com.mousetech.gourmetj.utils;

@ -40,16 +40,16 @@
</p:idleMonitor>
<p:confirmDialog closable="false"
id="sessionExpiredDlg"
message="Your session expired."
message="Your session has expired."
header="#{msgs['confirmDialog.initiatingDestroyProcess.label']}"
severity="alert"
widgetVar="sessionExpiredConfirmation"
style="z-index: 25000"
>
<p:commandButton id="confirmRouteDel"
value="Ok"
oncomplete="PF('sessionExpiredDlg').hide()"
actionListener="#{userSession.logoutAction}"
<p:commandButton id="cmdExpiredOK"
value="OK"
action="/main.jsf"
oncomplete="PF('sessionExpiredConfirmation').hide()"
/>
</p:confirmDialog>
</h:form>

@ -360,10 +360,12 @@
</p:tabView>
<p:commandButton id="doSave" value="Save"
icon="ui-icon-pencil"
ajax="false"
disabled="{not recipeDetailBean.dirty}"
action="#{recipeDetailBean.doSave}"
/>
<p:commandButton id="doCancel" value="Cancel"
ajax="false"
immediate="true" action="recipeDetails.jsf"
/>
</h:form>

@ -1,13 +1,14 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>ERROR - Page Expired</title>
</head>
<body>
<h1>Page Expired</h1>
<p>The page state could not be restored because it was left
idle too long.</p>
<p><a href="/main.jsf">Return to Main Page</a></p>
<p>The page state could not be restored because it was
left idle too long.</p>
<p>
<a href="/main.jsf">Return to Main Page</a>
</p>
</body>
</html>
</html>

@ -45,12 +45,12 @@
columns="2"
>
<p:commandButton
value="Back"
value="Back" ajax="false"
icon="ui-icon-arrowthick-1-w"
action="main.jsf"
immediate="true"
/>
<p:commandButton
<p:commandButton ajax="false"
value="Print"
icon="ui-icon-print"
action="recipePrint.jsf"

@ -0,0 +1,44 @@
/**
* Copyright (C) 2022, Tim Holloway
*
* Date written: Jan 8, 2022
* Author: Tim Holloway <timh@mousetech.com>
*/
package com.mousetech.gourmetj.utils;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
* @author timh
* @since Jan 8, 2022
*/
class TimeFormatterTest {
/**
* @throws java.lang.Exception
*/
@BeforeAll
static void setUpBeforeClass() throws Exception {
}
@Test
void test() {
assertEquals(5000, TimeFormatter.parseTime("5s"));
assertEquals(5000*60, TimeFormatter.parseTime("5m"));
assertEquals(3600_000 + 25*60_000, TimeFormatter.parseTime("1 hour, 25 min"));
assertEquals(5*3600000 + 6*60000, TimeFormatter.parseTime("5h 6m"));
assertEquals(277562000L, TimeFormatter.parseTime("3d 5h 6m 2s"));
assertEquals(18000000L, TimeFormatter.parseTime("1.5 hours"));
assertEquals(3*3600_000, TimeFormatter.parseTime("3 hours"));
assertNull(TimeFormatter.parseTime("1 week"));
}
}
Loading…
Cancel
Save