blob: ff6f296e4ca8a73649bf7813e3462aaae13973c2 [file] [log] [blame]
/*
* 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.johnzon.osgi;
import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.apache.aries.component.dsl.OSGi.all;
import static org.apache.aries.component.dsl.OSGi.coalesce;
import static org.apache.aries.component.dsl.OSGi.configuration;
import static org.apache.aries.component.dsl.OSGi.configurations;
import static org.apache.aries.component.dsl.OSGi.ignore;
import static org.apache.aries.component.dsl.OSGi.just;
import static org.apache.aries.component.dsl.OSGi.register;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import jakarta.annotation.Priority;
import jakarta.ws.rs.ext.MessageBodyReader;
import jakarta.ws.rs.ext.MessageBodyWriter;
import org.apache.aries.component.dsl.OSGi;
import org.apache.aries.component.dsl.OSGiResult;
import org.apache.johnzon.jaxrs.jsonb.jaxrs.JsonbJaxrsProvider;
import org.apache.johnzon.osgi.cdi.RegisterCdiExtension;
import org.osgi.annotation.bundle.Header;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.PrototypeServiceFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
import org.osgi.util.converter.Converter;
import org.osgi.util.converter.Converters;
@Header(name = Constants.BUNDLE_ACTIVATOR, value = "${@class}")
public class Activator implements BundleActivator {
private static final Converter CONVERTER = Converters.standardConverter();
private static final OSGi<Entry<Dictionary<String, ?>, Config>> CONFIGURATION = coalesce(
all(
configurations(Config.CONFIG_PID),
configuration(Config.CONFIG_PID)
),
just(Hashtable::new)
).map(
properties -> new AbstractMap.SimpleImmutableEntry<>(
properties,
CONVERTER.convert(properties).to(Config.class)
)
);
private OSGiResult _result;
@Override
public void start(BundleContext context) throws Exception {
_result = all(
ignore(
CONFIGURATION.flatMap(
entry -> register(
new String[]{
MessageBodyReader.class.getName(),
MessageBodyWriter.class.getName()
},
new JsonbJaxrsProviderFactory(entry.getValue()),
getJaxrsExtensionProperties(entry.getKey(), entry.getValue())
)
)
),
ignore(RegisterCdiExtension.ifPossible())
).run(context);
}
@Override
public void stop(BundleContext context) throws Exception {
_result.close();
}
@SuppressWarnings("serial")
private Map<String, ?> getJaxrsExtensionProperties(
Dictionary<String, ?> properties, Config config) {
Enumeration<String> keys = properties.keys();
return new HashMap<String, Object>() {{
while (keys.hasMoreElements()) {
String key = keys.nextElement();
if(!key.startsWith(".")) {
put(key, properties.get(key));
}
}
put(JaxrsWhiteboardConstants.JAX_RS_EXTENSION, true);
put(JaxrsWhiteboardConstants.JAX_RS_NAME, "johnzon.jsonb");
putIfAbsent("ignores", config.ignores());
putIfAbsent(
JaxrsWhiteboardConstants.JAX_RS_APPLICATION_SELECT,
config.osgi_jaxrs_application_select());
putIfAbsent(
JaxrsWhiteboardConstants.JAX_RS_MEDIA_TYPE,
config.osgi_jaxrs_media_type());
putIfAbsent(
Constants.SERVICE_RANKING,
JsonbJaxrsProvider.class.getAnnotation(Priority.class).value());
}};
}
private static Optional<String> notEmpty(String value) {
return ofNullable(value).filter(s -> !s.isEmpty());
}
private static Optional<Boolean> whenTrue(boolean value) {
return of(Boolean.valueOf(value)).filter(b -> b == Boolean.TRUE);
}
private static class JsonbJaxrsProviderFactory implements PrototypeServiceFactory<JsonbJaxrsProvider<?>> {
private final Config config;
public JsonbJaxrsProviderFactory(Config config) {
this.config = config;
}
@Override
public JsonbJaxrsProvider<?> getService(
Bundle bundle, ServiceRegistration<JsonbJaxrsProvider<?>> registration) {
return new ExtendedJsonbJaxrsProvider(config);
}
@Override
public void ungetService(
Bundle bundle, ServiceRegistration<JsonbJaxrsProvider<?>> registration, JsonbJaxrsProvider<?> service) {
}
}
private static class ExtendedJsonbJaxrsProvider extends JsonbJaxrsProvider<Object> {
public ExtendedJsonbJaxrsProvider(final Config config) {
super(Arrays.asList(config.ignores()));
this.config.setProperty("johnzon.skip-cdi", true); // by default disable it since to work it requires some effort
whenTrue(config.throw_no_content_exception_on_empty_streams()).ifPresent(this::setThrowNoContentExceptionOnEmptyStreams);
whenTrue(config.fail_on_unknown_properties()).ifPresent(this::setFailOnUnknownProperties);
whenTrue(config.use_js_range()).ifPresent(this::setUseJsRange);
notEmpty(config.other_properties()).ifPresent(this::setOtherProperties);
whenTrue(config.ijson()).ifPresent(this::setIJson);
notEmpty(config.encoding()).ifPresent(this::setEncoding);
notEmpty(config.binary_datastrategy()).ifPresent(this::setBinaryDataStrategy);
notEmpty(config.property_naming_strategy()).ifPresent(this::setPropertyNamingStrategy);
notEmpty(config.property_order_strategy()).ifPresent(this::setPropertyOrderStrategy);
whenTrue(config.null_values()).ifPresent(this::setNullValues);
whenTrue(config.pretty()).ifPresent(this::setPretty);
whenTrue(config.fail_on_missing_creator_values()).ifPresent(this::setFailOnMissingCreatorValues);
notEmpty(config.polymorphic_serialization_predicate()).ifPresent(this::setPolymorphicSerializationPredicate);
notEmpty(config.polymorphic_deserialization_predicate()).ifPresent(this::setPolymorphicDeserializationPredicate);
notEmpty(config.polymorphic_discriminator()).ifPresent(this::setPolymorphicDiscriminator);
}
}
}