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        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    }