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
021/**
022 * The StructuredData identifier.
023 */
024public class StructuredDataId implements Serializable {
025
026    private static final String AT = "@";
027
028    /**
029     * RFC 5424 Time Quality.
030     */
031    public static final StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null,
032        new String[]{"tzKnown", "isSynced", "syncAccuracy"});
033    
034    /**
035     * RFC 5424 Origin.
036     */
037    public static final StructuredDataId ORIGIN = new StructuredDataId("origin", null,
038        new String[]{"ip", "enterpriseId", "software", "swVersion"});
039    
040    /**
041     * RFC 5424 Meta.
042     */
043    public static final StructuredDataId META = new StructuredDataId("meta", null,
044        new String[]{"sequenceId", "sysUpTime", "language"});
045
046    /**
047     * Reserved enterprise number.
048     */
049    public static final int RESERVED = -1;
050
051    private static final long serialVersionUID = 9031746276396249990L;
052    private static final int MAX_LENGTH = 32;
053
054    private final String name;
055    private final int enterpriseNumber;
056    private final String[] required;
057    private final String[] optional;
058
059
060    protected StructuredDataId(final String name, final String[] required, final String[] optional) {
061        int index = -1;
062        if (name != null) {
063            if (name.length() > MAX_LENGTH) {
064                throw new IllegalArgumentException(String.format("Length of id %s exceeds maximum of %d characters",
065                        name, MAX_LENGTH));
066            }
067            index = name.indexOf(AT);
068        }
069
070        if (index > 0) {
071            this.name = name.substring(0, index);
072            this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
073        } else {
074            this.name = name;
075            this.enterpriseNumber = RESERVED;
076        }
077        this.required = required;
078        this.optional = optional;
079    }
080
081    /**
082     * A Constructor that helps conformance to RFC 5424.
083     *
084     * @param name             The name portion of the id.
085     * @param enterpriseNumber The enterprise number.
086     * @param required         The list of keys that are required for this id.
087     * @param optional         The list of keys that are optional for this id.
088     */
089    public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
090                            final String[] optional) {
091        if (name == null) {
092            throw new IllegalArgumentException("No structured id name was supplied");
093        }
094        if (name.contains(AT)) {
095            throw new IllegalArgumentException("Structured id name cannot contain an '" + AT + "'");
096        }
097        if (enterpriseNumber <= 0) {
098            throw new IllegalArgumentException("No enterprise number was supplied");
099        }
100        this.name = name;
101        this.enterpriseNumber = enterpriseNumber;
102        final String id = enterpriseNumber < 0 ? name : name + AT + enterpriseNumber;
103        if (id.length() > MAX_LENGTH) {
104            throw new IllegalArgumentException("Length of id exceeds maximum of 32 characters: " + id);
105        }
106        this.required = required;
107        this.optional = optional;
108    }
109
110    /**
111     * Creates an id using another id to supply default values.
112     * @param id The original StructuredDataId.
113     * @return the new StructuredDataId.
114     */
115    public StructuredDataId makeId(final StructuredDataId id) {
116        if (id == null) {
117            return this;
118        }
119        return makeId(id.getName(), id.getEnterpriseNumber());
120    }
121
122    /**
123     * Creates an id based on the current id.
124     * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
125     * @param enterpriseNumber The enterprise number.
126     * @return a StructuredDataId.
127     */
128    public StructuredDataId makeId(final String defaultId, final int enterpriseNumber) {
129        String id;
130        String[] req;
131        String[] opt;
132        if (enterpriseNumber <= 0) {
133            return this;
134        }
135        if (this.name != null) {
136            id = this.name;
137            req = this.required;
138            opt = this.optional;
139        } else {
140            id = defaultId;
141            req = null;
142            opt = null;
143        }
144
145        return new StructuredDataId(id, enterpriseNumber, req, opt);
146    }
147
148    /**
149     * Returns a list of required keys.
150     * @return a List of required keys or null if none have been provided.
151     */
152    public String[] getRequired() {
153        return required;
154    }
155
156    /**
157     * Returns a list of optional keys.
158     * @return a List of optional keys or null if none have been provided.
159     */
160    public String[] getOptional() {
161        return optional;
162    }
163
164    /**
165     * Returns the StructuredDataId name.
166     * @return the StructuredDataId name.
167     */
168    public String getName() {
169        return name;
170    }
171
172    /**
173     * Returns the enterprise number.
174     * @return the enterprise number.
175     */
176    public int getEnterpriseNumber() {
177        return enterpriseNumber;
178    }
179
180    /**
181     * Indicates if the id is reserved.
182     * @return true if the id uses the reserved enterprise number, false otherwise.
183     */
184    public boolean isReserved() {
185        return enterpriseNumber <= 0;
186    }
187
188    @Override
189    public String toString() {
190        return isReserved() ? name : name + AT + enterpriseNumber;
191    }
192}