* #%L
 * Alfresco Search Services
 * %%
 * Copyright (C) 2005 - 2020 Alfresco Software Limited
 * %%
 * This file is part of the Alfresco software. 
 * If the software was purchased under a paid Alfresco license, the terms of 
 * the paid license agreement will prevail.  Otherwise, the software is 
 * provided under the following open source license terms:
 * Alfresco is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Alfresco is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 * #L%

package org.alfresco.solr.tracker;

import org.alfresco.opencmis.dictionary.CMISStrictDictionaryService;
import org.alfresco.repo.dictionary.NamespaceDAO;
import org.alfresco.repo.index.shard.ShardMethodEnum;
import org.alfresco.repo.index.shard.ShardState;
import org.alfresco.repo.index.shard.ShardStateBuilder;
import org.alfresco.repo.search.impl.QueryParserUtils;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.namespace.QName;
import org.alfresco.solr.AlfrescoCoreAdminHandler;
import org.alfresco.solr.AlfrescoSolrDataModel;
import org.alfresco.solr.InformationServer;
import org.alfresco.solr.NodeReport;
import org.alfresco.solr.TrackerState;
import org.alfresco.solr.client.SOLRAPIClient;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Optional;
import java.util.Properties;

import static java.util.Optional.of;
import static java.util.Optional.ofNullable;
import static org.alfresco.solr.tracker.DocRouterFactory.SHARD_KEY_KEY;

 * Superclass for all components which are able to inform Alfresco about the hosting node state.
 * This has been introduced in SEARCH-1752 for splitting the dual responsibility of the {@link org.alfresco.solr.tracker.MetadataTracker}.
 * As consequence of that, this class contains only the members needed for obtaining a valid
 * {@link org.alfresco.repo.index.shard.ShardState} that can be periodically communicated to Alfresco.
 * @author Andrea Gazzarini
 * @since 1.5
 * @see <a href="https://issues.alfresco.com/jira/browse/SEARCH-1752">SEARCH-1752</a>
public abstract class AbstractShardInformationPublisher extends AbstractTracker
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractShardInformationPublisher.class);
    DocRouter docRouter;
    private final boolean isMaster;

    /** The string representation of the shard key. */
    private Optional<String> shardKey;

    /** The property to use for determining the shard. */
    protected Optional<QName> shardProperty = Optional.empty();

            boolean isMaster,
            Properties p,
            SOLRAPIClient client,
            String coreName,
            InformationServer informationServer,
            Type type)
        super(p, client, coreName, informationServer, type);
        this.isMaster = isMaster;
        shardKey = ofNullable(p.getProperty(SHARD_KEY_KEY));


        docRouter = DocRouterFactory.getRouter(p, shardMethod);

    AbstractShardInformationPublisher(Type type)
        this.isMaster = false;

     * Returns information about the {@link org.alfresco.solr.client.Node} associated with the given dbid.
     * @param dbid the node identifier.
     * @return the {@link org.alfresco.solr.client.Node} associated with the given dbid.
    public NodeReport checkNode(Long dbid)
        NodeReport nodeReport = new NodeReport();


        return nodeReport;

    private void firstUpdateShardProperty()
        shardKey.ifPresent( shardKeyName -> {
            if (shardProperty.isEmpty())
                LOGGER.warn("Sharding property {} was set to {}, but no such property was found.", SHARD_KEY_KEY, shardKeyName);

     * Set the shard property using the shard key.
    void updateShardProperty()
        shardKey.ifPresent(shardKeyName -> {
            Optional<QName> updatedShardProperty = getShardProperty(shardKeyName);
            if (!shardProperty.equals(updatedShardProperty))
                if (updatedShardProperty.isEmpty())
                    LOGGER.warn("The model defining {} property has been disabled", shardKeyName);
                    LOGGER.info("New {} property found for {}", SHARD_KEY_KEY, shardKeyName);
            shardProperty = updatedShardProperty;

     * Given the field name, returns the name of the property definition.
     * If the property definition is not found, Empty optional is returned.
     * @param field the field name.
     * @return the name of the associated property definition if present, Optional.Empty() otherwise
    static Optional<QName> getShardProperty(String field)
        if (StringUtils.isBlank(field))
            throw new IllegalArgumentException("Sharding property " + SHARD_KEY_KEY + " has not been set.");

        AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
        NamespaceDAO namespaceDAO = dataModel.getNamespaceDAO();
        DictionaryService dictionaryService = dataModel.getDictionaryService(CMISStrictDictionaryService.DEFAULT);
        PropertyDefinition propertyDef = QueryParserUtils.matchPropertyDefinition("http://www.alfresco.org/model/content/1.0",

        return ofNullable(propertyDef).map(PropertyDefinition::getName);

     * The {@link ShardState}, as the name suggests, encapsulates/stores the state of the shard which hosts this
     * {@link MetadataTracker} instance.
     * @return the {@link ShardState} instance which stores the current state of the hosting shard.
     * @see NodeStatePublisher
    ShardState getShardState()
        TrackerState transactionsTrackerState = getTrackerState();
        TrackerState changeSetsTrackerState =
                        .map(registry -> registry.getTrackerForCore(coreName, AclTracker.class))

        HashMap<String, String> propertyBag = new HashMap<>();
        propertyBag.put("coreName", coreName);


        return ShardStateBuilder.shardState()


     * Returns the {@link DocRouter} instance in use on this node.
     * @return the {@link DocRouter} instance in use on this node.
    public DocRouter getDocRouter()
        return this.docRouter;

     * Returns true if the hosting core is master or standalone.
     * @return true if the hosting core is master or standalone.
    public boolean isOnMasterOrStandalone()
        return isMaster;