ganymede.notebook.RendererMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ganymede-notebook Show documentation
Show all versions of ganymede-notebook Show documentation
Ganymede Notebook API and JShell Application
The newest version!
package ganymede.notebook;
/*-
* ##########################################################################
* Ganymede
* %%
* Copyright (C) 2021, 2022 Allen D. Ball
* %%
* 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.
* ##########################################################################
*/
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import ganymede.util.ServiceProviderMap;
import java.util.Comparator;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.TreeMap;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* {@link Renderer} {@link java.util.Map}.
*
* @author {@link.uri mailto:[email protected] Allen D. Ball}
*/
public class RendererMap extends TreeMap,Renderer> {
private static final long serialVersionUID = -8180874215822796778L;
private static final Comparator> COMPARATOR =
new IsAssignableFromOrder().thenComparing(Class::getName);
/** @serial */
private final ServiceProviderMap map;
/**
* Sole constructor.
*/
public RendererMap() {
super(COMPARATOR);
this.map = new ServiceProviderMap<>(Renderer.class, this::compute);
}
private Renderer compute(ServiceLoader.Provider provider) {
var value = provider.get().instance().orElse(null);
var key = (value != null) ? value.getRenderType() : null;
return (key != null) ? computeIfAbsent(key, k -> configure(value)) : null;
}
private Renderer configure(Renderer renderer) {
if (renderer != null) {
renderer.configure(this);
}
return renderer;
}
/**
* Reload the underlying {@link ServiceProviderMap} and add the
* corresponding entries.
*
* @return {@link.this}
*/
public RendererMap reload() {
map.reload();
return this;
}
/**
* Method to create a
* {@link ganymede.server.Message#execute_result(int,ObjectNode) mime bundle}
* and render an {@link Object} and any alternatives.
*
* @param object The {@link Object} to encode.
* @param alternates Optional alternate representations.
*
* @return The {@link ganymede.server.Message} {@code mime-bundle}.
*/
public ObjectNode render(Object object, Object... alternates) {
var bundle = new ObjectNode(JsonNodeFactory.instance);
renderTo(bundle, object, alternates);
return bundle;
}
/**
* Method to render an {@link Object} to a {@code mime-bundle}.
*
* @param bundle The {@code mime-bundle}.
* @param object The {@link Object} to render.
* @param alternates Optional alternate representations.
*/
public void renderTo(ObjectNode bundle, Object object, Object... alternates) {
var type = (object != null) ? object.getClass() : Object.class;
reload().find(type).ifPresent(t -> t.renderTo(bundle, object));
if (alternates != null) {
for (var alternate : alternates) {
if (alternate != null) {
find(alternate.getClass())
.ifPresent(t -> t.renderTo(bundle, alternate));
}
}
}
}
private Optional find(Class> type) {
var value =
entrySet().stream()
.filter(t -> t.getKey().isAssignableFrom(type))
.map(t -> t.getValue())
.findFirst();
return value;
}
@NoArgsConstructor @ToString
private static class IsAssignableFromOrder implements Comparator> {
@Override
public int compare(Class> left, Class> right) {
boolean ordered = right.isAssignableFrom(left);
boolean reversed = left.isAssignableFrom(right);
return (ordered ^ reversed) ? (ordered ? -1 : 1) : 0;
}
}
}