001/*
002 * Copyright (C) 2012 Facebook, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may
005 * not use this file except in compliance with the License. You may obtain
006 * a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations
014 * under the License.
015 */
016package com.facebook.swift.codec.metadata;
017
018import com.google.common.base.Function;
019import com.google.common.base.Optional;
020import com.google.common.collect.Collections2;
021import com.google.common.collect.ImmutableList;
022import com.google.common.collect.ImmutableSortedMap;
023import com.google.common.reflect.TypeToken;
024
025import javax.annotation.concurrent.Immutable;
026
027import java.lang.reflect.Type;
028import java.util.Collection;
029import java.util.List;
030import java.util.SortedMap;
031
032import static com.facebook.swift.codec.metadata.ThriftFieldMetadata.isTypePredicate;
033import static com.google.common.base.Preconditions.checkNotNull;
034import static com.google.common.collect.Maps.uniqueIndex;
035
036@Immutable
037public class ThriftStructMetadata
038{
039    public static enum MetadataType {
040        STRUCT, UNION;
041    }
042
043    private final String structName;
044
045    private final MetadataType metadataType;
046    private final Optional<ThriftMethodInjection> builderMethod;
047    private final ImmutableList<String> documentation;
048
049    private final SortedMap<Short, ThriftFieldMetadata> fields;
050
051    private final Optional<ThriftConstructorInjection> constructorInjection;
052
053    private final List<ThriftMethodInjection> methodInjections;
054    private final Type structType;
055    private final Type builderType;
056
057    public ThriftStructMetadata(
058            String structName,
059            Type structType,
060            Type builderType,
061            MetadataType metadataType,
062            Optional<ThriftMethodInjection> builderMethod,
063            List<String> documentation,
064            List<ThriftFieldMetadata> fields,
065            Optional<ThriftConstructorInjection> constructorInjection,
066            List<ThriftMethodInjection> methodInjections)
067    {
068        this.builderType = builderType;
069        this.builderMethod = checkNotNull(builderMethod, "builderMethod is null");
070        this.structName = checkNotNull(structName, "structName is null");
071        this.metadataType = checkNotNull(metadataType, "metadataType is null");
072        this.structType = checkNotNull(structType, "structType is null");
073        this.constructorInjection = checkNotNull(constructorInjection, "constructorInjection is null");
074        this.documentation = ImmutableList.copyOf(checkNotNull(documentation, "documentation is null"));
075        this.fields = ImmutableSortedMap.copyOf(uniqueIndex(checkNotNull(fields, "fields is null"), new Function<ThriftFieldMetadata, Short>()
076        {
077            @Override
078            public Short apply(ThriftFieldMetadata input)
079            {
080                return input.getId();
081            }
082        }));
083        this.methodInjections = ImmutableList.copyOf(checkNotNull(methodInjections, "methodInjections is null"));
084    }
085
086    public String getStructName()
087    {
088        return structName;
089    }
090
091    public Type getStructType()
092    {
093        return structType;
094    }
095
096    public Class<?> getStructClass()
097    {
098        return TypeToken.of(structType).getRawType();
099    }
100
101    public Type getBuilderType()
102    {
103        return builderType;
104    }
105
106    public Class<?> getBuilderClass()
107    {
108        return builderType == null ? null : TypeToken.of(builderType).getRawType();
109    }
110
111    public MetadataType getMetadataType()
112    {
113        return metadataType;
114    }
115
116    public Optional<ThriftMethodInjection> getBuilderMethod()
117    {
118        return builderMethod;
119    }
120
121    public ThriftFieldMetadata getField(int id)
122    {
123        return fields.get((short) id);
124    }
125
126    public ImmutableList<String> getDocumentation()
127    {
128        return documentation;
129    }
130
131    public Collection<ThriftFieldMetadata> getFields(FieldKind type)
132    {
133        return Collections2.filter(getFields(), isTypePredicate(type));
134    }
135
136    public Collection<ThriftFieldMetadata> getFields()
137    {
138        return fields.values();
139    }
140
141    public Optional<ThriftConstructorInjection> getConstructorInjection()
142    {
143        return constructorInjection;
144    }
145
146    public List<ThriftMethodInjection> getMethodInjections()
147    {
148        return methodInjections;
149    }
150
151    public boolean isException()
152    {
153        return Exception.class.isAssignableFrom(getStructClass());
154    }
155
156    public boolean isUnion()
157    {
158        return !isException() && getMetadataType() == MetadataType.UNION;
159    }
160
161    public boolean isStruct()
162    {
163        return !isException() && getMetadataType() == MetadataType.STRUCT;
164    }
165
166    @Override
167    public String toString()
168    {
169        final StringBuilder sb = new StringBuilder();
170        sb.append("ThriftStructMetadata");
171        sb.append("{structName='").append(structName).append('\'');
172        sb.append(", structType=").append(structType);
173        sb.append(", builderType=").append(builderType);
174        sb.append(", builderMethod=").append(builderMethod);
175        sb.append(", fields=").append(fields);
176        sb.append(", constructorInjection=").append(constructorInjection);
177        sb.append(", methodInjections=").append(methodInjections);
178        sb.append('}');
179        return sb.toString();
180    }
181}