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, int maxLength) {
99          int index = -1;
100         if (name != null) {
101             if (maxLength <= 0) {
102                 maxLength = MAX_LENGTH;
103             }
104             if (name.length() > maxLength) {
105                 throw new IllegalArgumentException(String.format("Length of id %s exceeds maximum of %d characters",
106                         name, maxLength));
107             }
108             index = name.indexOf(AT_SIGN);
109         }
110 
111         if (index > 0) {
112             this.name = name.substring(0, index);
113             this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
114         } else {
115             this.name = name;
116             this.enterpriseNumber = RESERVED;
117         }
118         this.required = required;
119         this.optional = optional;
120     }
121 
122     /**
123      * A Constructor that helps conformance to RFC 5424.
124      *
125      * @param name The name portion of the id.
126      * @param enterpriseNumber The enterprise number.
127      * @param required The list of keys that are required for this id.
128      * @param optional The list of keys that are optional for this id.
129      */
130     public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
131                             final String[] optional) {
132         this(name, enterpriseNumber, required, optional, MAX_LENGTH);
133     }
134 
135     /**
136      * A Constructor that helps conformance to RFC 5424.
137      *
138      * @param name The name portion of the id.
139      * @param enterpriseNumber The enterprise number.
140      * @param required The list of keys that are required for this id.
141      * @param optional The list of keys that are optional for this id.
142      * @param maxLength The maximum length of the StructuredData Id key.
143      * @since 2.9
144      */
145     public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
146             final String[] optional, final int maxLength) {
147         if (name == null) {
148             throw new IllegalArgumentException("No structured id name was supplied");
149         }
150         if (name.contains(AT_SIGN)) {
151             throw new IllegalArgumentException("Structured id name cannot contain an " + Strings.quote(AT_SIGN));
152         }
153         if (enterpriseNumber <= 0) {
154             throw new IllegalArgumentException("No enterprise number was supplied");
155         }
156         this.name = name;
157         this.enterpriseNumber = enterpriseNumber;
158         final String id = name + AT_SIGN + enterpriseNumber;
159         if (maxLength > 0 && id.length() > maxLength) {
160             throw new IllegalArgumentException("Length of id exceeds maximum of " + maxLength + " characters: " + id);
161         }
162         this.required = required;
163         this.optional = optional;
164     }
165 
166     /**
167      * Creates an id using another id to supply default values.
168      *
169      * @param id The original StructuredDataId.
170      * @return the new StructuredDataId.
171      */
172     public StructuredDataId makeId(final StructuredDataId id) {
173         if (id == null) {
174             return this;
175         }
176         return makeId(id.getName(), id.getEnterpriseNumber());
177     }
178 
179     /**
180      * Creates an id based on the current id.
181      *
182      * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
183      * @param anEnterpriseNumber The enterprise number.
184      * @return a StructuredDataId.
185      */
186     public StructuredDataId makeId(final String defaultId, final int anEnterpriseNumber) {
187         String id;
188         String[] req;
189         String[] opt;
190         if (anEnterpriseNumber <= 0) {
191             return this;
192         }
193         if (this.name != null) {
194             id = this.name;
195             req = this.required;
196             opt = this.optional;
197         } else {
198             id = defaultId;
199             req = null;
200             opt = null;
201         }
202 
203         return new StructuredDataId(id, anEnterpriseNumber, req, opt);
204     }
205 
206     /**
207      * Returns a list of required keys.
208      *
209      * @return a List of required keys or null if none have been provided.
210      */
211     public String[] getRequired() {
212         return required;
213     }
214 
215     /**
216      * Returns a list of optional keys.
217      *
218      * @return a List of optional keys or null if none have been provided.
219      */
220     public String[] getOptional() {
221         return optional;
222     }
223 
224     /**
225      * Returns the StructuredDataId name.
226      *
227      * @return the StructuredDataId name.
228      */
229     public String getName() {
230         return name;
231     }
232 
233     /**
234      * Returns the enterprise number.
235      *
236      * @return the enterprise number.
237      */
238     public int getEnterpriseNumber() {
239         return enterpriseNumber;
240     }
241 
242     /**
243      * Indicates if the id is reserved.
244      *
245      * @return true if the id uses the reserved enterprise number, false otherwise.
246      */
247     public boolean isReserved() {
248         return enterpriseNumber <= 0;
249     }
250 
251     @Override
252     public String toString() {
253         final StringBuilder sb = new StringBuilder(name.length() + 10);
254         formatTo(sb);
255         return sb.toString();
256     }
257 
258     @Override
259     public void formatTo(final StringBuilder buffer) {
260         if (isReserved()) {
261             buffer.append(name);
262         } else {
263             buffer.append(name).append(AT_SIGN).append(enterpriseNumber);
264         }
265     }
266 }