/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fusesource.hawtbuf.proto.compiler; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class MessageDescriptor implements TypeDescriptor { private String name; private ExtensionsDescriptor extensions; private Map<String,FieldDescriptor> fields = new LinkedHashMap<String, FieldDescriptor>(); private Map<String,MessageDescriptor> messages = new LinkedHashMap<String,MessageDescriptor>(); private Map<String,EnumDescriptor> enums = new LinkedHashMap<String, EnumDescriptor>(); private final ProtoDescriptor protoDescriptor; private List<MessageDescriptor> extendsList = new ArrayList<MessageDescriptor>(); private Map<String, OptionDescriptor> options = new LinkedHashMap<String, OptionDescriptor>(); private List<EnumFieldDescriptor> associatedEnumFieldDescriptors = new ArrayList<EnumFieldDescriptor>(); private final MessageDescriptor parent; private MessageDescriptor baseType; public MessageDescriptor(ProtoDescriptor protoDescriptor, MessageDescriptor parent) { this.protoDescriptor = protoDescriptor; this.parent = parent; } public void validate(List<String> errors) { String baseName = getOption(getOptions(), "base_type", null); if( baseName!=null ) { if( baseType==null ) { baseType = (MessageDescriptor) getType(baseName); } if( baseType == null ) { baseType = (MessageDescriptor) getProtoDescriptor().getType(baseName); } if( baseType == null ) { errors.add("base_type option not valid, type not found: "+baseName); } // Assert that all the fields in the base type are defined in this message defintion too. HashSet<String> baseFieldNames = new HashSet<String>(baseType.getFields().keySet()); baseFieldNames.removeAll(getFields().keySet()); // Some fields were not defined in the sub class.. if( !baseFieldNames.isEmpty() ) { for (String fieldName : baseFieldNames) { errors.add("base_type "+baseName+" field "+fieldName+" not defined in "+getName()); } } } for (FieldDescriptor field : fields.values()) { field.validate(errors); } for (EnumDescriptor o : enums.values()) { o.validate(errors); } for (MessageDescriptor o : messages.values()) { o.validate(errors); } } public String getOption(Map<String, OptionDescriptor> options, String optionName, String defaultValue) { OptionDescriptor optionDescriptor = options.get(optionName); if (optionDescriptor == null) { return defaultValue; } return optionDescriptor.getValue(); } public void setName(String name) { this.name = name; } public void setExtensions(ExtensionsDescriptor extensions) { this.extensions = extensions; } public void setExtends(List<MessageDescriptor> extendsList) { this.extendsList = extendsList; } public List<MessageDescriptor> getExtends() { return extendsList; } public void setFields(Map<String,FieldDescriptor> fields) { this.fields = fields; } public void setMessages(Map<String,MessageDescriptor> messages) { this.messages = messages; } public void setEnums(Map<String,EnumDescriptor> enums) { this.enums = enums; } public String getName() { return name; } public String getQName() { if( parent==null ) { return name; } else { return parent.getQName()+"."+name; } } public ExtensionsDescriptor getExtensions() { return extensions; } public Map<String,FieldDescriptor> getFields() { return fields; } public Map<String,MessageDescriptor> getMessages() { return messages; } public Map<String,EnumDescriptor> getEnums() { return enums; } public ProtoDescriptor getProtoDescriptor() { return protoDescriptor; } public Map<String, OptionDescriptor> getOptions() { return options; } public void setOptions(Map<String, OptionDescriptor> options) { this.options = options; } public MessageDescriptor getParent() { return parent; } public TypeDescriptor getType(String t) { for (MessageDescriptor o : messages.values()) { if( t.equals(o.getName()) ) { return o; } if( t.startsWith(o.getName()+".") ) { return o.getType( t.substring(o.getName().length()+1) ); } } for (EnumDescriptor o : enums.values()) { if( t.equals(o.getName()) ) { return o; } } return null; } public boolean isEnum() { return false; } public MessageDescriptor getBaseType() { return baseType; } public void associate(EnumFieldDescriptor desc) { associatedEnumFieldDescriptors.add(desc); } public List<EnumFieldDescriptor> getAssociatedEnumFieldDescriptors() { return associatedEnumFieldDescriptors; } }