Skip to content

Commit e2add0d

Browse files
committed
HJsonWriter support for new JSON encoding, add HNA
1 parent a0de699 commit e2add0d

21 files changed

+247
-36
lines changed

index.fandoc

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ and REST API for sensor systems such as HVAC, lighting, and energy equipment.
1313
This toolkit provides a simple, small Java API for working with haystack:
1414

1515
- **Modeling**: APIs for modeling tags values and grids
16-
- **Formats**: encoding and decoding of grids using Zinc, CSV, etc
16+
- **Formats**: encoding and decoding of grids using Zinc, JSON, CSV, etc
1717
- **Filter**: Haystack query language AST and parser
1818
- **Client**: full client side implementation of HTTP REST API
1919
- **Server**: servlet and server side implementation of HTTP REST API
@@ -38,6 +38,7 @@ the scalar values of [tag kinds]`http://project-haystack.org/doc/TagModel#tagKin
3838
- 'HTime': time as hour, minute, second, milliseconds
3939
- 'HDateTime': date time with timezone offset and timezone name
4040
- 'HBin': MIME typed binary blob
41+
- 'HCoord': geographic coordinate as latitude and longitute
4142

4243
All 'HVal' classes are immutable, once created they cannot be modified.
4344

index.html

+9-7
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@
5656

5757
<!-- Title Block -->
5858
<h1 class='title'>Haystack Java Toolkit</h1>
59-
<h2 id='overview'>Overview </h2>
59+
<h2 id='overview'>Overview</h2>
6060

6161
<p><a href='http://project-haystack.org/'>Project Haystack</a> defines a tagging model and REST API for sensor systems such as HVAC, lighting, and energy equipment. This toolkit provides a simple, small Java API for working with haystack:</p>
6262

6363
<ul>
6464
<li><strong>Modeling</strong>: APIs for modeling tags values and grids</li>
6565

66-
<li><strong>Formats</strong>: encoding and decoding of grids using Zinc, CSV, etc</li>
66+
<li><strong>Formats</strong>: encoding and decoding of grids using Zinc, JSON, CSV, etc</li>
6767

6868
<li><strong>Filter</strong>: Haystack query language AST and parser</li>
6969

@@ -74,7 +74,7 @@ <h2 id='overview'>Overview </h2>
7474

7575
<p>All code is written to work with Java 1.4 and J2ME (no use of newer Java features such as generics). This code is all open sourced under the Academic Free License version 3.0 (same license used as Project Haystack).</p>
7676

77-
<h2 id='vals'>HVal APIs </h2>
77+
<h2 id='vals'>HVal APIs</h2>
7878

7979
<p>The <code>HVal</code> class is the common base class for classes used to model the scalar values of <a href='http://project-haystack.org/doc/TagModel#tagKinds'>tag kinds</a>:</p>
8080

@@ -98,11 +98,13 @@ <h2 id='vals'>HVal APIs </h2>
9898
<li><code>HDateTime</code>: date time with timezone offset and timezone name</li>
9999

100100
<li><code>HBin</code>: MIME typed binary blob</li>
101+
102+
<li><code>HCoord</code>: geographic coordinate as latitude and longitute</li>
101103
</ul>
102104

103105
<p>All <code>HVal</code> classes are immutable, once created they cannot be modified.</p>
104106

105-
<h2 id='dict'>HDict API </h2>
107+
<h2 id='dict'>HDict API</h2>
106108

107109
<p>The <code>HDict</code> class models a set of tag name/value pairs. The tag names are modeled as <code>String</code> and values as <code>HVal</code>. The <code>HDict</code> class is immutable, once an instance is created it cannot be modified. Use <code>HDictBuilder</code> to build an immutable <code>HDict</code> instance:</p>
108110

@@ -128,7 +130,7 @@ <h2 id='dict'>HDict API </h2>
128130
HVal val = (HVal)e.getValue();
129131
}</pre>
130132

131-
<h2 id='grid'>HGrid API </h2>
133+
<h2 id='grid'>HGrid API</h2>
132134

133135
<p>The <code>HGrid</code> class models a <a href='http://project-haystack.org/doc/Grids'>Haystack grid</a>. A grid is composed</p>
134136

@@ -172,7 +174,7 @@ <h2 id='grid'>HGrid API </h2>
172174
HRow row = grid.row(i);
173175
}</pre>
174176

175-
<h2 id='client'>HClient API </h2>
177+
<h2 id='client'>HClient API</h2>
176178

177179
<p>The <code>HClient</code> class is used to communicate over HTTP to a Haystack server via the <a href='http://project-haystack.org/doc/Rest'>REST API</a>.</p>
178180

@@ -185,7 +187,7 @@ <h2 id='client'>HClient API </h2>
185187
// read all records that have "site" tag
186188
HGrid sites = client.readAll("site");</pre>
187189

188-
<h2 id='server'>HServer API </h2>
190+
<h2 id='server'>HServer API</h2>
189191

190192
<p>The <code>HServer</code> class provides infrastructure to add server side support for the <a href='http://project-haystack.org/doc/Rest'>Haystack REST API</a>.</p>
191193

src/org/projecthaystack/HBin.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,33 @@ public boolean equals(Object that)
3838
return this.mime.equals(((HBin)that).mime);
3939
}
4040

41+
/** Encode as "b:<mime>" */
42+
public String toJson()
43+
{
44+
StringBuffer s = new StringBuffer();
45+
s.append("b:");
46+
encodeMime(s);
47+
return s.toString();
48+
}
49+
4150
/** Encode as "Bin(<mime>)" */
4251
public String toZinc()
4352
{
4453
StringBuffer s = new StringBuffer();
4554
s.append("Bin(");
55+
encodeMime(s);
56+
s.append(')');
57+
return s.toString();
58+
}
59+
60+
private void encodeMime(StringBuffer s)
61+
{
4662
for (int i=0; i<mime.length(); ++i)
4763
{
4864
int c = mime.charAt(i);
4965
if (c > 127 || c == ')') throw new IllegalArgumentException("Invalid mime, char='" + (char)c + "'");
5066
s.append((char)c);
5167
}
52-
s.append(')');
53-
return s.toString();
5468
}
5569

5670
}

src/org/projecthaystack/HBool.java

+3
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public class HBool extends HVal
3838
/** Encode as "true" or "false" */
3939
public String toString() { return val ? "true" : "false"; }
4040

41+
/** Raise UnsupportedOperationException */
42+
public String toJson() { throw new UnsupportedOperationException(); }
43+
4144
/** Encode as "T" or "F" */
4245
public String toZinc() { return val ? "T" : "F"; }
4346

src/org/projecthaystack/HCoord.java

+11
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ public boolean equals(Object that)
8787
return ulat == x.ulat && ulng == x.ulng;
8888
}
8989

90+
/** Return "c:lat,lng" */
91+
public String toJson()
92+
{
93+
StringBuffer s = new StringBuffer();
94+
s.append("c:");
95+
uToStr(s, ulat);
96+
s.append(',');
97+
uToStr(s, ulng);
98+
return s.toString();
99+
}
100+
90101
/** Represented as "C(lat,lng)" */
91102
public String toZinc()
92103
{

src/org/projecthaystack/HDate.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,25 @@ public int compareTo(Object that)
9191
/** Day of month as 1-31 */
9292
public final int day;
9393

94+
/** Encode as "d:YYYY-MM-DD" */
95+
public String toJson()
96+
{
97+
StringBuffer s = new StringBuffer();
98+
s.append("d:");
99+
encode(s);
100+
return s.toString();
101+
}
102+
94103
/** Encode as "YYYY-MM-DD" */
95104
public String toZinc()
96105
{
97106
StringBuffer s = new StringBuffer();
98-
toZinc(s);
107+
encode(s);
99108
return s.toString();
100109
}
101110

102111
/** Package private implementation shared with HDateTime */
103-
void toZinc(StringBuffer s)
112+
void encode(StringBuffer s)
104113
{
105114
s.append(year).append('-');
106115
if (month < 10) s.append('0'); s.append(month).append('-');
@@ -178,4 +187,4 @@ public int weekday()
178187
private static final int daysInMon[] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
179188
private static final int daysInMonLeap[] = { -1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
180189

181-
}
190+
}

src/org/projecthaystack/HDateTime.java

+20-6
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ public static HDateTime make(long millis, HTimeZone tz)
7979
return ts;
8080
}
8181

82-
/** Parse from string fomat "YYYY-MM-DD'T'hh:mm:ss.FFFz zzzz"
83-
* or raise ParseException
82+
/** Parse from string fomat "YYYY-MM-DD'T'hh:mm:ss.FFFz zzzz"
83+
* or raise ParseException
8484
*/
8585
public static HDateTime make(String s)
8686
{
@@ -162,13 +162,28 @@ public int compareTo(Object that)
162162
return 0;
163163
}
164164

165+
/** Encode as "t:YYYY-MM-DD'T'hh:mm:ss.FFFz zzzz" */
166+
public String toJson()
167+
{
168+
StringBuffer s = new StringBuffer();
169+
s.append("t:");
170+
encode(s);
171+
return s.toString();
172+
}
173+
165174
/** Encode as "YYYY-MM-DD'T'hh:mm:ss.FFFz zzzz" */
166175
public String toZinc()
167176
{
168177
StringBuffer s = new StringBuffer();
169-
date.toZinc(s);
178+
encode(s);
179+
return s.toString();
180+
}
181+
182+
private void encode(StringBuffer s)
183+
{
184+
date.encode(s);
170185
s.append('T');
171-
time.toZinc(s);
186+
time.encode(s);
172187
if (tzOffset == 0) s.append('Z');
173188
else
174189
{
@@ -181,9 +196,8 @@ public String toZinc()
181196
if (zm < 10) s.append('0'); s.append(zm);
182197
}
183198
s.append(' ').append(tz);
184-
return s.toString();
185199
}
186200

187201
private static final TimeZone utc = TimeZone.getTimeZone("Etc/UTC");
188202

189-
}
203+
}

src/org/projecthaystack/HMarker.java

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ private HMarker() {}
2828
/** Encode as "marker" */
2929
public String toString() { return "marker"; }
3030

31+
/** Encode as "m:" */
32+
public String toJson() { return "m:"; }
33+
3134
/** Encode as "M" */
3235
public String toZinc() { return "M"; }
3336

src/org/projecthaystack/HNA.java

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// Copyright (c) 2015, Brian Frank
3+
// Licensed under the Academic Free License version 3.0
4+
//
5+
// History:
6+
// 09 Jun 2015 Brian Frank Creation
7+
//
8+
package org.projecthaystack;
9+
10+
/**
11+
* HNA is the singleton value used to indicate not available.
12+
*
13+
* @see <a href='http://project-haystack.org/doc/TagModel#tagKinds'>Project Haystack</a>
14+
*/
15+
public class HNA extends HVal
16+
{
17+
/** Singleton value */
18+
public static final HNA VAL = new HNA();
19+
20+
private HNA() {}
21+
22+
/** Hash code */
23+
public int hashCode() { return 0x6e61; }
24+
25+
/** Equals is based on reference */
26+
public boolean equals(Object that) { return this == that; }
27+
28+
/** Encode as "na" */
29+
public String toString() { return "na"; }
30+
31+
/** Encode as "z:" */
32+
public String toJson() { return "z:"; }
33+
34+
/** Encode as "NA" */
35+
public String toZinc() { return "NA"; }
36+
37+
}

src/org/projecthaystack/HNum.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,31 @@ public int compareTo(Object that)
112112
return 1;
113113
}
114114

115+
/** Encode as "n:<float> [unit]" */
116+
public String toJson()
117+
{
118+
StringBuffer s = new StringBuffer();
119+
s.append("n:");
120+
encode(s, true);
121+
return s.toString();
122+
}
123+
115124
/** Encode as floating value followed by optional unit string */
116125
public String toZinc()
117126
{
118127
StringBuffer s = new StringBuffer();
128+
encode(s, false);
129+
return s.toString();
130+
}
131+
132+
private void encode(StringBuffer s, boolean spaceBeforeUnit)
133+
{
119134
if (val == Double.POSITIVE_INFINITY) s.append("INF");
120135
else if (val == Double.NEGATIVE_INFINITY) s.append("-INF");
121136
else if (Double.isNaN(val)) s.append("NaN");
122137
else
123138
{
124-
// don't let fractions
139+
// don't encode huge set of decimals if over 1.0
125140
double abs = val; if (abs < 0) abs = -abs;
126141
if (abs > 1.0)
127142
s.append(new DecimalFormat("#0.####", new DecimalFormatSymbols(Locale.ENGLISH)).format(val));
@@ -130,11 +145,11 @@ public String toZinc()
130145

131146
if (unit != null)
132147
{
148+
if (spaceBeforeUnit) s.append(' ');
133149
for (int i=0; i<unit.length(); ++i)
134150
s.append(unit.charAt(i));
135151
}
136152
}
137-
return s.toString();
138153
}
139154

140155
/**

src/org/projecthaystack/HRef.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,16 @@ public String dis()
5959
/** Encode as "@id" */
6060
public String toCode() { return "@" + val; }
6161

62-
/** Encode as "@id <dis>" */
62+
/** Encode as "r:<id> [dis]" */
63+
public String toJson()
64+
{
65+
StringBuffer s = new StringBuffer();
66+
s.append("r:").append(val);
67+
if (dis != null) s.append(' ').append(dis);
68+
return s.toString();
69+
}
70+
71+
/** Encode as "@<id> [dis]" */
6372
public String toZinc()
6473
{
6574
StringBuffer s = new StringBuffer();

src/org/projecthaystack/HRemove.java

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ private HRemove() {}
2828
/** Encode as "remove" */
2929
public String toString() { return "remove"; }
3030

31+
/** Encode as "x:" */
32+
public String toJson() { return "x:"; }
33+
3134
/** Encode as "R" */
3235
public String toZinc() { return "R"; }
3336

src/org/projecthaystack/HStr.java

+6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public String toString()
4949
return val;
5050
}
5151

52+
/** Encode as "s:" if string contains a colon */
53+
public String toJson()
54+
{
55+
return val.indexOf(':') < 0 ? val : "s:"+val;
56+
}
57+
5258
/** Encode using double quotes and back slash escapes */
5359
public String toZinc()
5460
{

0 commit comments

Comments
 (0)