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