001/*
002 * (C) Copyright 2010-2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Olivier Grisel
016 */
017package org.nuxeo.ecm.platform.suggestbox.service.descriptors;
018
019import java.util.HashMap;
020import java.util.Map;
021
022import org.nuxeo.common.xmap.annotation.XNode;
023import org.nuxeo.common.xmap.annotation.XNodeMap;
024import org.nuxeo.common.xmap.annotation.XObject;
025import org.nuxeo.ecm.platform.suggestbox.service.ComponentInitializationException;
026import org.nuxeo.ecm.platform.suggestbox.service.Suggester;
027import org.nuxeo.runtime.model.RuntimeContext;
028
029/**
030 * XMap descriptor for registering overridable parameterized Suggester implementation on the SuggesterService.
031 *
032 * @author ogrisel
033 */
034@XObject("suggester")
035public class SuggesterDescriptor implements Cloneable {
036
037    @XNode("@name")
038    protected String name = "default";
039
040    @XNode("@class")
041    protected String className;
042
043    @XNode("@enabled")
044    protected boolean enabled = true;
045
046    @XNodeMap(value = "parameters/parameter", key = "@name", type = HashMap.class, componentType = String.class)
047    protected Map<String, String> parameters = new HashMap<String, String>();
048
049    protected Suggester suggester;
050
051    protected RuntimeContext runtimeContext;
052
053    public String getName() {
054        return name;
055    }
056
057    public boolean isEnabled() {
058        return enabled;
059    }
060
061    public Map<String, String> getParameters() {
062        return parameters;
063    }
064
065    public void setRuntimeContext(RuntimeContext context) throws ComponentInitializationException {
066        // store the runtime context for later usage if a merge is required
067        this.runtimeContext = context;
068        loadParameterizedSuggester();
069    }
070
071    protected void loadParameterizedSuggester() throws ComponentInitializationException {
072        if (enabled && className != null) {
073            // try build the suggester instance as early as possible to throw
074            // errors at deployment time rather than lazily at first access time
075            // by the user: fail early.
076            try {
077                suggester = (Suggester) runtimeContext.loadClass(className).newInstance();
078            } catch (ReflectiveOperationException e) {
079                throw new ComponentInitializationException(String.format(
080                        "Failed to initialize suggester '%s' with class '%s'", name, className), e);
081            }
082            suggester.initWithParameters(this);
083        }
084        // if the the descriptor is enabled but does not provide any
085        // contrib this is probably just for overriding some parameters
086        // handled at merge time
087    }
088
089    public Suggester getSuggester() {
090        return suggester;
091    }
092
093    public void mergeFrom(SuggesterDescriptor newDescriptor) throws ComponentInitializationException {
094        if (name == null || !name.equals(newDescriptor.name)) {
095            throw new RuntimeException("Cannot merge descriptor with name '" + name
096                    + "' with another descriptor with different name " + newDescriptor.getName() + "'");
097        }
098        if (className == null) {
099            if (enabled && newDescriptor.className == null) {
100                throw new RuntimeException("Cannot merge descriptor with name '" + name
101                        + "' with source a source version that has no" + " className defined.");
102            }
103            className = newDescriptor.className;
104            runtimeContext = newDescriptor.runtimeContext;
105        }
106        // merged the parameters
107        Map<String, String> mergedParameters = new HashMap<String, String>();
108        mergedParameters.putAll(parameters);
109        mergedParameters.putAll(newDescriptor.parameters);
110        parameters = mergedParameters;
111        loadParameterizedSuggester();
112    }
113
114    /*
115     * Override the Object.clone to make it public
116     */
117    @Override
118    public Object clone() throws CloneNotSupportedException {
119        return super.clone();
120    }
121
122}