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.io.Serializable;
20  
21  import org.apache.logging.log4j.util.StringBuilderFormattable;
22  import org.apache.logging.log4j.util.Strings;
23  
24  /**
25   * The StructuredData identifier.
26   */
27  public class StructuredDataId implements Serializable, StringBuilderFormattable {
28  
29      /**
30       * RFC 5424 Time Quality.
31       */
32      public static final StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null, new String[] {
33              "tzKnown", "isSynced", "syncAccuracy"});
34  
35      /**
36       * RFC 5424 Origin.
37       */
38      public static final StructuredDataId ORIGIN = new StructuredDataId("origin", null, new String[] {"ip",
39              "enterpriseId", "software", "swVersion"});
40  
41      /**
42       * RFC 5424 Meta.
43       */
44      public static final StructuredDataId META = new StructuredDataId("meta", null, new String[] {"sequenceId",
45              "sysUpTime", "language"});
46  
47      /**
48       * Reserved enterprise number.
49       */
50      public static final int RESERVED = -1;
51  
52      private static final long serialVersionUID = 9031746276396249990L;
53      private static final int MAX_LENGTH = 32;
54      private static final String AT_SIGN = "@";
55  
56      private final String name;
57      private final int enterpriseNumber;
58      private final String[] required;
59      private final String[] optional;
60  
61      /**
62       * Creates a StructuredDataId based on the name.
63       * @param name The Structured Data Element name (maximum length is 32)
64       * @since 2.9
65       */
66      public StructuredDataId(final String name) {
67          this(name, null, null, MAX_LENGTH);
68      }
69  
70      /**
71       * Creates a StructuredDataId based on the name.
72       * @param name The Structured Data Element name.
73       * @param maxLength The maximum length of the name.
74       * @since 2.9
75       */
76      public StructuredDataId(final String name, final int maxLength) {
77          this(name, null, null, maxLength);
78      }
79  
80      /**
81       *
82       * @param name
83       * @param required
84       * @param optional
85       */
86      public StructuredDataId(final String name, final String[] required, final String[] optional) {
87          this(name, required, optional, MAX_LENGTH);
88      }
89  
90      /**
91       * A Constructor that helps conformance to RFC 5424.
92       *
93       * @param name The name portion of the id.
94       * @param required The list of keys that are required for this id.
95       * @param optional The list of keys that are optional for this id.
96       * @since 2.9
97       */
98      public StructuredDataId(final String name, final String[] required, final String[] optional,
99                                 final int maxLength) {
100         int index = -1;
101         if (name != null) {
102             if (maxLength > 0 && name.length() > MAX_LENGTH) {
103                 throw new IllegalArgumentException(String.format("Length of id %s exceeds maximum of %d characters",
104                         name, maxLength));
105             }
106             index = name.indexOf(AT_SIGN);
107         }
108 
109         if (index > 0) {
110             this.name = name.substring(0, index);
111             this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
112         } else {
113             this.name = name;
114             this.enterpriseNumber = RESERVED;
115         }
116         this.required = required;
117         this.optional = optional;
118     }
119 
120     /**
121      * A Constructor that helps conformance to RFC 5424.
122      *
123      * @param name The name portion of the id.
124      * @param enterpriseNumber The enterprise number.
125      * @param required The list of keys that are required for this id.
126      * @param optional The list of keys that are optional for this id.
127      */
128     public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
129                             final String[] optional) {
130         this(name, enterpriseNumber, required, optional, MAX_LENGTH);
131     }
132 
133     /**
134      * A Constructor that helps conformance to RFC 5424.
135      *
136      * @param name The name portion of the id.
137      * @param enterpriseNumber The enterprise number.
138      * @param required The list of keys that are required for this id.
139      * @param optional The list of keys that are optional for this id.
140      * @param maxLength The maximum length of the StructuredData Id key.
141      * @since 2.9
142      */
143     public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
144             final String[] optional, final int maxLength) {
145         if (name == null) {
146             throw new IllegalArgumentException("No structured id name was supplied");
147         }
148         if (name.contains(AT_SIGN)) {
149             throw new IllegalArgumentException("Structured id name cannot contain an " + Strings.quote(AT_SIGN));
150         }
151         if (enterpriseNumber <= 0) {
152             throw new IllegalArgumentException("No enterprise number was supplied");
153         }
154         this.name = name;
155         this.enterpriseNumber = enterpriseNumber;
156         final String id = name + AT_SIGN + enterpriseNumber;
157         if (maxLength > 0 && id.length() > maxLength) {
158             throw new IllegalArgumentException("Length of id exceeds maximum of " + maxLength + " characters: " + id);
159         }
160         this.required = required;
161         this.optional = optional;
162     }
163 
164     /**
165      * Creates an id using another id to supply default values.
166      *
167      * @param id The original StructuredDataId.
168      * @return the new StructuredDataId.
169      */
170     public StructuredDataId makeId(final StructuredDataId id) {
171         if (id == null) {
172             return this;
173         }
174         return makeId(id.getName(), id.getEnterpriseNumber());
175     }
176 
177     /**
178      * Creates an id based on the current id.
179      *
180      * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
181      * @param anEnterpriseNumber The enterprise number.
182      * @return a StructuredDataId.
183      */
184     public StructuredDataId makeId(final String defaultId, final int anEnterpriseNumber) {
185         String id;
186         String[] req;
187         String[] opt;
188         if (anEnterpriseNumber <= 0) {
189             return this;
190         }
191         if (this.name != null) {
192             id = this.name;
193             req = this.required;
194             opt = this.optional;
195         } else {
196             id = defaultId;
197             req = null;
198             opt = null;
199         }
200 
201         return new StructuredDataId(id, anEnterpriseNumber, req, opt);
202     }
203 
204     /**
205      * Returns a list of required keys.
206      *
207      * @return a List of required keys or null if none have been provided.
208      */
209     public String[] getRequired() {
210         return required;
211     }
212 
213     /**
214      * Returns a list of optional keys.
215      *
216      * @return a List of optional keys or null if none have been provided.
217      */
218     public String[] getOptional() {
219         return optional;
220     }
221 
222     /**
223      * Returns the StructuredDataId name.
224      *
225      * @return the StructuredDataId name.
226      */
227     public String getName() {
228         return name;
229     }
230 
231     /**
232      * Returns the enterprise number.
233      *
234      * @return the enterprise number.
235      */
236     public int getEnterpriseNumber() {
237         return enterpriseNumber;
238     }
239 
240     /**
241      * Indicates if the id is reserved.
242      *
243      * @return true if the id uses the reserved enterprise number, false otherwise.
244      */
245     public boolean isReserved() {
246         return enterpriseNumber <= 0;
247     }
248 
249     @Override
250     public String toString() {
251         final StringBuilder sb = new StringBuilder(name.length() + 10);
252         formatTo(sb);
253         return sb.toString();
254     }
255 
256     @Override
257     public void formatTo(final StringBuilder buffer) {
258         if (isReserved()) {
259             buffer.append(name);
260         } else {
261             buffer.append(name).append(AT_SIGN).append(enterpriseNumber);
262         }
263     }
264 }