aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/rendering/RendererRegistry.java
blob: 0f01261f6a4910b2345ed341ad1db309bdd7cb96 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.rendering;

import com.yahoo.component.ComponentId;
import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.prelude.templates.PageTemplateSet;
import com.yahoo.prelude.templates.SearchRendererAdaptor;
import com.yahoo.prelude.templates.TiledTemplateSet;
import com.yahoo.prelude.templates.UserTemplate;
import com.yahoo.processing.rendering.Renderer;
import com.yahoo.search.Result;

import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.Executor;

/**
 * Holds all configured and built-in renderers.
 * This registry is always frozen.
 *
 * @author bratseth
 */
public final class RendererRegistry extends ComponentRegistry<com.yahoo.processing.rendering.Renderer<Result>> {

    public static final ComponentId xmlRendererId = ComponentId.fromString("DefaultRenderer");
    private static final ComponentId newXmlRendererId = ComponentId.fromString("XmlRenderer");
    public static final ComponentId jsonRendererId = ComponentId.fromString("JsonRenderer");
    public static final ComponentId defaultRendererId = jsonRendererId;
    
    private final ComponentId tiledRendererId;
    private final ComponentId pageRendererId;

    /** Creates a registry containing the built-in renderers only */
    public RendererRegistry() {
        this(Collections.emptyList());
    }

    /** 
     * Creates a registry containing the built-in renderers only, using a custom executor.
     * Using a custom executor is useful for tests to avoid creating new threads for each renderer registry:
     * Use MoreExecutors.directExecutor().
     */
    public RendererRegistry(Executor executor) {
        this(Collections.emptyList(), executor);
    }

    /** Creates a registry of the given renderers plus the built-in ones */
    public RendererRegistry(Collection<Renderer> renderers) {
        this(renderers, null);
    }

    /** 
     * Creates a registry of the given renderers plus the built-in ones, using a custom executor.
     * Using a custom executor is useful for tests to avoid creating new threads for each renderer registry.
     */
    public RendererRegistry(Collection<Renderer> renderers, Executor executor) {
        // add json renderer
        Renderer jsonRenderer = new JsonRenderer(executor);
        jsonRenderer.initId(RendererRegistry.jsonRendererId);
        register(jsonRenderer.getId(), jsonRenderer);

        // Add xml renderer
        Renderer xmlRenderer = new DefaultRenderer(executor);
        xmlRenderer.initId(xmlRendererId);
        register(xmlRenderer.getId(), xmlRenderer);

        // Add new Vespa 7 xml renderer
        Renderer newXmlRenderer = new XmlRenderer(executor);
        newXmlRenderer.initId(newXmlRendererId);
        register(newXmlRenderer.getId(), newXmlRenderer);

        // add application renderers
        for (Renderer renderer : renderers)
            register(renderer.getId(), renderer);

        // add legacy "templates" converted to renderers // TODO: Remove on Vespa 7
        tiledRendererId = addTemplateSet(new TiledTemplateSet());
        pageRendererId = addTemplateSet(new PageTemplateSet());

        freeze();
    }
    
    /** Must be called when use of this is discontinued to free the resources it has allocated */
    public void deconstruct() {
        // deconstruct the renderers which was created by this
        getRenderer(jsonRendererId.toSpecification()).deconstruct();
        getRenderer(xmlRendererId.toSpecification()).deconstruct();
        getRenderer(newXmlRendererId.toSpecification()).deconstruct();
        getRenderer(tiledRendererId.toSpecification()).deconstruct();
        getRenderer(pageRendererId.toSpecification()).deconstruct();
    }

    @SuppressWarnings({"deprecation", "unchecked"})
    private ComponentId addTemplateSet(UserTemplate<?> templateSet) {
        Renderer renderer = new SearchRendererAdaptor(templateSet);
        ComponentId rendererId = new ComponentId(templateSet.getName());
        renderer.initId(rendererId);
        register(rendererId, renderer);
        return rendererId;
    }

    /**
     * Returns the default JSON renderer
     *
     * @return the default built-in result renderer
     */
    public com.yahoo.processing.rendering.Renderer<Result> getDefaultRenderer() {
        return getComponent(jsonRendererId);
    }

    /**
     * Returns the requested renderer.
     *
     * @param format the id or format alias of the renderer to return. If null is passed the default renderer
     *               is returned
     * @throws IllegalArgumentException if the renderer cannot be resolved
     */
    public com.yahoo.processing.rendering.Renderer<Result> getRenderer(ComponentSpecification format) {
        if (format == null || format.stringValue().equals("default")) return getDefaultRenderer();
        if (format.stringValue().equals("json")) return getComponent(jsonRendererId);
        if (format.stringValue().equals("xml")) return getComponent(xmlRendererId);

        com.yahoo.processing.rendering.Renderer<Result> renderer = getComponent(format);
        if (renderer == null)
            throw new IllegalArgumentException("No renderer with id or alias '" + format + "'. " +
                                               "Available renderers are: [" + rendererNames() + "].");
        return renderer;
    }

    private String rendererNames() {
        StringBuilder r = new StringBuilder();
        for (Renderer<Result> c : allComponents()) {
            if (r.length() > 0)
                r.append(", ");
            r.append(c.getId().stringValue());
        }
        return r.toString();
    }

}