diff options
Diffstat (limited to 'vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java')
-rw-r--r-- | vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java new file mode 100644 index 000000000..4b6ab776c --- /dev/null +++ b/vpp-integration/api-docs/core/src/main/java/io/fd/hc2vpp/docs/core/CoverageGenerator.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * + * Licensed 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 io.fd.hc2vpp.docs.core; + + +import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.DELETE; +import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.UPDATE; +import static io.fd.hc2vpp.docs.api.Operation.CrudOperation.WRITE; +import static java.lang.String.format; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.TypeLiteral; +import io.fd.hc2vpp.docs.api.CoverageUnit; +import io.fd.hc2vpp.docs.api.JavaApiMessage; +import io.fd.hc2vpp.docs.api.Operation; +import io.fd.hc2vpp.docs.api.PluginCoverage; +import io.fd.hc2vpp.docs.api.YangType; +import io.fd.honeycomb.translate.write.WriterFactory; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.reflections.ReflectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CoverageGenerator implements VppApiUtils { + + private static final Logger LOG = LoggerFactory.getLogger(CoverageGenerator.class); + + private final CollectingWriterBuilder writerBuilder; + + public CoverageGenerator() { + writerBuilder = new CollectingWriterBuilder(); + } + + public PluginCoverage generateConfigCoverage(final Class<?> pluginClass, + final String version, + final List<Module> scannedModules, + final YangTypeLinkIndex yangTypeIndex, + final ClassPathTypeIndex classPathIndex) { + LOG.info("Generating config coverage for plugin {}", pluginClass); + getInjectedWriterFactories(scannedModules).forEach(writerFactory -> writerFactory.init(writerBuilder)); + + LOG.info("Processing single node handlers"); + final Set<CoverageUnit> singleNodeCoverageUnits = writerBuilder.getSingleNodeHandlers().stream() + .flatMap(writer -> { + // extracts customizer class from handler + final Class<?> customizerClass = getCustomizerClass(writer); + + // scans within write method + final Set<PluginMethodReference> writeReferences = + new CoverageScanner(customizerClass, WRITE, pluginClass).scan(); + + // scans within update method + final Set<PluginMethodReference> updateReferences = + new CoverageScanner(customizerClass, UPDATE, pluginClass).scan(); + + // scans within delete method + final Set<PluginMethodReference> deleteReferences = + new CoverageScanner(customizerClass, DELETE, pluginClass).scan(); + + return Stream.of(writeReferences.stream(), updateReferences.stream(), deleteReferences.stream()) + .flatMap(pluginMethodReferences -> pluginMethodReferences) + .map(reference -> { + final CoverageUnit.CoverageUnitBuilder builder = new CoverageUnit.CoverageUnitBuilder(); + + // binds vpp api name and generateLink bind with version + builder.setVppApi(fromJvppApi(version, reference)); + + //binds java api reference + builder.setJavaApi(new JavaApiMessage(reference.getName())); + + //binds Yang types with links from pre-build index + // TODO - use deserialized yii + final String typeName = writer.getManagedDataObjectType().getTargetType().getTypeName(); + builder.setYangTypes(Collections.singletonList(new YangType( + typeName, + yangTypeIndex.getLinkForType(typeName)))); + + final List<Operation> supportedOperations = new LinkedList<>(); + + final String callerClassLink = classPathIndex.linkForClass(reference.getCaller()); + if (writeReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, WRITE)); + } + + if (updateReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, UPDATE)); + } + + if (deleteReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, DELETE)); + } + return builder.setSupportedOperations(supportedOperations).build(); + }); + }).collect(Collectors.toSet()); + + LOG.info("Processing multi node handlers"); + final Set<CoverageUnit> multiNodeCoverageUnits = writerBuilder.getMultiNodeWriteHandlers().stream() + .flatMap(handler -> { + final Class<?> customizerClass = getCustomizerClass(handler.getWriter()); + final Set<PluginMethodReference> writeReferences = + new CoverageScanner(customizerClass, WRITE, pluginClass).scan(); + + final Set<PluginMethodReference> updateReferences = + new CoverageScanner(customizerClass, UPDATE, pluginClass).scan(); + + final Set<PluginMethodReference> deleteReferences = + new CoverageScanner(customizerClass, DELETE, pluginClass).scan(); + + return Stream.of(writeReferences.stream(), updateReferences.stream(), deleteReferences.stream()) + .flatMap(pluginMethodReferenceStream -> pluginMethodReferenceStream) + .map(reference -> { + final CoverageUnit.CoverageUnitBuilder builder = new CoverageUnit.CoverageUnitBuilder(); + builder.setVppApi(fromJvppApi(version, reference)); + builder.setJavaApi(new JavaApiMessage(reference.getName())); + + builder.setYangTypes(handler.getHandledChildren().stream() + .map(type -> new YangType(type, yangTypeIndex.getLinkForType(type))) + .collect(Collectors.toList())); + + final String callerClassLink = classPathIndex.linkForClass(reference.getCaller()); + final List<Operation> supportedOperations = new LinkedList<>(); + if (writeReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, WRITE)); + } + + if (updateReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, UPDATE)); + } + + if (deleteReferences.contains(reference)) { + supportedOperations.add(new Operation(callerClassLink, DELETE)); + } + return builder.setSupportedOperations(supportedOperations).build(); + }); + }).collect(Collectors.toSet()); + + return new PluginCoverage(pluginClass.getSimpleName(), + Stream.of(singleNodeCoverageUnits.stream(), multiNodeCoverageUnits.stream()) + .flatMap(coverageUnitStream -> coverageUnitStream) + .collect(Collectors.toSet()), true); + } + + private static Class<?> getCustomizerClass(final Object handler) { + try { + final Set<Field> customizerFields = + ReflectionUtils.getAllFields(handler.getClass(), field -> "customizer".equals(field.getName())); + final Field customizerField = customizerFields.iterator().next(); + customizerField.setAccessible(true); + return customizerField.get(handler).getClass(); + } catch (IllegalAccessException e) { + throw new IllegalStateException(format("Unable to get customizer from %s ", handler), e); + } + } + + private static Set<WriterFactory> getInjectedWriterFactories(final List<Module> scannedModules) { + Injector injector = Guice.createInjector(scannedModules); + TypeLiteral<Set<WriterFactory>> writerFactoryType = new TypeLiteral<Set<WriterFactory>>() { + }; + return injector.getInstance(Key.get(writerFactoryType)); + } +} |