View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.message;
18  
19  import java.util.Map;
20  
21  import org.apache.logging.log4j.util.EnglishEnums;
22  
23  /**
24   * Represents a Message that conforms to RFC 5424 (http://tools.ietf.org/html/rfc5424).
25   */
26  public class StructuredDataMessage extends MapMessage {
27  
28      private static final long serialVersionUID = 1703221292892071920L;
29      private static final int MAX_LENGTH = 32;
30      private static final int HASHVAL = 31;
31  
32      private StructuredDataId id;
33  
34      private String message;
35  
36      private String type;
37  
38      /**
39       * Supported formats.
40       */
41      public enum Format {
42          /** The map should be formatted as XML. */
43          XML,
44          /** Full message format includes the type and message. */
45          FULL
46      }
47  
48      /**
49       * Constructor based on a String id.
50       * @param id The String id.
51       * @param msg The message.
52       * @param type The message type.
53       */
54      public StructuredDataMessage(final String id, final String msg, final String type) {
55          this.id = new StructuredDataId(id, null, null);
56          this.message = msg;
57          this.type = type;
58      }
59      /**
60       * Constructor based on a String id.
61       * @param id The String id.
62       * @param msg The message.
63       * @param type The message type.
64       * @param data The StructuredData map.
65       */
66      public StructuredDataMessage(final String id, final String msg, final String type,
67                                   final Map<String, String> data) {
68          super(data);
69          this.id = new StructuredDataId(id, null, null);
70          this.message = msg;
71          this.type = type;
72      }
73  
74      /**
75       * Constructor based on a StructuredDataId.
76       * @param id The StructuredDataId.
77       * @param msg The message.
78       * @param type The message type.
79       */
80      public StructuredDataMessage(final StructuredDataId id, final String msg, final String type) {
81          this.id = id;
82          this.message = msg;
83          this.type = type;
84      }
85  
86      /**
87       * Constructor based on a StructuredDataId.
88       * @param id The StructuredDataId.
89       * @param msg The message.
90       * @param type The message type.
91       * @param data The StructuredData map.
92       */
93      public StructuredDataMessage(final StructuredDataId id, final String msg, final String type,
94                                   final Map<String, String> data) {
95          super(data);
96          this.id = id;
97          this.message = msg;
98          this.type = type;
99      }
100 
101 
102     /**
103      * Constructor based on a StructuredDataMessage.
104      * @param msg The StructuredDataMessage.
105      * @param map The StructuredData map.
106      */
107     private StructuredDataMessage(final StructuredDataMessage msg, final Map<String, String> map) {
108         super(map);
109         this.id = msg.id;
110         this.message = msg.message;
111         this.type = msg.type;
112     }
113 
114 
115     /**
116      * Basic constructor.
117      */
118     protected StructuredDataMessage() {
119 
120     }
121 
122     /**
123      * Returns the supported formats.
124      * @return An array of the supported format names.
125      */
126     @Override
127     public String[] getFormats() {
128         final String[] formats = new String[Format.values().length];
129         int i = 0;
130         for (final Format format : Format.values()) {
131             formats[i++] = format.name();
132         }
133         return formats;
134     }
135 
136     /**
137      * Returns the id.
138      * @return the StructuredDataId.
139      */
140     public StructuredDataId getId() {
141         return id;
142     }
143 
144     /**
145      * Set the id from a String.
146      * @param id The String id.
147      */
148     protected void setId(final String id) {
149         this.id = new StructuredDataId(id, null, null);
150     }
151 
152     /**
153      * Set the id.
154      * @param id The StructuredDataId.
155      */
156     protected void setId(final StructuredDataId id) {
157         this.id = id;
158     }
159 
160     /**
161      * Set the type.
162      * @return the type.
163      */
164     public String getType() {
165         return type;
166     }
167 
168     protected void setType(final String type) {
169         if (type.length() > MAX_LENGTH) {
170             throw new IllegalArgumentException("Structured data type exceeds maximum length of 32 characters: " + type);
171         }
172         this.type = type;
173     }
174     /**
175      * Returns the message.
176      * @return the message.
177      */
178     @Override
179     public String getFormat() {
180         return message;
181     }
182 
183     protected void setMessageFormat(final String msg) {
184         this.message = msg;
185     }
186 
187 
188     @Override
189     protected void validate(final String key, final String value) {
190         if (key.length() > MAX_LENGTH) {
191             throw new IllegalArgumentException("Structured data keys are limited to 32 characters. key: " + key +
192                 " value: " + value);
193         }
194     }
195 
196     /**
197      * Format the Structured data as described in RFC 5424.
198      *
199      * @return The formatted String.
200      */
201     @Override
202     public String asString() {
203         return asString(Format.FULL, null);
204     }
205 
206     /**
207      * Format the Structured data as described in RFC 5424.
208      *
209      * @param format The format identifier. Ignored in this implementation.
210      * @return The formatted String.
211      */
212 
213     @Override
214     public String asString(final String format) {
215         try {
216             return asString(EnglishEnums.valueOf(Format.class, format), null);
217         } catch (final IllegalArgumentException ex) {
218             return asString();
219         }
220     }
221 
222     /**
223      * Format the Structured data as described in RFC 5424.
224      *
225      * @param format           "full" will include the type and message. null will return only the STRUCTURED-DATA as
226      *                         described in RFC 5424
227      * @param structuredDataId The SD-ID as described in RFC 5424. If null the value in the StructuredData
228      *                         will be used.
229      * @return The formatted String.
230      */
231     public final String asString(final Format format, final StructuredDataId structuredDataId) {
232         final StringBuilder sb = new StringBuilder();
233         final boolean full = Format.FULL.equals(format);
234         if (full) {
235             final String type = getType();
236             if (type == null) {
237                 return sb.toString();
238             }
239             sb.append(getType()).append(" ");
240         }
241         StructuredDataId id = getId();
242         if (id != null) {
243             id = id.makeId(structuredDataId);
244         } else {
245             id = structuredDataId;
246         }
247         if (id == null || id.getName() == null) {
248             return sb.toString();
249         }
250         sb.append("[");
251         sb.append(id);
252         sb.append(" ");
253         appendMap(sb);
254         sb.append("]");
255         if (full) {
256             final String msg = getFormat();
257             if (msg != null) {
258                 sb.append(" ").append(msg);
259             }
260         }
261         return sb.toString();
262     }
263 
264     /**
265      * Format the message and return it.
266      * @return the formatted message.
267      */
268     @Override
269     public String getFormattedMessage() {
270         return asString(Format.FULL, null);
271     }
272 
273     /**
274      * Format the message according the the specified format.
275      * @param formats An array of Strings that provide extra information about how to format the message.
276      * StructuredDataMessage accepts only a format of "FULL" which will cause the event type to be
277      * prepended and the event message to be appended. Specifying any other value will cause only the
278      * StructuredData to be included. The default is "FULL".
279      *
280      * @return the formatted message.
281      */
282     @Override
283     public String getFormattedMessage(final String[] formats) {
284         if (formats != null && formats.length > 0) {
285             for (final String format : formats) {
286                 if (Format.XML.name().equalsIgnoreCase(format)) {
287                     return asXML();
288                 } else if (Format.FULL.name().equalsIgnoreCase(format)) {
289                     return asString(Format.FULL, null);
290                 }
291             }
292             return asString(null, null);
293         } else {
294             return asString(Format.FULL, null);
295         }
296     }
297 
298     private String asXML() {
299         final StringBuilder sb = new StringBuilder();
300         final StructuredDataId id = getId();
301         if (id == null || id.getName() == null || type == null) {
302             return sb.toString();
303         }
304         sb.append("<StructuredData>\n");
305         sb.append("<type>").append(type).append("</type>\n");
306         sb.append("<id>").append(id).append("</id>\n");
307         super.asXML(sb);
308         sb.append("</StructuredData>\n");
309         return sb.toString();
310     }
311 
312     @Override
313     public String toString() {
314         return asString(null, null);
315     }
316 
317 
318     @Override
319     public MapMessage newInstance(final Map<String, String> map) {
320         return new StructuredDataMessage(this, map);
321     }
322 
323     @Override
324     public boolean equals(final Object o) {
325         if (this == o) {
326             return true;
327         }
328         if (o == null || getClass() != o.getClass()) {
329             return false;
330         }
331 
332         final StructuredDataMessage that = (StructuredDataMessage) o;
333 
334         if (!super.equals(o)) {
335             return false;
336         }
337         if (type != null ? !type.equals(that.type) : that.type != null) {
338             return false;
339         }
340         if (id != null ? !id.equals(that.id) : that.id != null) {
341             return false;
342         }
343         if (message != null ? !message.equals(that.message) : that.message != null) {
344             return false;
345         }
346 
347         return true;
348     }
349 
350     @Override
351     public int hashCode() {
352         int result = super.hashCode();
353         result = HASHVAL * result + (type != null ? type.hashCode() : 0);
354         result = HASHVAL * result + (id != null ? id.hashCode() : 0);
355         result = HASHVAL * result + (message != null ? message.hashCode() : 0);
356         return result;
357     }
358 }