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    import org.apache.logging.log4j.util.Strings;
022    
023    /**
024     * The StructuredData identifier.
025     */
026    public 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    }