Skip to content

Commit

Permalink
Merge pull request payara#4777 from jGauravGupta/FISH-162-2
Browse files Browse the repository at this point in the history
FISH-162 OpenAPI Class Data Processing
  • Loading branch information
jGauravGupta authored and Pandrex247 committed Oct 14, 2020
1 parent ccabcf3 commit d641f33
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 350 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand All @@ -70,7 +69,6 @@
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.glassfish.api.StartupRunLevel;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.Events;
import org.glassfish.grizzly.config.dom.NetworkListener;
Expand All @@ -91,9 +89,9 @@
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.NotProcessed;
import org.jvnet.hk2.config.UnprocessedChangeEvents;

import static java.util.logging.Level.WARNING;
import static java.util.stream.Collectors.toSet;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.hk2.classmodel.reflect.Type;

@Service(name = "microprofile-openapi-service")
Expand All @@ -102,6 +100,8 @@ public class OpenApiService implements PostConstruct, PreDestroy, EventListener,

private static final Logger LOGGER = Logger.getLogger(OpenApiService.class.getName());

private OpenAPI allDocuments;

private Deque<OpenApiMapping> mappings;

@Inject
Expand Down Expand Up @@ -174,28 +174,49 @@ public void event(Event<?> event) {
if (isValidApp(appInfo)) {
// Store the application mapping in the list
mappings.add(new OpenApiMapping(appInfo));
allDocuments = null;
}
} else if (event.is(Deployment.APPLICATION_UNLOADED)) {
ApplicationInfo appInfo = (ApplicationInfo) event.hook();
for (OpenApiMapping mapping : mappings) {
if (mapping.getAppInfo().equals(appInfo)) {
mappings.remove(mapping);
allDocuments = null;
break;
}
}
}
}

/**
* @return the document for the most recently deployed application. Creates
* one if it hasn't already been created.
* @return the document If multiple application deployed then merge all the
* documents. Creates one if it hasn't already been created.
* @throws OpenAPIBuildException if creating the document failed.
*/
public OpenAPI getDocument() throws OpenAPIBuildException {
if (mappings.isEmpty() || !isEnabled()) {
return null;
}
return mappings.peekLast().getDocument();
if (mappings.size() == 1) {
OpenAPI document = mappings.peekLast().getDocument();
if (document == null) {
document = mappings.peekLast().buildDocument();
}
return document;
}
List<OpenAPI> docs = new ArrayList<>();
for (OpenApiMapping mapping : mappings) {
if (mapping.getDocument() == null) {
allDocuments = null;
mapping.buildDocument();
}
docs.add(mapping.getDocument());
}
if (allDocuments == null) {
allDocuments = new OpenAPIImpl();
OpenAPIImpl.merge(allDocuments, docs, true);
}
return allDocuments;
}

/**
Expand Down Expand Up @@ -240,34 +261,31 @@ ApplicationInfo getAppInfo() {
}

private synchronized OpenAPI getDocument() throws OpenAPIBuildException {
if (document == null) {
document = buildDocument();
}
return document;
}

private OpenAPI buildDocument() throws OpenAPIBuildException {
OpenAPI openapi = new OpenAPIImpl();
document = new OpenAPIImpl();

try {
String contextRoot = getContextRoot(appInfo);
List<URL> baseURLs = getServerURL(contextRoot);

openapi = new ModelReaderProcessor().process(openapi, appConfig);
openapi = new FileProcessor(appInfo.getAppClassLoader()).process(openapi, appConfig);
openapi = new ApplicationProcessor(
document = new ModelReaderProcessor().process(document, appConfig);
document = new FileProcessor(appInfo.getAppClassLoader()).process(document, appConfig);
document = new ApplicationProcessor(
appInfo.getTypes(),
filterTypes(appInfo, appConfig),
appInfo.getAppClassLoader()
).process(openapi, appConfig);
openapi = new BaseProcessor(baseURLs).process(openapi, appConfig);
openapi = new FilterProcessor().process(openapi, appConfig);
).process(document, appConfig);
document = new BaseProcessor(baseURLs).process(document, appConfig);
document = new FilterProcessor().process(document, appConfig);
} catch (Throwable t) {
throw new OpenAPIBuildException(t);
}

LOGGER.info("OpenAPI document created.");
return openapi;
return document;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import fish.payara.microprofile.openapi.impl.model.tags.TagImpl;
import fish.payara.microprofile.openapi.impl.model.util.ModelUtils;
import static fish.payara.microprofile.openapi.impl.model.util.ModelUtils.extractAnnotations;
import static fish.payara.microprofile.openapi.impl.model.util.ModelUtils.mergeProperty;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.microprofile.openapi.models.Components;
Expand Down Expand Up @@ -220,10 +221,18 @@ public void setComponents(Components components) {
this.components = components;
}

public static OpenAPI merge(OpenAPI parent, List<OpenAPI> children, boolean override) {
for (OpenAPI child : children) {
OpenAPIImpl.merge(child, parent, override, null);
}
return parent;
}

public static void merge(OpenAPI from, OpenAPI to, boolean override, ApiContext context) {
if (from == null) {
return;
}
to.setOpenapi(mergeProperty(to.getOpenapi(), from.getOpenapi(), override));
// Handle @Info
if (from.getInfo() != null) {
if (to.getInfo() == null) {
Expand Down Expand Up @@ -277,6 +286,7 @@ public static void merge(OpenAPI from, OpenAPI to, boolean override, ApiContext
}
// Handle @Components
ComponentsImpl.merge(from.getComponents(), to.getComponents(), override, context);
PathsImpl.merge(from.getPaths(), to.getPaths(), override);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ public class SchemaImpl extends ExtensibleImpl<Schema> implements Schema {
private Integer minProperties;
private List<String> required = new ArrayList<>();
private SchemaType type;
private Schema not;
private Map<String, Schema> properties = new HashMap<>();
private String description;
private String format;
Expand All @@ -104,6 +103,7 @@ public class SchemaImpl extends ExtensibleImpl<Schema> implements Schema {
private List<Object> enumeration = new ArrayList<>();
private Discriminator discriminator;

private Schema not;
private List<Schema> anyOf = new ArrayList<>();
private List<Schema> allOf = new ArrayList<>();
private List<Schema> oneOf = new ArrayList<>();
Expand Down Expand Up @@ -723,87 +723,28 @@ public static void merge(Schema from, Schema to,
applyReference(to, from.getRef());
return;
}
if (from.getType() != null) {
to.setType(mergeProperty(to.getType(), from.getType(), override));
}
if (from instanceof SchemaImpl
&& ((SchemaImpl) from).getImplementation() != null
&& context.getApi().getComponents().getSchemas() != null) {
String implementationClass = ((SchemaImpl) from).getImplementation();
if (!implementationClass.equals("java.lang.Void")) {
Type type = context.getType(implementationClass);
String schemaName = null;
if (type instanceof ExtensibleType) {
ExtensibleType implementationType = (ExtensibleType) type;
AnnotationInfo annotationInfo = AnnotationInfo.valueOf(implementationType);
AnnotationModel annotation = annotationInfo.getAnnotation(org.eclipse.microprofile.openapi.annotations.media.Schema.class);
// Get the schema name
if (annotation != null) {
schemaName = annotation.getValue("name", String.class);
}
}
if (schemaName == null || schemaName.isEmpty()) {
schemaName = ModelUtils.getSimpleName(implementationClass);
}
// Get the schema reference, and copy it's values over to the new schema model
Schema copyFrom = context.getApi().getComponents().getSchemas().get(schemaName);
if (copyFrom == null) {
SchemaType schemaType = ModelUtils.getSchemaType(implementationClass, context);
copyFrom = new SchemaImpl().type(schemaType);
}
if (to.getType() == SchemaType.ARRAY) {
to.setItems(new SchemaImpl());
ModelUtils.merge(copyFrom, to.getItems(), true);
} else {
ModelUtils.merge(copyFrom, to, true);
}
to.setRef(null);
}
}
if (from.getDiscriminator() != null) {
if (to.getDiscriminator() == null) {
to.setDiscriminator(new DiscriminatorImpl());
}
Discriminator discriminator = to.getDiscriminator();
discriminator.setPropertyName(
mergeProperty(discriminator.getPropertyName(), from.getDiscriminator().getPropertyName(), override)
);
for (Entry<String, String> mapping : from.getDiscriminator().getMapping().entrySet()) {
discriminator.addMapping(mapping.getKey(), mapping.getValue());
}
}
to.setTitle(mergeProperty(to.getTitle(), from.getTitle(), override));
to.setDefaultValue(mergeProperty(to.getDefaultValue(), from.getDefaultValue(), override));
if (from.getEnumeration() != null && from.getEnumeration().size() > 0) {
if (to.getEnumeration() == null) {
to.setEnumeration(new ArrayList<>());
}
for (Object value : from.getEnumeration()) {
if (!to.getEnumeration().contains(value)) {
to.addEnumeration(value);
}
}
}
to.setTitle(mergeProperty(to.getTitle(), from.getTitle(), override));
if (from.getMultipleOf() != null && from.getMultipleOf().compareTo(BigDecimal.ZERO) > 0) {
to.setMultipleOf(mergeProperty(to.getMultipleOf(),
from.getMultipleOf().stripTrailingZeros(), override));
}
if (from.getMaximum() != null) {
to.setMaximum(mergeProperty(to.getMaximum(), from.getMaximum(), override));
}
to.setExclusiveMaximum(mergeProperty(to.getExclusiveMaximum(), from.getExclusiveMaximum(), override));
if (from.getMinimum() != null) {
to.setMinimum(mergeProperty(to.getMinimum(), from.getMinimum(), override));
}
to.setExclusiveMaximum(mergeProperty(to.getExclusiveMaximum(), from.getExclusiveMaximum(), override));
to.setExclusiveMinimum(mergeProperty(to.getExclusiveMinimum(), from.getExclusiveMinimum(), override));
to.setMaxLength(mergeProperty(to.getMaxLength(), from.getMaxLength(), override));
to.setMinLength(mergeProperty(to.getMinLength(), from.getMinLength(), override));
to.setPattern(mergeProperty(to.getPattern(), from.getPattern(), override));
to.setMaxItems(mergeProperty(to.getMaxItems(), from.getMaxItems(), override));
to.setMinItems(mergeProperty(to.getMinItems(), from.getMinItems(), override));
to.setUniqueItems(mergeProperty(to.getUniqueItems(), from.getUniqueItems(), override));
to.setMaxProperties(mergeProperty(to.getMaxProperties(), from.getMaxProperties(), override));
to.setMinProperties(mergeProperty(to.getMinProperties(), from.getMinProperties(), override));
to.setUniqueItems(mergeProperty(to.getUniqueItems(), from.getUniqueItems(), override));
to.setPattern(mergeProperty(to.getPattern(), from.getPattern(), override));
if (from.getRequired() != null && !from.getRequired().isEmpty()) {
if (to.getRequired() == null) {
to.setRequired(new ArrayList<>());
Expand All @@ -814,6 +755,19 @@ public static void merge(Schema from, Schema to,
}
}
}
if (from.getType() != null) {
to.setType(mergeProperty(to.getType(), from.getType(), override));
}
if (from.getProperties() != null && !from.getProperties().isEmpty()) {
if (to.getProperties() == null) {
to.setProperties(new HashMap<>());
}
for (String key : from.getProperties().keySet()) {
if (!to.getProperties().containsKey(key)) {
to.addProperty(key, from.getProperties().get(key));
}
}
}
to.setDescription(mergeProperty(to.getDescription(), from.getDescription(), override));
to.setFormat(mergeProperty(to.getFormat(), from.getFormat(), override));
to.setNullable(mergeProperty(to.getNullable(), from.getNullable(), override));
Expand All @@ -827,6 +781,28 @@ public static void merge(Schema from, Schema to,
ExternalDocumentationImpl.merge(from.getExternalDocs(), to.getExternalDocs(), override);
}
to.setDeprecated(mergeProperty(to.getDeprecated(), from.getDeprecated(), override));
if (from.getEnumeration() != null && from.getEnumeration().size() > 0) {
if (to.getEnumeration() == null) {
to.setEnumeration(new ArrayList<>());
}
for (Object value : from.getEnumeration()) {
if (!to.getEnumeration().contains(value)) {
to.addEnumeration(value);
}
}
}
if (from.getDiscriminator() != null) {
if (to.getDiscriminator() == null) {
to.setDiscriminator(new DiscriminatorImpl());
}
Discriminator discriminator = to.getDiscriminator();
discriminator.setPropertyName(
mergeProperty(discriminator.getPropertyName(), from.getDiscriminator().getPropertyName(), override)
);
for (Entry<String, String> mapping : from.getDiscriminator().getMapping().entrySet()) {
discriminator.addMapping(mapping.getKey(), mapping.getValue());
}
}
if (from.getNot() != null) {
to.setNot(from.getNot());
}
Expand All @@ -848,6 +824,41 @@ public static void merge(Schema from, Schema to,
}
to.getOneOf().addAll(from.getOneOf());
}
if (from instanceof SchemaImpl
&& ((SchemaImpl) from).getImplementation() != null
&& context.getApi().getComponents().getSchemas() != null) {
String implementationClass = ((SchemaImpl) from).getImplementation();
if (!implementationClass.equals("java.lang.Void")) {
Type type = context.getType(implementationClass);
String schemaName = null;
if (type instanceof ExtensibleType) {
ExtensibleType implementationType = (ExtensibleType) type;
AnnotationInfo annotationInfo = AnnotationInfo.valueOf(implementationType);
AnnotationModel annotation = annotationInfo.getAnnotation(org.eclipse.microprofile.openapi.annotations.media.Schema.class);
// Get the schema name
if (annotation != null) {
schemaName = annotation.getValue("name", String.class);
}
}
if (schemaName == null || schemaName.isEmpty()) {
schemaName = ModelUtils.getSimpleName(implementationClass);
}
// Get the schema reference, and copy it's values over to the new schema model
Schema copyFrom = context.getApi().getComponents().getSchemas().get(schemaName);
if (copyFrom == null) {
SchemaType schemaType = ModelUtils.getSchemaType(implementationClass, context);
copyFrom = new SchemaImpl().type(schemaType);
}
if (to.getType() == SchemaType.ARRAY) {
to.setItems(new SchemaImpl());
ModelUtils.merge(copyFrom, to.getItems(), true);
} else {
ModelUtils.merge(copyFrom, to, true);
}
to.setRef(null);
}
}

}

}
Loading

0 comments on commit d641f33

Please sign in to comment.