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 }