PInterfaceDescriptor.java
/*
* Copyright 2015-2016 Providence Authors
*
* 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 net.morimekta.providence.descriptor;
import net.morimekta.providence.PMessage;
import net.morimekta.providence.PMessageBuilder;
import net.morimekta.providence.PMessageVariant;
import net.morimekta.util.collect.UnmodifiableList;
import net.morimekta.util.collect.UnmodifiableMap;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* The definition of a providence interface. This is a complete class,
* in order to minimize the need for generated code for interfaces.
*/
@Immutable
public class PInterfaceDescriptor<T extends PMessage<T>> extends PMessageDescriptor<T> {
private final PField<T>[] fields;
private final Map<Integer, PField<T>> fieldIdMap;
private final Map<String, PField<T>> fieldNameMap;
private final Map<String, PField<T>> fieldPojoNameMap;
private final List<PMessageDescriptorProvider<?>> possibleTypeProviders;
private final AtomicReference<List<PMessageDescriptor<?>>> possibleTypes;
public PInterfaceDescriptor(String programName,
String name,
PField<T>[] fields,
PMessageDescriptorProvider<?>... possibleTypes) {
super(programName, name, null, false);
this.fields = fields;
this.possibleTypeProviders = UnmodifiableList.copyOf(possibleTypes);
this.possibleTypes = new AtomicReference<>();
// TODO: Make better detection of auto interfaces. Currently there is none.
UnmodifiableMap.Builder<Integer, PField<T>> fieldIdMap = UnmodifiableMap.builder(this.fields.length);
UnmodifiableMap.Builder<String, PField<T>> fieldNameMap = UnmodifiableMap.builder(this.fields.length);
UnmodifiableMap.Builder<String, PField<T>> fieldPojoNameMap = UnmodifiableMap.builder(this.fields.length);
for (PField<T> field : fields) {
fieldIdMap.put(field.getId(), field);
fieldNameMap.put(field.getName(), field);
fieldPojoNameMap.put(field.getPojoName(), field);
}
this.fieldIdMap = fieldIdMap.build();
this.fieldNameMap = fieldNameMap.build();
this.fieldPojoNameMap = fieldPojoNameMap.build();
}
@Override
public boolean isInnerType() {
return false;
}
@Override
public boolean isAutoType() {
return false;
}
/**
* @return Get a list of know possible types implementing this interface.
*/
public List<PMessageDescriptor<?>> getPossibleTypes() {
return possibleTypes.updateAndGet(list -> {
if (list == null) {
list = possibleTypeProviders.stream().map(PMessageDescriptorProvider::descriptor).collect(Collectors.toList());
}
return list;
});
}
@Nonnull
@Override
public PMessageVariant getVariant() {
return PMessageVariant.INTERFACE;
}
@Nonnull
@Override
public PField<T>[] getFields() {
return Arrays.copyOf(fields, fields.length);
}
@Override
public PField<T> findFieldByName(String name) {
return fieldNameMap.get(name);
}
@Override
public PField<T> findFieldByPojoName(String pojoName) {
return fieldPojoNameMap.get(pojoName);
}
@Override
public PField<T> findFieldById(int id) {
return fieldIdMap.get(id);
}
@Nonnull
@Override
public PMessageBuilder<T> builder() {
throw new UnsupportedOperationException("Interfaces cannot be built");
}
}