1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.any23.extractor.microdata;
19
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.text.ParseException;
23 import java.text.SimpleDateFormat;
24 import java.util.Date;
25 import java.util.Locale;
26 import java.util.Objects;
27
28 import org.apache.any23.util.StringUtils;
29 import org.eclipse.rdf4j.model.Literal;
30 import org.eclipse.rdf4j.model.vocabulary.XSD;
31
32
33
34
35
36
37 public class ItemPropValue {
38
39
40
41
42 private final Object content;
43
44
45
46
47 private final Type type;
48
49 private static final ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<>();
50
51
52
53
54 public enum Type {
55 Plain(String.class), Link(String.class), Date(Date.class), Nested(ItemScope.class);
56
57 Type(Class<?> contentClass) {
58 this.contentClass = contentClass;
59 }
60
61 private final Class<?> contentClass;
62
63 private Object checkClass(Object content) {
64 Objects.requireNonNull(content, "content cannot be null");
65 if (!contentClass.isInstance(content)) {
66 throw new IllegalArgumentException(
67 "content must be a " + contentClass.getName() + " when type is " + this);
68 }
69 return content;
70 }
71 }
72
73 public static Date parseDateTime(String dateStr) throws ParseException {
74 return getSdf().parse(dateStr);
75 }
76
77 public static String formatDateTime(Date in) {
78 return getSdf().format(in);
79 }
80
81 private static SimpleDateFormat getSdf() {
82 SimpleDateFormat simpleDateFormat = sdf.get();
83 if (simpleDateFormat == null) {
84 simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ROOT);
85 sdf.set(simpleDateFormat);
86 }
87 return simpleDateFormat;
88 }
89
90
91
92
93
94
95
96
97
98 public ItemPropValue(Object content, Type type) {
99 this.type = Objects.requireNonNull(type, "type cannot be null");
100 this.content = type.checkClass(content);
101 this.literal = null;
102 }
103
104 ItemPropValue(Literal literal) {
105 this.literal = literal;
106
107 Type type;
108 Object content;
109
110
111 if (XSD.DATE.equals(literal.getDatatype()) || XSD.DATETIME.equals(literal.getDatatype())) {
112 try {
113 content = parseDateTime(literal.getLabel());
114 type = Type.Date;
115 } catch (Exception e) {
116 content = literal.getLabel();
117 type = Type.Plain;
118 }
119 } else {
120 content = literal.getLabel();
121 type = Type.Plain;
122 }
123 this.type = type;
124 this.content = content;
125 }
126
127 final Literal literal;
128
129
130
131
132 public Object getContent() {
133 return content;
134 }
135
136
137
138
139 public Type getType() {
140 return type;
141 }
142
143
144
145
146 public boolean isPlain() {
147 return type == Type.Plain;
148 }
149
150
151
152
153 public boolean isLink() {
154 return type == Type.Link;
155 }
156
157
158
159
160 public boolean isDate() {
161 return type == Type.Date;
162 }
163
164
165
166
167 public boolean isNested() {
168 return type == Type.Nested;
169 }
170
171
172
173
174 public boolean isInteger() {
175 if (type != Type.Plain)
176 return false;
177 try {
178 Integer.parseInt((String) content);
179 return true;
180 } catch (Exception e) {
181 return false;
182 }
183 }
184
185
186
187
188 public boolean isFloat() {
189 if (type != Type.Plain)
190 return false;
191 try {
192 Float.parseFloat((String) content);
193 return true;
194 } catch (Exception e) {
195 return false;
196 }
197 }
198
199
200
201
202 public boolean isNumber() {
203 return isInteger() || isFloat();
204 }
205
206
207
208
209
210
211
212
213
214 public int getAsInteger() {
215 return Integer.parseInt((String) content);
216 }
217
218
219
220
221
222
223
224
225
226 public float getAsFloat() {
227 return Float.parseFloat((String) content);
228 }
229
230
231
232
233
234
235
236 public Date getAsDate() {
237 return (Date) content;
238 }
239
240
241
242
243 public URL getAsLink() {
244 try {
245 return new URL((String) content);
246 } catch (MalformedURLException murle) {
247 throw new IllegalStateException("Error while parsing IRI.", murle);
248 }
249 }
250
251
252
253
254 public ItemScope getAsNested() {
255 return (ItemScope) content;
256 }
257
258 public String toJSON() {
259 String contentStr;
260 if (content instanceof String) {
261 contentStr = "\"" + StringUtils.escapeAsJSONString((String) content) + "\"";
262 } else if (content instanceof Date) {
263 contentStr = "\"" + getSdf().format((Date) content) + "\"";
264 } else {
265 contentStr = content.toString();
266 }
267
268 return String.format(Locale.ROOT, "{ \"content\" : %s, \"type\" : \"%s\" }", contentStr, type);
269 }
270
271 @Override
272 public String toString() {
273 return toJSON();
274 }
275
276 @Override
277 public int hashCode() {
278 return content.hashCode() * type.hashCode() * 2;
279 }
280
281 @Override
282 public boolean equals(Object obj) {
283 if (obj == null) {
284 return false;
285 }
286 if (obj == this) {
287 return true;
288 }
289 if (obj instanceof ItemPropValue) {
290 final ItemPropValue other = (ItemPropValue) obj;
291 return content.equals(other.content) && type.equals(other.type);
292 }
293 return false;
294 }
295 }