001/*
002 * (C) Copyright 2010-2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Olivier Grisel
018 */
019package org.nuxeo.ecm.platform.suggestbox.service.descriptors;
020
021import java.util.HashMap;
022import java.util.Map;
023
024import org.nuxeo.common.xmap.annotation.XNode;
025import org.nuxeo.common.xmap.annotation.XNodeMap;
026import org.nuxeo.common.xmap.annotation.XObject;
027import org.nuxeo.ecm.platform.suggestbox.service.ComponentInitializationException;
028import org.nuxeo.ecm.platform.suggestbox.service.Suggester;
029import org.nuxeo.runtime.model.RuntimeContext;
030
031/**
032 * XMap descriptor for registering overridable parameterized Suggester implementation on the SuggesterService.
033 *
034 * @author ogrisel
035 */
036@XObject("suggester")
037public class SuggesterDescriptor implements Cloneable {
038
039    @XNode("@name")
040    protected String name = "default";
041
042    @XNode("@class")
043    protected String className;
044
045    @XNode("@enabled")
046    protected boolean enabled = true;
047
048    @XNodeMap(value = "parameters/parameter", key = "@name", type = HashMap.class, componentType = String.class)
049    protected Map<String, String> parameters = new HashMap<String, String>();
050
051    protected Suggester suggester;
052
053    protected RuntimeContext runtimeContext;
054
055    public String getName() {
056        return name;
057    }
058
059    public boolean isEnabled() {
060        return enabled;
061    }
062
063    public Map<String, String> getParameters() {
064        return parameters;
065    }
066
067    public void setRuntimeContext(RuntimeContext context) throws ComponentInitializationException {
068        // store the runtime context for later usage if a merge is required
069        this.runtimeContext = context;
070        loadParameterizedSuggester();
071    }
072
073    protected void loadParameterizedSuggester() throws ComponentInitializationException {
074        if (enabled && className != null) {
075            // try build the suggester instance as early as possible to throw
076            // errors at deployment time rather than lazily at first access time
077            // by the user: fail early.
078            try {
079                suggester = (Suggester) runtimeContext.loadClass(className).newInstance();
080            } catch (ReflectiveOperationException e) {
081                throw new ComponentInitializationException(String.format(
082                        "Failed to initialize suggester '%s' with class '%s'", name, className), e);
083            }
084            suggester.initWithParameters(this);
085        }
086        // if the the descriptor is enabled but does not provide any
087        // contrib this is probably just for overriding some parameters
088        // handled at merge time
089    }
090
091    public Suggester getSuggester() {
092        return suggester;
093    }
094
095    public void mergeFrom(SuggesterDescriptor newDescriptor) throws ComponentInitializationException {
096        if (name == null || !name.equals(newDescriptor.name)) {
097            throw new RuntimeException("Cannot merge descriptor with name '" + name
098                    + "' with another descriptor with different name " + newDescriptor.getName() + "'");
099        }
100        if (className == null) {
101            if (enabled && newDescriptor.className == null) {
102                throw new RuntimeException("Cannot merge descriptor with name '" + name
103                        + "' with source a source version that has no" + " className defined.");
104            }
105            className = newDescriptor.className;
106            runtimeContext = newDescriptor.runtimeContext;
107        }
108        // merged the parameters
109        Map<String, String> mergedParameters = new HashMap<String, String>();
110        mergedParameters.putAll(parameters);
111        mergedParameters.putAll(newDescriptor.parameters);
112        parameters = mergedParameters;
113        loadParameterizedSuggester();
114    }
115
116    /*
117     * Override the Object.clone to make it public
118     */
119    @Override
120    public Object clone() throws CloneNotSupportedException {
121        return super.clone();
122    }
123
124}