Skip to content

Commit 0e92815

Browse files
author
Cyrille Le Clerc
authored
Merge pull request #16 from bbergquist0930/structureddata
Add support for Structured Data
2 parents bd329fc + 31627c2 commit 0e92815

File tree

4 files changed

+395
-1
lines changed

4 files changed

+395
-1
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright 2010-2014, CloudBees Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.cloudbees.syslog;
17+
18+
import java.io.Serializable;
19+
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.List;
22+
import java.util.Objects;
23+
24+
/**
25+
* A SD-ELEMENT
26+
*
27+
* @author <a href="mailto:[email protected]">Brett Bergquist</a>
28+
*/
29+
public class SDElement implements Serializable {
30+
31+
private static final long serialVersionUID = 1L;
32+
33+
/**
34+
* Reserved SD-IDs as documented in <a href="https://www.rfc-editor.org/rfc/rfc5424.txt">RFC-5424</a>
35+
*/
36+
public static final String[] RESERVED_SDID = new String[]{
37+
"timeQuality",
38+
"tzKnown",
39+
"isSynced",
40+
"syncAccuracy"
41+
};
42+
43+
public SDElement(String sdID) {
44+
validateSDID(sdID);
45+
this.sdID = sdID;
46+
}
47+
48+
public SDElement(String sdID, SDParam... sdParams) {
49+
validateSDID(sdID);
50+
this.sdID = sdID;
51+
this.sdParams.addAll(Arrays.asList(sdParams));
52+
}
53+
54+
private String sdID;
55+
56+
/**
57+
* Get the value of sdID
58+
*
59+
* @return the value of sdID
60+
*/
61+
public String getSdID() {
62+
return sdID;
63+
}
64+
65+
private List<SDParam> sdParams = new ArrayList<SDParam>();
66+
67+
/**
68+
* Get the value of sdParams
69+
*
70+
* @return the value of sdParams
71+
*/
72+
public List<SDParam> getSdParams() {
73+
return sdParams;
74+
}
75+
76+
/**
77+
* Set the value of sdParams
78+
*
79+
* @param sdParams new value of sdParams
80+
*/
81+
public void setSdParams(List<SDParam> sdParams) {
82+
if (null == sdParams) {
83+
throw new IllegalArgumentException("sdParams list cannot be null");
84+
}
85+
this.sdParams.addAll(sdParams);
86+
}
87+
88+
/**
89+
* Adds a SDParam
90+
* @param paramName the PARAM-NAME
91+
* @param paramValue the PARAM-VALUE
92+
* @return
93+
*/
94+
public SDElement addSDParam(String paramName, String paramValue) {
95+
return addSDParam(new SDParam(paramName, paramValue));
96+
}
97+
98+
public SDElement addSDParam(SDParam sdParam) {
99+
this.sdParams.add(sdParam);
100+
return this;
101+
}
102+
103+
@Override
104+
public int hashCode() {
105+
int hash = 7;
106+
hash = 97 * hash + Objects.hashCode(this.sdID);
107+
return hash;
108+
}
109+
110+
@Override
111+
public boolean equals(Object obj) {
112+
if (this == obj) {
113+
return true;
114+
}
115+
if (obj == null) {
116+
return false;
117+
}
118+
if (getClass() != obj.getClass()) {
119+
return false;
120+
}
121+
final SDElement other = (SDElement) obj;
122+
return Objects.equals(this.sdID, other.sdID);
123+
}
124+
125+
private void validateSDID(String sdName) {
126+
if (null == sdName) {
127+
throw new IllegalArgumentException("SD-ID cannot be null");
128+
}
129+
if (sdName.length() > 32) {
130+
throw new IllegalArgumentException("SD-ID must be less than 32 characters: " + sdName);
131+
}
132+
if (sdName.contains("=")) {
133+
throw new IllegalArgumentException("SD-ID cannot contain '='");
134+
}
135+
if (sdName.contains(" ")) {
136+
throw new IllegalArgumentException("SD-ID cannot contain ' '");
137+
}
138+
if (sdName.contains("]")) {
139+
throw new IllegalArgumentException("SD-ID cannot contain ']'");
140+
}
141+
if (sdName.contains("\"")) {
142+
throw new IllegalArgumentException("SD-ID cannot contain '\"'");
143+
}
144+
if (! sdName.contains("@")) {
145+
boolean found = false;
146+
for (String rn : RESERVED_SDID) {
147+
if (rn.equals(sdName)) {
148+
found = true;
149+
break;
150+
}
151+
}
152+
if (! found) {
153+
throw new IllegalArgumentException("SD-ID is not known registered SDID: " + sdName);
154+
}
155+
}
156+
}
157+
158+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright 2010-2014, CloudBees Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.cloudbees.syslog;
17+
18+
import java.io.Serializable;
19+
import java.util.Objects;
20+
21+
/**
22+
*
23+
* @author <a href="mailto:[email protected]">Brett Bergquist</a>
24+
*/
25+
public class SDParam implements Serializable {
26+
27+
private static final long serialVersionUID = 1L;
28+
29+
public SDParam(String paramName, String paramValue) {
30+
validateParamName(paramName);
31+
this.paramName = paramName;
32+
this.paramValue = paramValue;
33+
}
34+
35+
private String paramName;
36+
37+
/**
38+
* Get the value of paramName
39+
*
40+
* @return the value of paramName
41+
*/
42+
public String getParamName() {
43+
return paramName;
44+
}
45+
46+
/**
47+
* Set the value of paramName
48+
*
49+
* @param paramName new value of paramName
50+
*/
51+
public void setParamName(String paramName) {
52+
validateParamName(paramName);
53+
this.paramName = paramName;
54+
}
55+
56+
private String paramValue;
57+
58+
/**
59+
* Get the value of paramValue
60+
*
61+
* @return the value of paramValue
62+
*/
63+
public String getParamValue() {
64+
return paramValue;
65+
}
66+
67+
/**
68+
* Set the value of paramValue
69+
*
70+
* @param paramValue new value of paramValue
71+
*/
72+
public void setParamValue(String paramValue) {
73+
this.paramValue = paramValue;
74+
}
75+
76+
private void validateParamName(String sdName) {
77+
if (null == sdName) {
78+
throw new IllegalArgumentException("PARAM-NAME cannot be null");
79+
}
80+
if (sdName.length() > 32) {
81+
throw new IllegalArgumentException("PARAM-NAME must be less than 32 characters: " + sdName);
82+
}
83+
if (sdName.contains("=")) {
84+
throw new IllegalArgumentException("PARAM-NAME cannot contain '='");
85+
}
86+
if (sdName.contains(" ")) {
87+
throw new IllegalArgumentException("PARAM-NAME cannot contain ' '");
88+
}
89+
if (sdName.contains("]")) {
90+
throw new IllegalArgumentException("PARAM-NAME cannot contain ']'");
91+
}
92+
if (sdName.contains("\"")) {
93+
throw new IllegalArgumentException("PARAM-NAME cannot contain '\"'");
94+
}
95+
}
96+
97+
@Override
98+
public int hashCode() {
99+
int hash = 7;
100+
hash = 59 * hash + Objects.hashCode(this.paramName);
101+
hash = 59 * hash + Objects.hashCode(this.paramValue);
102+
return hash;
103+
}
104+
105+
@Override
106+
public boolean equals(Object obj) {
107+
if (this == obj) {
108+
return true;
109+
}
110+
if (obj == null) {
111+
return false;
112+
}
113+
if (getClass() != obj.getClass()) {
114+
return false;
115+
}
116+
final SDParam other = (SDParam) obj;
117+
if (!Objects.equals(this.paramName, other.paramName)) {
118+
return false;
119+
}
120+
if (!Objects.equals(this.paramValue, other.paramValue)) {
121+
return false;
122+
}
123+
return true;
124+
}
125+
126+
@Override
127+
public String toString() {
128+
return "SDParam{" + "paramName=" + paramName + ", paramValue=" + paramValue + '}';
129+
}
130+
131+
}

src/main/java/com/cloudbees/syslog/SyslogMessage.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import java.net.InetAddress;
2525
import java.net.UnknownHostException;
2626
import java.util.Date;
27+
import java.util.HashSet;
2728
import java.util.Locale;
29+
import java.util.Set;
2830
import java.util.TimeZone;
2931
import java.util.concurrent.TimeUnit;
3032

@@ -91,6 +93,7 @@ protected String newObject() {
9193
private String appName;
9294
private String procId;
9395
private String msgId;
96+
private Set<SDElement> sdElements;
9497
/**
9598
* Use a {@link java.io.CharArrayWriter} instead of a {@link String} or a {@code char[]} because middlewares like
9699
* Apache Tomcat use {@code CharArrayWriter} and it's convenient for pooling objects.
@@ -213,6 +216,26 @@ public SyslogMessage withMsg(final String msg) {
213216
}
214217
});
215218
}
219+
220+
public Set<SDElement> getSDElements() {
221+
Set<SDElement> ssde = sdElements;
222+
if (ssde == null) {
223+
ssde = new HashSet<SDElement>(0);
224+
}
225+
return ssde;
226+
}
227+
228+
public void setSDElements(Set<SDElement> ssde) {
229+
this.sdElements = ssde;
230+
}
231+
232+
public SyslogMessage withSDElement(SDElement sde) {
233+
if (sdElements == null) {
234+
sdElements = new HashSet<SDElement>();
235+
}
236+
sdElements.add(sde);
237+
return this;
238+
}
216239

217240
/**
218241
* Generates a Syslog message complying to the <a href="http://tools.ietf.org/html/rfc5424">RFC-5424</a> format
@@ -290,7 +313,7 @@ public void toRfc5424SyslogMessage(Writer out) throws IOException {
290313
out.write(SP);
291314
writeNillableValue(msgId, out);// Message ID
292315
out.write(SP);
293-
out.write(NILVALUE); // structured data
316+
writeStructuredDataOrNillableValue(sdElements, out);
294317
if (msg != null) {
295318
out.write(SP);
296319
msg.writeTo(out);
@@ -342,4 +365,53 @@ protected void writeNillableValue(@Nullable String value, @Nonnull Writer out) t
342365
out.write(value);
343366
}
344367
}
368+
369+
protected void writeStructuredDataOrNillableValue(@Nullable Set<SDElement> ssde, @Nonnull Writer out) throws IOException {
370+
if (ssde == null || ssde.isEmpty()) {
371+
out.write(NILVALUE);
372+
} else {
373+
for (SDElement sde : ssde) {
374+
writeSDElement(sde, out);
375+
}
376+
}
377+
}
378+
379+
protected void writeSDElement(@Nonnull SDElement sde, @Nonnull Writer out) throws IOException {
380+
out.write("[");
381+
out.write(sde.getSdID());
382+
for (SDParam sdp : sde.getSdParams()) {
383+
writeSDParam(sdp, out);
384+
}
385+
out.write("]");
386+
}
387+
388+
protected void writeSDParam(@Nonnull SDParam sdp, @Nonnull Writer out) throws IOException {
389+
out.write(SP);
390+
out.write(sdp.getParamName());
391+
out.write('=');
392+
out.write('"');
393+
out.write(getEscapedParamValue(sdp.getParamValue()));
394+
out.write('"');
395+
}
396+
397+
protected String getEscapedParamValue(String paramValue) {
398+
StringBuilder sb = new StringBuilder(paramValue.length());
399+
400+
for (int i = 0; i < paramValue.length(); i++) {
401+
char c = paramValue.charAt(i);
402+
switch (c) {
403+
// Falls through
404+
case '"':
405+
case '\\':
406+
case ']':
407+
sb.append('\\');
408+
break;
409+
default:
410+
break;
411+
}
412+
sb.append(c);
413+
}
414+
415+
return sb.toString();
416+
}
345417
}

0 commit comments

Comments
 (0)