001: /*
002: * <copyright>
003: *
004: * Copyright 2001-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.glm.execution.eg;
027:
028: import java.io.BufferedReader;
029: import java.io.IOException;
030: import java.io.InputStream;
031: import java.io.InputStreamReader;
032: import java.net.MalformedURLException;
033: import java.net.URL;
034: import java.net.URLConnection;
035: import java.text.NumberFormat;
036: import java.util.HashMap;
037: import java.util.Iterator;
038: import java.util.Map;
039: import javax.swing.JLabel;
040: import javax.swing.JPanel;
041:
042: /**
043: * This plugin controls the failure/consumption rate of a set of
044: * consumables by reading a sensor value from a URL. A multiplier is
045: * computed from the reading and used to increase or decrease the mean
046: * consumption rate. The URL is obtained by replacing a % in the url
047: * pattern with the name of the sensor as entered from the GUI.
048: **/
049: public class TwentyFourBySevenPlugin extends TripletFCPlugin implements
050: TimeConstants {
051: private static final long SENSOR_UPDATE_INTERVAL = 10 * ONE_MINUTE;
052: private static final String DEFAULT_URL_PATTERN = "file:%.txt";
053:
054: private String urlPrefix;
055: private String urlSuffix;
056:
057: private class Sensor {
058: public URL url;
059: public String name;
060: public double reading;
061:
062: public Sensor(String name) {
063: url = getSensorURL(name);
064: this .name = name;
065: reading = Double.NaN;
066: }
067:
068: public String toString() {
069: return name + "(" + url + ")=" + reading;
070: }
071: }
072:
073: private static String[] valueLabels = { "Start Time", "End Time",
074: "Sensor", "Low-value", "Low-multiplier", "High-value",
075: "High-Multiplier" };
076: private static Class[] valueClasses = { EGDate.class, EGDate.class,
077: String.class, Double.class, Double.class, Double.class,
078: Double.class, };
079:
080: private static NumberFormat formatter;
081:
082: static {
083: formatter = NumberFormat.getInstance();
084: formatter.setMinimumFractionDigits(0);
085: formatter.setMaximumFractionDigits(2);
086: }
087:
088: private long nextSensorUpdateTime;
089: private Map sensors = new HashMap();
090:
091: protected class TripletValueImpl implements TripletValue {
092: private long startDate;
093: private long endDate;
094: private Sensor sensor;
095: private double base;
096: private double highValue;
097: private double midValue;
098: private double lowValue;
099:
100: public TripletValueImpl(long start, long end, Sensor sensor,
101: double lowValue, double lowMultiplier,
102: double highValue, double highMultiplier) {
103: startDate = start;
104: endDate = end;
105: this .sensor = sensor;
106: this .highValue = highValue;
107: this .lowValue = lowValue;
108: double loghm = Math.log(highMultiplier);
109: double loglm = Math.log(lowMultiplier);
110: double q = (loghm - loglm) / (highValue - lowValue);
111: base = Math.exp(q);
112: if (q == 0.0) {
113: midValue = (lowValue + highValue) * 0.5;
114: } else {
115: midValue = lowValue - Math.log(lowMultiplier) / q;
116: }
117: }
118:
119: public long getStartDate() {
120: return startDate;
121: }
122:
123: public long getEndDate() {
124: return endDate;
125: }
126:
127: public AnnotatedDouble getMultiplier() {
128: double reading = sensor.reading;
129: return new AnnotatedDouble(Double.isNaN(reading) ? 1.0
130: : getMultiplier(reading), sensor.name + "="
131: + reading);
132: }
133:
134: private double getMultiplier(double sensorValue) {
135: return Math.pow(base, sensorValue - midValue);
136: }
137:
138: private double getLowValue() {
139: return lowValue;
140: }
141:
142: private double getHighValue() {
143: return highValue;
144: }
145:
146: private double getLowMultiplier() {
147: return getMultiplier(lowValue);
148: }
149:
150: private double getHighMultiplier() {
151: return getMultiplier(highValue);
152: }
153:
154: public int getFieldCount() {
155: return 5;
156: }
157:
158: public Object getFieldValue(int ix) {
159: switch (ix) {
160: case 0:
161: return new EGDate(startDate);
162: case 1:
163: return new EGDate(endDate);
164: case 2:
165: return sensor.name;
166: case 3:
167: return formatter.format(getLowValue());
168: case 4:
169: return formatter.format(getLowMultiplier());
170: case 5:
171: return formatter.format(getHighValue());
172: case 6:
173: return formatter.format(getHighMultiplier());
174: default:
175: return "";
176: }
177: }
178:
179: public String toString() {
180: return new StringBuffer().append(getFieldValue(0)).append(
181: ",").append(getFieldValue(1)).append(",").append(
182: getFieldValue(2)).append(",").append(
183: getFieldValue(3)).append(",").append(
184: getFieldValue(4)).toString();
185: }
186: }
187:
188: public TwentyFourBySevenPlugin() {
189: setURLPattern(DEFAULT_URL_PATTERN);
190: }
191:
192: private void setURLPattern(String pattern) {
193: int ix = pattern.indexOf('%');
194: if (ix < 0) {
195: urlPrefix = pattern;
196: urlSuffix = "";
197: } else {
198: urlPrefix = pattern.substring(0, ix);
199: urlSuffix = pattern.substring(ix + 1);
200: }
201: }
202:
203: private URL getSensorURL(String name) {
204: try {
205: return new URL(urlPrefix + name + urlSuffix);
206: } catch (MalformedURLException e) {
207: throw new IllegalArgumentException("Bad sensor name");
208: }
209: }
210:
211: protected TripletValue createTripletValue(String[] args) {
212: Sensor sensor = (Sensor) sensors.get(args[2]);
213: if (sensor == null) {
214: final Sensor newSensor = new Sensor(args[2]);
215: sensors.put(args[2], newSensor);
216: new Thread("SensorUpdate " + args[2]) {
217: public void run() {
218: updateSensor(newSensor);
219: }
220: }.start();
221: sensor = newSensor;
222: }
223: return new TripletValueImpl(new EGDate(args[0]).getTime(),
224: new EGDate(args[1]).getTime(), sensor, Double
225: .parseDouble(args[3]), Double
226: .parseDouble(args[4]), Double
227: .parseDouble(args[5]), Double
228: .parseDouble(args[6]));
229: }
230:
231: protected String[] getTripletValueNames() {
232: return valueLabels;
233: }
234:
235: protected Class[] getTripletValueClasses() {
236: return valueClasses;
237: }
238:
239: protected Object[] getTripletDefaultValues() {
240: Object[] result = {
241: new EGDate(theEventGenerator.getExecutionTime()),
242: new EGDate(theEventGenerator.getExecutionTime() + 1800L
243: * ONE_DAY), "temperature", new Double(65.0),
244: new Double(1.0), new Double(75.0), new Double(1.1), };
245: return result;
246: }
247:
248: protected JPanel createMessage() {
249: JPanel message = super .createMessage();
250: // addItem(message, COMMENT_ROW, new JLabel("Multiplier = Base ^ (value - midValue)"));
251: return message;
252: }
253:
254: /**
255: * @return the name of this plugin
256: **/
257: public String getPluginName() {
258: return "TwentyFourBySeven";
259: }
260:
261: public String getDescription() {
262: return "Special plugin for controlling consumption from sensor readings";
263: }
264:
265: public void setParameter(String parameter) {
266: setURLPattern(parameter);
267: }
268:
269: protected void checkExecutionTime(long executionTime) {
270: if (executionTime > nextSensorUpdateTime) {
271: try {
272: updateSensors();
273: } catch (RuntimeException re) {
274: re.printStackTrace();
275: }
276: nextSensorUpdateTime = executionTime
277: + SENSOR_UPDATE_INTERVAL;
278: }
279: super .checkExecutionTime(executionTime);
280: }
281:
282: private void updateSensors() {
283: for (Iterator keys = sensors.keySet().iterator(); keys
284: .hasNext();) {
285: String key = (String) keys.next();
286: Sensor sensor = (Sensor) sensors.get(key);
287: updateSensor(sensor);
288: }
289: }
290:
291: private void updateSensor(Sensor sensor) {
292: try {
293: sensor.reading = readSensor(sensor.url);
294: System.out.println("Sensor " + sensor);
295: } catch (Exception e) {
296: e.printStackTrace();
297: }
298: }
299:
300: private double readSensor(URL url) throws IOException {
301: URLConnection conn = url.openConnection();
302: BufferedReader reader = new BufferedReader(
303: new InputStreamReader(conn.getInputStream()));
304: String line = reader.readLine();
305: reader.close();
306: return Double.parseDouble(line);
307: }
308: }
|