org.eclipse.smila.search.templates.TemplateRegistryController.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.smila.search.templates.TemplateRegistryController.java

Source

/***********************************************************************************************************************
 * Copyright (c) 2008 empolis GmbH and brox IT Solutions GmbH. All rights reserved. This program and the accompanying
 * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: August Georg Schmidt (brox IT Solutions GmbH) - initial API and implementation
 **********************************************************************************************************************/
package org.eclipse.smila.search.templates;

import java.io.File;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.smila.search.EIFActivator;
import org.eclipse.smila.search.datadictionary.DataDictionaryController;
import org.eclipse.smila.search.index.IndexConnection;
import org.eclipse.smila.search.index.IndexException;
import org.eclipse.smila.search.plugin.Plugin;
import org.eclipse.smila.search.plugin.PluginFactory;
import org.eclipse.smila.search.templates.messages.fieldtemplates.DFieldTemplate;
import org.eclipse.smila.search.templates.messages.fieldtemplates.DFieldTemplates;
import org.eclipse.smila.search.templates.messages.fieldtemplates.DFieldTemplatesCodec;
import org.eclipse.smila.search.templates.messages.fieldtemplates.DFieldTemplatesException;
import org.eclipse.smila.search.templates.messages.searchtemplates.DIndexField;
import org.eclipse.smila.search.templates.messages.searchtemplates.DSearchTemplates;
import org.eclipse.smila.search.templates.messages.searchtemplates.DSearchTemplatesCodec;
import org.eclipse.smila.search.templates.messages.searchtemplates.DSearchTemplatesException;
import org.eclipse.smila.search.templates.messages.searchtemplates.DSelector;
import org.eclipse.smila.search.templates.messages.searchtemplates.DTemplate;
import org.eclipse.smila.search.utils.advsearch.IQueryExpression;
import org.eclipse.smila.search.utils.advsearch.ITerm;
import org.eclipse.smila.search.utils.search.DField;
import org.eclipse.smila.search.utils.search.DQuery;
import org.eclipse.smila.utils.config.ConfigUtils;
import org.eclipse.smila.utils.xml.XMLUtils;
import org.eclipse.smila.utils.xml.XMLUtilsConfig;
import org.eclipse.smila.utils.xml.XMLUtilsException;
import org.w3c.dom.Document;

/**
 * A cache and manager for Search- and FieldTemplates. If a template is not defined then an empty dummy template is
 * created.
 * 
 * @author August Georg Schmidt (BROX)
 */
public abstract class TemplateRegistryController {

    /**
     * Search templates.
     */
    private static Hashtable<String, DSearchTemplates> s_searchTemplates = new Hashtable<String, DSearchTemplates>(
            0);

    /**
     * Field templates.
     */
    private static Hashtable<String, DFieldTemplates> s_fieldTemplates = new Hashtable<String, DFieldTemplates>(0);

    /**
     * 
     */
    private TemplateRegistryController() {
    }

    /**
     * Get template for simple search.
     * 
     * @param dQuery
     *          Simple search query.
     * @return Search template or null.
     * @throws TemplateException
     *           Unable to get template.
     */
    public static DTemplate getTemplate(DQuery dQuery) throws TemplateException {
        final DSearchTemplates templates = getSearchTemplates(dQuery.getIndexName());
        for (int i = 0; i < templates.getTemplateCount(); i++) {
            final DTemplate template = templates.getTemplate(i);
            if (doesQueryMatchTemplate(dQuery, template)) {
                return template;
            }
        }
        return null;
    }

    /**
     * Get field template for simple search field.
     * 
     * @param query
     *          Simple search query.
     * @param field
     *          Field from simple search.
     * @param indexName
     *          index name.
     * @return Field template or null.
     * @throws TemplateException
     *           Unable to get template.
     */
    public static DFieldTemplate getFieldTemplate(DQuery query, DField field, String indexName)
            throws TemplateException {
        final DFieldTemplates templates = getFieldTemplates(indexName);
        for (int i = 0; i < templates.getTemplateCount(); i++) {
            final DFieldTemplate template = templates.getTemplate(i);
            if (doesFieldMatchTemplate(query, field, template)) {
                try {
                    return (DFieldTemplate) template.clone();
                } catch (final CloneNotSupportedException e) {
                    ; // no error handling required.
                }
            }
        }
        return null;
    }

    /**
     * Check whether a template matches a search query.
     * 
     * @param query
     *          Simple search query.
     * @param template
     *          Template.
     * @return Whether the template matches the query.
     */
    static boolean doesQueryMatchTemplate(DQuery query, DTemplate template) {

        if (query == null) {
            throw new NullPointerException("query");
        }
        if (template == null) {
            throw new NullPointerException("template");
        }

        final DSelector dSelector = template.getSelector();
        String selector = "";
        if (dSelector.getName() != null) {
            selector = dSelector.getName().trim();
        }
        String templateSelectorName = "";
        if (query.getTemplateSelectorName() != null) {
            templateSelectorName = query.getTemplateSelectorName().trim();
        }

        if (query.getFieldsCount() != dSelector.getIndexFieldCount()) {
            // selector has additional fields
            return false;
        }

        // test selector name
        if (!templateSelectorName.equals(selector)) {
            return false;
        }

        // test selector structure
        final Iterator fields = dSelector.getIndexFields();
        while (fields.hasNext()) {
            final DIndexField field = (DIndexField) fields.next();
            if (!isFieldInQuery(field, query)) {
                // field does not exist in selector
                return false;
            }
        }

        return true;
    }

    /**
     * Checks whether a field is contained in a search query.
     * 
     * @param indexField
     *          Field.
     * @param query
     *          Search query.
     * @return Whether field is in query.
     */
    private static boolean isFieldInQuery(DIndexField indexField, DQuery query) {
        final Enumeration enm = query.getFields();
        while (enm.hasMoreElements()) {
            final DField field = (DField) enm.nextElement();
            if (field.getFieldNo() == indexField.getFieldNo()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether a field does match a template.
     * 
     * @param query
     *          Query.
     * @param field
     *          Field.
     * @param template
     *          Template.
     * @return Whether a field matches a template.
     */
    public static boolean doesFieldMatchTemplate(DQuery query, DField field, DFieldTemplate template) {

        if (query == null) {
            throw new NullPointerException("query");
        }
        if (field == null) {
            throw new NullPointerException("field");
        }
        if (template == null) {
            throw new NullPointerException("template");
        }

        final Log log = LogFactory.getLog(TemplateRegistryController.class);

        final org.eclipse.smila.search.templates.messages.fieldtemplates.DSelector dSelector = template
                .getSelector();
        if (dSelector == null) {
            throw new NullPointerException("template.selector");
        }

        String selector = "";
        if (dSelector.getName() != null) {
            selector = dSelector.getName().trim();
        }
        String fieldTemplate = "";
        if (field.getFieldTemplate() != null) {
            fieldTemplate = field.getFieldTemplate().trim();
        }

        // test selector name and field no
        if (fieldTemplate.equals(selector) && field.getFieldNo() == dSelector.getFieldNo()) {

            if ((dSelector.getFilterExpression() != null) && (!"".equals(dSelector.getFilterExpression().trim()))) {
                final boolean matchesFilterExpression;
                try {
                    matchesFilterExpression = matchesFilterExpression(dSelector.getFilterExpression().trim(),
                            query);
                } catch (final TemplateException exception) {
                    log.error("unable to check template expression filter [" + template.getName() + "]", exception);
                    return false;
                }
                return matchesFilterExpression;
            } else {
                return true;
            }

        }
        return false;
    }

    /**
     * Checks whether a query matches the filter expression.
     * 
     * @param filterExpression
     *          Filter expression.
     * @param query
     *          Query.
     * @return Whether query matches.
     * @throws TemplateException -
     */
    public static boolean matchesFilterExpression(String filterExpression, DQuery query) throws TemplateException {

        if (filterExpression == null) {
            throw new NullPointerException("filterExpression");
        }
        if (query == null) {
            throw new NullPointerException("query");
        }

        if ("".equals(filterExpression.trim())) {
            return true;
        }

        final String[] tokens = filterExpression.trim().split(";");

        final Set<String> queryFields = new HashSet<String>();
        for (final Enumeration fields = query.getFields(); fields.hasMoreElements();) {
            queryFields.add(((DField) fields.nextElement()).getFieldNo() + "");
        }

        final Set<String> requiredFields = new HashSet<String>();
        final Set<String> prohibitedFields = new HashSet<String>();

        for (int i = 0; i < tokens.length; i++) {
            final String token = tokens[i].trim();
            if (token.length() > 0) {
                String number = token;
                if (token.startsWith("!")) {
                    number = token.substring(1);
                    prohibitedFields.add(number);
                } else {
                    requiredFields.add(number);
                }

                try {
                    final int fieldNo = Integer.parseInt(number);
                } catch (final NumberFormatException exception) {
                    throw new TemplateException("unable to check for filter expression", exception);
                }
            }
        }

        // check all required fields
        for (final String field : requiredFields) {
            if (!queryFields.contains(field)) {
                return false;
            }
        }

        // check all prohibited fields
        for (final String field : prohibitedFields) {
            if (queryFields.contains(field)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @param dQuery
     *          Search query.
     * @param dTemplate
     *          Search template.
     * @param ic
     *          Index connection.
     * @return Query expression.
     * @throws TemplateException
     *           Unable to apply search template.
     * @throws NodeTransformerException
     *           Unable to apply node transformers.
     * @throws IndexException
     *           Unable to apply search template.
     */
    public static IQueryExpression applyTemplate(DQuery dQuery, DTemplate dTemplate, IndexConnection ic)
            throws TemplateException, NodeTransformerException, IndexException {

        final Plugin plugin = PluginFactory.getPlugin();
        return plugin.getTemplateAccess().applyTemplate(dQuery, dTemplate, ic);
    }

    /**
     * Apply field template.
     * 
     * @param dField
     *          Query field.
     * @param dTemplate
     *          Template.
     * @param ic
     *          Index connection.
     * @return Subterm containing applied field template.
     * @throws TemplateException
     *           Unable to apply field template.
     * @throws NodeTransformerException
     *           Unable to apply node transformers.
     * @throws IndexException
     *           Error applying field templates.
     */
    public static ITerm applyFieldTemplate(DField dField, DFieldTemplate dTemplate, IndexConnection ic)
            throws TemplateException, NodeTransformerException, IndexException {

        final Plugin plugin = PluginFactory.getPlugin();
        return plugin.getTemplateAccess().applyFieldTemplate(dField, dTemplate, ic);
    }

    /**
     * Takes the given SearchTemplate (a) caches it in .searchTemplates and saves it to the harddrive.
     * 
     * @param templates
     *          Search templates for a index.
     * @throws TemplateException
     *           Unable to set search templates.
     */
    public static void setSearchTemplates(DSearchTemplates templates) throws TemplateException {
        synchronized (s_searchTemplates) {

            // cache template
            if (s_searchTemplates.containsKey(templates.getIndexName())) {
                s_searchTemplates.put(templates.getIndexName(), templates);
            }

            // write template to disk
            saveTemplateToDisk(templates);

        }
    }

    /**
     * Store templates persistent on disk.
     * 
     * @param templates
     *          Search templates to store.
     * @throws TemplateException
     *           Unable to store search templates.
     */
    private static void saveTemplateToDisk(DSearchTemplates templates) throws TemplateException {
        final Log log = LogFactory.getLog(TemplateRegistryController.class);
        final File file = getSearchTemplateFile(templates.getIndexName());
        try {
            final Document doc = DSearchTemplatesCodec.encode(templates);
            XMLUtils.stream(doc.getDocumentElement(), true, "UTF-8", file);
        } catch (final Exception e) {
            s_searchTemplates.remove(templates.getIndexName());
            log.error(
                    "unable to store templates [" + templates.getIndexName() + "] in file [" + file.getName() + "]",
                    e);
            throw new TemplateException("unable to store templates [" + templates.getIndexName() + "]", e);
        }
    }

    /**
     * Returns the SearchTemplate-File-object for the given index. Just gets the object but it doesnt create or open the
     * file for you.
     * 
     * @param indexName
     *          Index name.
     * @return File containing search templates.
     */
    private static File getSearchTemplateFile(String indexName) {
        final File folder = ConfigUtils.getConfigFolder(EIFActivator.BUNDLE_NAME, "xml");
        final File file = new File(folder, "SearchTemplates-" + indexName + ".xml");
        return file;
    }

    /**
     * Returns the SearchTemplate-File-object for the given index. Just gets the object but it doesnt create or open the
     * file for you.
     * 
     * @param indexName
     *          Index name.
     * @return File containing field templates.
     */
    private static File getFieldTemplateFile(String indexName) {
        final File folder = ConfigUtils.getConfigFolder(EIFActivator.BUNDLE_NAME, "xml");
        final File file = new File(folder, "FieldTemplates-" + indexName + ".xml");
        return file;
    }

    /**
     * Resolves all search templates for a given index.
     * 
     * @param indexName
     *          Index name.
     * @return Search templates.
     * @throws TemplateException
     *           Unable to get search templates.
     */
    public static DSearchTemplates getSearchTemplates(String indexName) throws TemplateException {
        final Log log = LogFactory.getLog(TemplateRegistryController.class);

        checkIndexExistance(indexName);

        synchronized (s_searchTemplates) {
            if (s_searchTemplates.containsKey(indexName)) {
                return s_searchTemplates.get(indexName);
            } else {
                DSearchTemplates templates = null;
                final File file = getSearchTemplateFile(indexName);

                // create dummy template
                if (!file.exists()) {
                    templates = new DSearchTemplates();
                    templates.setIndexName(indexName);

                    saveTemplateToDisk(templates);
                } else {
                    // load template file

                    try {
                        final Document doc = XMLUtils.parse(file, new XMLUtilsConfig());
                        templates = DSearchTemplatesCodec.decode(doc.getDocumentElement());
                    } catch (final XMLUtilsException e) {
                        log.error(e.getMessage());
                        throw new TemplateException("unable parse templates file [" + file.getName() + "]", e);
                    } catch (final DSearchTemplatesException e) {
                        log.error("unable to load templates file [" + file.getName() + "]", e);
                        throw new TemplateException("unable decode templates file [" + file.getName() + "]", e);
                    }
                }
                // register file
                s_searchTemplates.put(indexName, templates);
                return templates;
            }
        }
    }

    /**
     * Takes the given FieldTemplate (a) caches it in .fieldTemplates and saves it to the harddrive.
     * 
     * @param templates
     *          Field templates for a index.
     * @throws TemplateException
     *           Unable to set field templates.
     */
    public static void setFieldTemplates(DFieldTemplates templates) throws TemplateException {
        synchronized (s_fieldTemplates) {

            // cache
            if (s_fieldTemplates.containsKey(templates.getIndexName())) {
                s_fieldTemplates.put(templates.getIndexName(), templates);
            }

            saveTemplateToDisk(templates);

        }
    }

    /**
     * Store templates persistent on disk.
     * 
     * @param templates
     *          Field templates to store.
     * @throws TemplateException
     *           Unable to store field templates.
     */
    private static void saveTemplateToDisk(DFieldTemplates templates) throws TemplateException {
        final Log log = LogFactory.getLog(TemplateRegistryController.class);
        // write template to disk
        final File file = getFieldTemplateFile(templates.getIndexName());
        try {
            final Document doc = DFieldTemplatesCodec.encode(templates);
            XMLUtils.stream(doc.getDocumentElement(), true, "UTF-8", file);
        } catch (final Exception e) {
            s_fieldTemplates.remove(templates.getIndexName());
            log.error(
                    "unable to store templates [" + templates.getIndexName() + "] in file [" + file.getName() + "]",
                    e);
            throw new TemplateException("unable to store templates [" + templates.getIndexName() + "]", e);
        }
    }

    /**
     * Returns the template for the given index. These attempts are made in this order: 1. cache; 2. file 3. dummy
     * 
     * @param indexName
     *          Index name.
     * @return Field templates.
     * @throws TemplateException
     *           Unable to resolve field templates.
     */
    public static DFieldTemplates getFieldTemplates(String indexName) throws TemplateException {
        final Log log = LogFactory.getLog(TemplateRegistryController.class);

        checkIndexExistance(indexName);

        synchronized (s_fieldTemplates) {
            // try to get from cache
            if (s_fieldTemplates.containsKey(indexName)) {
                return s_fieldTemplates.get(indexName);
            } else {
                DFieldTemplates templates = null;
                final File file = getFieldTemplateFile(indexName);

                // create dummy (empty) template
                if (!file.exists()) {
                    templates = new DFieldTemplates();
                    templates.setIndexName(indexName);

                    // create templatefile
                    saveTemplateToDisk(templates);
                } else {
                    // load template file
                    try {
                        final Document doc = XMLUtils.parse(file, new XMLUtilsConfig());
                        templates = DFieldTemplatesCodec.decode(doc.getDocumentElement());
                    } catch (final XMLUtilsException e) {
                        log.error(e.getMessage());
                        throw new TemplateException("unable to parse templates file [" + file.getName() + "]", e);
                    } catch (final DFieldTemplatesException e) {
                        log.error("unable to load templates file [" + file.getName() + "]: " + e.getMessage(), e);
                        throw new TemplateException("unable to decode templates file [" + file.getName() + "]", e);
                    }
                }
                // register file
                s_fieldTemplates.put(indexName, templates);
                return templates;
            }
        }
    }

    /**
     * Checks existance of given index and just returns if it does, otherwise throes exception.
     * 
     * @param indexName
     *          Index name.
     * @throws TemplateException
     *           Index does not exist.
     */
    private static void checkIndexExistance(String indexName) throws TemplateException {
        boolean indexExists = false;

        try {
            indexExists = DataDictionaryController.hasIndex(indexName);
        } catch (final Throwable e) {
            throw new TemplateException("index does not exist [" + indexName + "]", e);
        }

        if (!indexExists) {
            throw new TemplateException("index does not exist [" + indexName + "]");
        }
    }

    /**
     * Removes for the given index the given template(s) from cache and disk. The method is optimistic, ie it doesnt check
     * for existance of the given index nor the successful removal from cache and disk and consequently doesnt throw any
     * exception.
     * 
     * @param indexName
     *          Index name.
     * @param doSearchTemplates
     *          Whether search templates should be deleted.
     * @param doFieldTemplates
     *          Whether field templates should be deleted.
     */
    public static void removeTemplates(String indexName, boolean doSearchTemplates, boolean doFieldTemplates) {

        if (doSearchTemplates) {
            final File file = getSearchTemplateFile(indexName);
            file.delete();

            synchronized (s_searchTemplates) {
                s_searchTemplates.remove(indexName);
            }
        }

        if (doFieldTemplates) {
            final File file = getFieldTemplateFile(indexName);
            file.delete();

            synchronized (s_fieldTemplates) {
                s_fieldTemplates.remove(indexName);
            }
        }

    }

}