diff --git a/.classpath b/.classpath index 76fc9c8..f6013c0 100644 --- a/.classpath +++ b/.classpath @@ -99,5 +99,6 @@ + diff --git a/src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java b/src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java index 3ea29c2..c21665e 100644 --- a/src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java +++ b/src/main/java/com/mousetech/gourmetj/RecipeDetailBean.java @@ -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 diff --git a/src/main/java/com/mousetech/gourmetj/UserSession.java b/src/main/java/com/mousetech/gourmetj/UserSession.java index eb21410..0e4af9c 100644 --- a/src/main/java/com/mousetech/gourmetj/UserSession.java +++ b/src/main/java/com/mousetech/gourmetj/UserSession.java @@ -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"; } } diff --git a/src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java b/src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java new file mode 100644 index 0000000..13be7b0 --- /dev/null +++ b/src/main/java/com/mousetech/gourmetj/utils/TimeFormatter.java @@ -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; + } +} diff --git a/src/main/java/com/mousetech/gourmetj/utils/package-info.java b/src/main/java/com/mousetech/gourmetj/utils/package-info.java new file mode 100644 index 0000000..410ff17 --- /dev/null +++ b/src/main/java/com/mousetech/gourmetj/utils/package-info.java @@ -0,0 +1 @@ +package com.mousetech.gourmetj.utils; diff --git a/src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml b/src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml index 1a63bc7..d537bf7 100644 --- a/src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml +++ b/src/main/resources/META-INF/resources/WEB-INF/layout/layout.xhtml @@ -40,16 +40,16 @@ - diff --git a/src/main/resources/META-INF/resources/detailEdit.xhtml b/src/main/resources/META-INF/resources/detailEdit.xhtml index af80892..f9a139c 100644 --- a/src/main/resources/META-INF/resources/detailEdit.xhtml +++ b/src/main/resources/META-INF/resources/detailEdit.xhtml @@ -360,10 +360,12 @@ diff --git a/src/main/resources/META-INF/resources/error/viewExpired.html b/src/main/resources/META-INF/resources/error/viewExpired.html index b1a8cba..5ebdb02 100644 --- a/src/main/resources/META-INF/resources/error/viewExpired.html +++ b/src/main/resources/META-INF/resources/error/viewExpired.html @@ -1,13 +1,14 @@ - ERROR - Page Expired

Page Expired

-

The page state could not be restored because it was left - idle too long.

-

Return to Main Page

+

The page state could not be restored because it was + left idle too long.

+

+ Return to Main Page +

- + \ No newline at end of file diff --git a/src/main/resources/META-INF/resources/recipeDetails.xhtml b/src/main/resources/META-INF/resources/recipeDetails.xhtml index 581bde0..2f6d5d5 100644 --- a/src/main/resources/META-INF/resources/recipeDetails.xhtml +++ b/src/main/resources/META-INF/resources/recipeDetails.xhtml @@ -45,12 +45,12 @@ columns="2" > - + */ +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")); + } + +}