001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.message; 018 019import java.io.Serializable; 020 021import org.apache.logging.log4j.util.StringBuilderFormattable; 022import org.apache.logging.log4j.util.Strings; 023 024/** 025 * The StructuredData identifier. 026 */ 027public class StructuredDataId implements Serializable, StringBuilderFormattable { 028 029 /** 030 * RFC 5424 Time Quality. 031 */ 032 public static final StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null, new String[] { 033 "tzKnown", "isSynced", "syncAccuracy"}); 034 035 /** 036 * RFC 5424 Origin. 037 */ 038 public static final StructuredDataId ORIGIN = new StructuredDataId("origin", null, new String[] {"ip", 039 "enterpriseId", "software", "swVersion"}); 040 041 /** 042 * RFC 5424 Meta. 043 */ 044 public static final StructuredDataId META = new StructuredDataId("meta", null, new String[] {"sequenceId", 045 "sysUpTime", "language"}); 046 047 /** 048 * Reserved enterprise number. 049 */ 050 public static final int RESERVED = -1; 051 052 private static final long serialVersionUID = 9031746276396249990L; 053 private static final int MAX_LENGTH = 32; 054 private static final String AT_SIGN = "@"; 055 056 private final String name; 057 private final int enterpriseNumber; 058 private final String[] required; 059 private final String[] optional; 060 061 /** 062 * Creates a StructuredDataId based on the name. 063 * @param name The Structured Data Element name (maximum length is 32) 064 * @since 2.9 065 */ 066 public StructuredDataId(final String name) { 067 this(name, null, null, MAX_LENGTH); 068 } 069 070 /** 071 * Creates a StructuredDataId based on the name. 072 * @param name The Structured Data Element name. 073 * @param maxLength The maximum length of the name. 074 * @since 2.9 075 */ 076 public StructuredDataId(final String name, final int maxLength) { 077 this(name, null, null, maxLength); 078 } 079 080 /** 081 * 082 * @param name 083 * @param required 084 * @param optional 085 */ 086 public StructuredDataId(final String name, final String[] required, final String[] optional) { 087 this(name, required, optional, MAX_LENGTH); 088 } 089 090 /** 091 * A Constructor that helps conformance to RFC 5424. 092 * 093 * @param name The name portion of the id. 094 * @param required The list of keys that are required for this id. 095 * @param optional The list of keys that are optional for this id. 096 * @since 2.9 097 */ 098 public StructuredDataId(final String name, final String[] required, final String[] optional, 099 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}