001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.env; 018 019import java.util.Timer; 020import java.util.TimerTask; 021 022import org.apache.commons.scxml2.model.ModelException; 023 024/** 025 * A SCXML document driven stop watch. 026 * 027 * Using SCXML makes the StopWatch class simplistic; you are neither 028 * managing the stopwatch "lifecycle" nor coding any "transitions", 029 * that information is pulled in straight from the behavioral model 030 * of the stop watch, which is encapsulated in the SCXML document 031 * the constructor points to (which in turn may be generated straight 032 * from the UML model). 033 */ 034public class StopWatch extends AbstractStateMachine { 035 036 /** The events for the stop watch. */ 037 public static final String EVENT_START = "watch.start", 038 EVENT_STOP = "watch.stop", EVENT_SPLIT = "watch.split", 039 EVENT_UNSPLIT = "watch.unsplit", EVENT_RESET = "watch.reset"; 040 041 /** The fragments of the elapsed time. */ 042 private int hr, min, sec, fract; 043 /** The fragments of the display time. */ 044 private int dhr, dmin, dsec, dfract; 045 /** The stopwatch "split" (display freeze). */ 046 private boolean split; 047 /** The Timer to keep time. */ 048 private Timer timer; 049 /** The display decorations. */ 050 private static final String DELIM = ":", DOT = ".", EMPTY = "", ZERO = "0"; 051 052 public StopWatch() throws ModelException { 053 super(StopWatch.class.getClassLoader(). 054 getResource("org/apache/commons/scxml2/env/stopwatch.xml")); 055 } 056 057 // Each method below is the activity corresponding to a state in the 058 // SCXML document (see class constructor for pointer to the document). 059 public void reset() { 060 hr = min = sec = fract = dhr = dmin = dsec = dfract = 0; 061 split = false; 062 } 063 064 public void running() { 065 split = false; 066 if (timer == null) { 067 timer = new Timer(true); 068 timer.scheduleAtFixedRate(new TimerTask() { 069 @Override 070 public void run() { 071 increment(); 072 } 073 }, 100, 100); 074 } 075 } 076 077 public void paused() { 078 split = true; 079 } 080 081 public void stopped() { 082 timer.cancel(); 083 timer = null; 084 } 085 086 public String getDisplay() { 087 String padhr = dhr > 9 ? EMPTY : ZERO; 088 String padmin = dmin > 9 ? EMPTY : ZERO; 089 String padsec = dsec > 9 ? EMPTY : ZERO; 090 return new StringBuffer().append(padhr).append(dhr).append(DELIM). 091 append(padmin).append(dmin).append(DELIM).append(padsec). 092 append(dsec).append(DOT).append(dfract).toString(); 093 } 094 095 // used by the demonstration (see StopWatchDisplay usecase) 096 public String getCurrentState() { 097 return getEngine().getStatus().getStates().iterator().next().getId(); 098 } 099 100 private void increment() { 101 if (fract < 9) { 102 fract++; 103 } else { 104 fract = 0; 105 if (sec < 59) { 106 sec++; 107 } else { 108 sec = 0; 109 if (min < 59) { 110 min++; 111 } else { 112 min = 0; 113 if (hr < 99) { 114 hr++; 115 } else { 116 hr = 0; //wrap 117 } 118 } 119 } 120 } 121 if (!split) { 122 dhr = hr; 123 dmin = min; 124 dsec = sec; 125 dfract = fract; 126 } 127 } 128 129} 130