Skip to content
Permalink
Browse files
refactoring model + adding reader and filter loading
  • Loading branch information
rmannibucau committed Jun 24, 2018
1 parent 15df9dd commit dca74124b0338a222257a7801f69d96ee618e3c6
Showing 37 changed files with 817 additions and 169 deletions.
@@ -16,23 +16,36 @@
*/
package org.apache.geronimo.microprofile.openapi.cdi;

import static java.util.Optional.ofNullable;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessBean;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;

import org.apache.geronimo.microprofile.openapi.config.GeronimoOpenAPIConfig;
import org.apache.geronimo.microprofile.openapi.impl.model.OpenAPIImpl;
import org.apache.geronimo.microprofile.openapi.impl.processor.AnnotationProcessor;
import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.OASModelReader;
import org.eclipse.microprofile.openapi.models.OpenAPI;

public class GeronimoOpenAPIExtension implements Extension {
@@ -51,18 +64,96 @@ public <T> void findEndpointsAndApplication(@Observes final ProcessBean<T> event

public OpenAPI getOrCreateOpenAPI(final Application application) {
if (!application.getSingletons().isEmpty() || !application.getClasses().isEmpty()) {
return openapis.computeIfAbsent(application, app -> createOpenApi(application.getClass(),
Stream.concat(app.getClasses().stream(), app.getSingletons().stream().map(Object::getClass))));
return openapis.computeIfAbsent(application,
app -> createOpenApi(application.getClass(), Stream.concat(endpoints.stream().map(Bean::getBeanClass),
Stream.concat(app.getClasses().stream(), app.getSingletons().stream().map(Object::getClass)))));
}
return openapis.computeIfAbsent(application,
app -> createOpenApi(application.getClass(), endpoints.stream().map(Bean::getBeanClass)));
}

private OpenAPI createOpenApi(final Class<?> application, final Stream<Class<?>> beans) {
final BeanManager beanManager = CDI.current().getBeanManager();
final OpenAPIImpl api = new OpenAPIImpl();
processor.processApplication(api, beanManager.createAnnotatedType(application));
beans.map(beanManager::createAnnotatedType).forEach(at -> processor.processClass(api, at));
return api;
final CDI<Object> current = CDI.current();
final GeronimoOpenAPIConfig config = GeronimoOpenAPIConfig.create();
final OpenAPI api = ofNullable(config.read("mp.openapi.model.reader", null)).map(value -> newInstance(current, value))
.map(it -> OASModelReader.class.cast(it).buildModel()).orElseGet(() -> {
final BeanManager beanManager = current.getBeanManager();
final OpenAPI impl = loadDefaultApi();
processor.processApplication(impl, new ElementImpl(beanManager.createAnnotatedType(application)));
beans.map(beanManager::createAnnotatedType).forEach(at -> processor.processClass(impl, new ElementImpl(at),
at.getMethods().stream().map(ElementImpl::new)));
return impl;
});

return ofNullable(config.read("mp.openapi.filter", null))
.map(it -> newInstance(current, it))
.map(i -> {
OASFilter.class.cast(i).filterOpenAPI(api);
return api;
})
.orElse(api);
}

private OpenAPI loadDefaultApi() {
// todo: yaml handling + json mapping correctly (interface to impl)
return Stream.of("", "/")
.map(prefix -> prefix + "openapi.json")
.map(it -> Thread.currentThread().getContextClassLoader().getResourceAsStream(it))
.filter(Objects::nonNull)
.findFirst()
.map(r -> {
try (final Jsonb jsonb = JsonbBuilder.create()) {
return jsonb.fromJson(r, OpenAPIImpl.class);
} catch (final Exception e) {
throw new IllegalStateException(e);
}
})
.orElseGet(OpenAPIImpl::new);
}

private Object newInstance(final CDI<Object> current, final String value) {
try {
final Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(value.trim());
try {
return current.select(clazz);
} catch (final RuntimeException e) {
try {
return clazz.getConstructor().newInstance();
} catch (final Exception e1) {
throw e;
}
}
} catch (final ClassNotFoundException e) {
throw new IllegalArgumentException("Can't load " + value, e);
}
}

private static class ElementImpl implements AnnotatedElement {

private final Annotated delegate;

private ElementImpl(final Annotated annotated) {
this.delegate = annotated;
}

@Override
public <T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
return delegate.getAnnotation(annotationClass);
}

@Override
public Annotation[] getAnnotations() {
return delegate.getAnnotations().toArray(new Annotation[0]);
}

@Override
public <T extends Annotation> T[] getAnnotationsByType(final Class<T> annotationClass) {
return delegate.getAnnotations(annotationClass).toArray((T[]) Array.newInstance(annotationClass, 0));
}

@Override
public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}
}
}
@@ -0,0 +1,49 @@
/*
* 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 org.apache.geronimo.microprofile.openapi.config;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.enterprise.inject.Vetoed;

@Vetoed
class DefaultOpenAPIConfig implements GeronimoOpenAPIConfig {
private final Map<String, String> configuration = new HashMap<>();

DefaultOpenAPIConfig() {
System.getProperties().stringPropertyNames()
.forEach(k -> configuration.put(k, System.getProperty(k)));
try (final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/geronimo/microprofile/opentracing.properties")) {
if (stream != null) {
final Properties properties = new Properties();
properties.load(stream);
properties.stringPropertyNames().forEach(k -> configuration.put(k, properties.getProperty(k)));
}
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}

@Override
public String read(final String value, final String def) {
return configuration.getOrDefault(value, def);
}
}
@@ -0,0 +1,31 @@
/*
* 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 org.apache.geronimo.microprofile.openapi.config;

@FunctionalInterface
public interface GeronimoOpenAPIConfig {

String read(String value, String def);

static GeronimoOpenAPIConfig create() {
try {
return new PrefixedConfig(new OpenAPIConfigMpConfigImpl());
} catch (final NoClassDefFoundError | ExceptionInInitializerError cnfe) {
return new PrefixedConfig(new DefaultOpenAPIConfig());
}
}
}
@@ -0,0 +1,36 @@
/*
* 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 org.apache.geronimo.microprofile.openapi.config;

import javax.enterprise.inject.Vetoed;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;

@Vetoed
class OpenAPIConfigMpConfigImpl implements GeronimoOpenAPIConfig {
private final Config config;

OpenAPIConfigMpConfigImpl() {
config = ConfigProvider.getConfig();
}

@Override
public String read(final String key, final String def) {
return config.getOptionalValue(key, String.class).orElse(def);
}
}
@@ -0,0 +1,37 @@
/*
* 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 org.apache.geronimo.microprofile.openapi.config;

import javax.enterprise.inject.Vetoed;

@Vetoed
class PrefixedConfig implements GeronimoOpenAPIConfig {

private final GeronimoOpenAPIConfig delegate;

PrefixedConfig(final GeronimoOpenAPIConfig geronimoOpenAPIConfig) {
this.delegate = geronimoOpenAPIConfig;
}

@Override
public String read(final String value, final String def) {
if (value.startsWith("mp.")) {
return delegate.read(value, def);
}
return delegate.read("geronimo.openapi." + value, def);
}
}
@@ -29,11 +29,17 @@

@Vetoed
public class APIResponseImpl implements APIResponse {

private Extensible _extensible = new ExtensibleImpl();

private Content _content;

private String _description;

private Map<String, Header> _headers;

private Map<String, Link> _links;

private String _ref;

@Override
@@ -42,13 +48,13 @@ public Map<String, Object> getExtensions() {
}

@Override
public void addExtension(final String name, final Object value) {
_extensible.addExtension(name, value);
public void setExtensions(final Map<String, Object> extensions) {
_extensible.setExtensions(extensions);
}

@Override
public void setExtensions(final Map<String, Object> extensions) {
_extensible.setExtensions(extensions);
public void addExtension(final String name, final Object value) {
_extensible.addExtension(name, value);
}

@Override
@@ -25,6 +25,7 @@

@Vetoed
public class APIResponsesImpl extends LinkedHashMap<String, APIResponse> implements APIResponses {

private APIResponse _default;

@Override
@@ -27,7 +27,9 @@

@Vetoed
public class CallbackImpl extends LinkedHashMap<String, PathItem> implements Callback {

private Extensible _extensible = new ExtensibleImpl();

private String _ref;

@Override
@@ -36,13 +38,13 @@ public Map<String, Object> getExtensions() {
}

@Override
public void addExtension(final String name, final Object value) {
_extensible.addExtension(name, value);
public void setExtensions(final Map<String, Object> extensions) {
_extensible.setExtensions(extensions);
}

@Override
public void setExtensions(final Map<String, Object> extensions) {
_extensible.setExtensions(extensions);
public void addExtension(final String name, final Object value) {
_extensible.addExtension(name, value);
}

@Override

0 comments on commit dca7412

Please sign in to comment.