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.LinkedHashMap;
020    import java.util.List;
021    import java.util.Map;
022    
023    public class EnumDescriptor implements TypeDescriptor {
024    
025        private String name;
026        private Map<String,EnumFieldDescriptor> fields= new LinkedHashMap<String, EnumFieldDescriptor>();
027        private final ProtoDescriptor protoDescriptor;
028        private final MessageDescriptor parent;
029        private Map<String, OptionDescriptor> options = new LinkedHashMap<String, OptionDescriptor>();
030    
031        public EnumDescriptor(ProtoDescriptor protoDescriptor, MessageDescriptor parent) {
032            this.protoDescriptor = protoDescriptor;
033            this.parent = parent;
034        }
035    
036        public String getName() {
037            return name;
038        }
039    
040        public Map<String,EnumFieldDescriptor> getFields() {
041            return fields;
042        }
043    
044        public void setName(String name) {
045            this.name = name;
046        }
047    
048        public void setFields(Map<String,EnumFieldDescriptor> fields) {
049            this.fields = fields;
050        }
051        public ProtoDescriptor getProtoDescriptor() {
052            return protoDescriptor;
053        }
054    
055        private String getOption(Map<String, OptionDescriptor> options, String optionName, String defaultValue) {
056            OptionDescriptor optionDescriptor = options.get(optionName);
057            if (optionDescriptor == null) {
058                return defaultValue;
059            }
060            return optionDescriptor.getValue();
061        }
062        
063        private String constantToUCamelCase(String name) {
064            boolean upNext=true;
065            StringBuilder sb = new StringBuilder();
066            for (int i = 0; i < name.length(); i++) {
067                char c = name.charAt(i);
068                if( Character.isJavaIdentifierPart(c) && Character.isLetterOrDigit(c)) {
069                    if( upNext ) {
070                        c = Character.toUpperCase(c);
071                        upNext=false;
072                    } else {
073                        c = Character.toLowerCase(c);
074                    }
075                    sb.append(c);
076                } else {
077                    upNext=true;
078                }
079            }
080            return sb.toString();
081        }
082        
083        public void validate(List<String> errors) {
084            String createMessage = getOption(getOptions(), "java_create_message", null);        
085            if( "true".equals(createMessage) ) {
086                for (EnumFieldDescriptor field : getFields().values()) {
087                    String type = constantToUCamelCase(field.getName());
088                    
089                    TypeDescriptor typeDescriptor=null;
090                    // Find the type def for that guy..
091                    if( parent!=null ) {
092                        typeDescriptor = parent.getType(type);
093                    }
094                    if( typeDescriptor == null ) {
095                        typeDescriptor = protoDescriptor.getType(type);
096                    }
097                    if( typeDescriptor == null ) {
098                        errors.add("ENUM constant '"+field.getName()+"' did not find expected associated message: "+type);
099                    } else {
100                        field.associate(typeDescriptor);
101                        typeDescriptor.associate(field);
102                    }
103                }
104            }
105        }
106    
107        public MessageDescriptor getParent() {
108            return parent;
109        }
110    
111        public String getQName() {
112            if( parent==null ) {
113                return name;
114            } else {
115                return parent.getQName()+"."+name;
116            }
117        }
118    
119        public boolean isEnum() {
120            return true;
121        }
122    
123        public Map<String, OptionDescriptor> getOptions() {
124            return options;
125        }
126    
127        public void setOptions(Map<String, OptionDescriptor> options) {
128            this.options = options;
129        }
130    
131        public void associate(EnumFieldDescriptor desc) {
132            throw new RuntimeException("not supported.");
133        }
134    
135    
136    }