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 }