/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.system.init;
import fr.gael.dhus.service.MetadataTypeService;
import fr.gael.dhus.service.metadata.SolrField;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.schema.ManagedIndexSchema;
import org.apache.solr.schema.ManagedIndexSchemaFactory;
import org.apache.solr.schema.SchemaField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.xml.sax.SAXException;
/**
* This is a workaround to create a schema.xml at startup,
* only compatible with Solr v4.10.
*
* Until Solr is updated to v5.3+, we won't benefint from
* <a href="https://issues.apache.org/jira/browse/SOLR-7182">SOLR-7182</a>.
*/
@Component(value = "solrInitializer")
public class SolrInitializer
{
private static final Logger LOGGER = LogManager.getLogger(SolrInitializer.class);
private static final String SOLR_CONFIG_NAME = "solrconfig.xml";
/* Field property flags, not public in Solr. */
private static final int INDEXED = 0x00000001;
private static final int STORED = 0x00000004;
private static final int MULTIVALUED = 0x00000200;
private static final int REQUIRED = 0x00001000;
// In Solr and DHuS, all Solr field types are indexed and stored by default.
private static final int DEFAULT = INDEXED | STORED;
private static final int ALLOPTS = INDEXED | STORED | MULTIVALUED | REQUIRED;
/** The MetadataTypeService holds solr field informations. */
@Autowired
private MetadataTypeService metadataTypeService;
/**
* Opens and Parses `schema.xml` and adds every fields returned by
* {@link MetadataTypeService#getSolrFields()}.
*
* @param path_to_coredir path to the core's instanceDir.
* @param path_to_schema path to the schema.xml to edit.
*
* @throws ParserConfigurationException An error occured while parsing schema.xml
* @throws IOException An error occured while accessing schema.xml
* @throws SAXException An error occured while parsing schema.xml
*/
public void createSchema(Path path_to_coredir, String path_to_schema)
throws ParserConfigurationException, IOException, SAXException
{
SolrConfig sc = new SolrConfig(path_to_coredir, SOLR_CONFIG_NAME, null);
ManagedIndexSchemaFactory misf = new ManagedIndexSchemaFactory();
NamedList named_list = new NamedList();
named_list.add("mutable", Boolean.TRUE);
misf.init(named_list);
ManagedIndexSchema schema = misf.create(path_to_schema, sc);
Map<String, SolrField> solrfm = metadataTypeService.getSolrFields();
List<SchemaField> schemafl = new ArrayList<>(solrfm.size() + 1);
for (SolrField solrf: solrfm.values())
{
Map<String, Object> options = new HashMap<>();
int metadata_properties = DEFAULT;
if (solrf.isStored() != null)
{
if (solrf.isStored())
{
options.put("stored", true);
}
else
{
options.put("stored", false);
metadata_properties &= ~STORED;
}
}
if (solrf.isIndexed() != null)
{
if (solrf.isIndexed())
{
options.put("indexed", true);
}
else
{
options.put("indexed", false);
metadata_properties &= ~INDEXED;
}
}
if (solrf.isRequired() != null)
{
if (solrf.isRequired())
{
options.put("required", true);
metadata_properties |= REQUIRED;
}
else
{
options.put("required", false);
}
}
if (solrf.isMultiValued() != null)
{
if (solrf.isMultiValued())
{
options.put("multiValued", true);
metadata_properties |= MULTIVALUED;
}
else
{
options.put("multiValued", false);
}
}
if (LOGGER.isDebugEnabled())
{
StringBuilder sb = new StringBuilder("solr field: ").append(solrf.getName());
sb.append( " type=").append(solrf.getType());
sb.append( " stored=").append((metadata_properties & STORED) > 0);
sb.append( " indexed=").append((metadata_properties & INDEXED) > 0);
sb.append( " required=").append((metadata_properties & REQUIRED) > 0);
sb.append(" multiValued=").append((metadata_properties & MULTIVALUED) > 0);
LOGGER.debug(sb.toString());
}
SchemaField schemaf;
if ((schemaf = schema.getFieldOrNull(solrf.getName())) != null)
{
// If already defined with a different type: fatal error!
if (!schemaf.getType().getTypeName().equals(solrf.getType()))
{
String msg = new StringBuilder()
.append("Conflicting solr field '")
.append(solrf.getName())
.append("' defined twice with different types: ")
.append(schemaf.getType().getTypeName())
.append(" and ")
.append(solrf.getType())
.toString();
throw new RuntimeException(msg);
}
int schema_properties = schemaf.getProperties();
// If already defined with a different properties: fatal error!
if ((schema_properties & ALLOPTS) != metadata_properties)
{
String msg = new StringBuilder()
.append("Conflicting solr field '")
.append(solrf.getName())
.append("' defined twice with different properties")
.toString();
throw new RuntimeException(msg);
}
LOGGER.info(String.format("solr field '%s' already in schema", solrf.getName()));
continue;
}
LOGGER.info(String.format("Adding solr field '%s' in schema", solrf.getName()));
schemaf = schema.newField(solrf.getName(), solrf.getType(), options);
schemafl.add(schemaf);
}
// Adds new fields and saves the schema.xml
schema.addFields(schemafl);
}
}