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.fusesource.hawtbuf.proto.compiler;
018    
019    import java.util.ArrayList;
020    import java.util.HashSet;
021    import java.util.LinkedHashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    
026    public class MessageDescriptor implements TypeDescriptor {
027    
028        private String name;
029        private ExtensionsDescriptor extensions;
030        private Map<String,FieldDescriptor> fields = new LinkedHashMap<String, FieldDescriptor>();
031        private Map<String,MessageDescriptor> messages = new LinkedHashMap<String,MessageDescriptor>();
032        private Map<String,EnumDescriptor> enums = new LinkedHashMap<String, EnumDescriptor>();
033        private final ProtoDescriptor protoDescriptor;
034        private List<MessageDescriptor> extendsList = new ArrayList<MessageDescriptor>();
035        private Map<String, OptionDescriptor> options = new LinkedHashMap<String, OptionDescriptor>();
036        private List<EnumFieldDescriptor> associatedEnumFieldDescriptors = new ArrayList<EnumFieldDescriptor>();
037        
038        private final MessageDescriptor parent;
039            private MessageDescriptor baseType;
040    
041        public MessageDescriptor(ProtoDescriptor protoDescriptor, MessageDescriptor parent) {
042            this.protoDescriptor = protoDescriptor;
043            this.parent = parent;
044        }
045        
046        public void validate(List<String> errors) {
047            String baseName = getOption(getOptions(), "base_type", null);
048            if( baseName!=null ) {
049                if( baseType==null ) {
050                    baseType = (MessageDescriptor) getType(baseName);
051                }
052                if( baseType == null ) {
053                    baseType = (MessageDescriptor) getProtoDescriptor().getType(baseName);
054                }
055                if( baseType == null ) {
056                    errors.add("base_type option not valid, type not found: "+baseName);
057                }
058                
059                // Assert that all the fields in the base type are defined in this message defintion too.
060                HashSet<String> baseFieldNames = new HashSet<String>(baseType.getFields().keySet());
061                baseFieldNames.removeAll(getFields().keySet());
062                
063                // Some fields were not defined in the sub class..
064                if( !baseFieldNames.isEmpty() ) {
065                    for (String fieldName : baseFieldNames) {
066                        errors.add("base_type "+baseName+" field "+fieldName+" not defined in "+getName());
067                                    }
068                }
069            }
070    
071            for (FieldDescriptor field : fields.values()) {
072                field.validate(errors);
073            }
074            for (EnumDescriptor o : enums.values()) {
075                o.validate(errors);
076            }
077            for (MessageDescriptor o : messages.values()) {
078                o.validate(errors);
079            }
080        }
081        
082        public String getOption(Map<String, OptionDescriptor> options, String optionName, String defaultValue) {
083            OptionDescriptor optionDescriptor = options.get(optionName);
084            if (optionDescriptor == null) {
085                return defaultValue;
086            }
087            return optionDescriptor.getValue();
088        }
089    
090        public void setName(String name) {
091            this.name = name;
092        }
093    
094        public void setExtensions(ExtensionsDescriptor extensions) {
095            this.extensions = extensions;
096        }
097    
098        public void setExtends(List<MessageDescriptor> extendsList) {
099            this.extendsList = extendsList;
100        }
101        public List<MessageDescriptor> getExtends() {
102            return extendsList;
103        }
104    
105        public void setFields(Map<String,FieldDescriptor> fields) {
106            this.fields = fields;
107        }
108    
109        public void setMessages(Map<String,MessageDescriptor> messages) {
110            this.messages = messages;
111        }
112    
113        public void setEnums(Map<String,EnumDescriptor> enums) {
114            this.enums = enums;
115        }
116    
117        public String getName() {
118            return name;
119        }
120    
121        public String getQName() {
122            if( parent==null ) {
123                return name;
124            } else {
125                return parent.getQName()+"."+name;
126            }
127        }
128    
129        public ExtensionsDescriptor getExtensions() {
130            return extensions;
131        }
132    
133        public Map<String,FieldDescriptor> getFields() {
134            return fields;
135        }
136    
137        public Map<String,MessageDescriptor> getMessages() {
138            return messages;
139        }
140    
141        public Map<String,EnumDescriptor> getEnums() {
142            return enums;
143        }
144    
145        public ProtoDescriptor getProtoDescriptor() {
146            return protoDescriptor;
147        }
148    
149        public Map<String, OptionDescriptor> getOptions() {
150            return options;
151        }
152    
153        public void setOptions(Map<String, OptionDescriptor> options) {
154            this.options = options;
155        }
156    
157        public MessageDescriptor getParent() {
158            return parent;
159        }
160    
161        public TypeDescriptor getType(String t) {
162            for (MessageDescriptor o : messages.values()) {
163                if( t.equals(o.getName()) ) {
164                    return o;
165                }
166                if( t.startsWith(o.getName()+".") ) {
167                    return o.getType( t.substring(o.getName().length()+1) );
168                }
169            }
170            for (EnumDescriptor o : enums.values()) {
171                if( t.equals(o.getName()) ) {
172                    return o;
173                }
174            }
175            return null;
176        }
177    
178        public boolean isEnum() {
179            return false;
180        }
181    
182            public MessageDescriptor getBaseType() {
183                    return baseType;
184            }
185    
186        public void associate(EnumFieldDescriptor desc) {
187            associatedEnumFieldDescriptors.add(desc);
188        }
189    
190        public List<EnumFieldDescriptor> getAssociatedEnumFieldDescriptors() {
191            return associatedEnumFieldDescriptors;
192        }
193    
194    }