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