/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.stanbol.commons.solr;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.core.SolrCore;
import org.apache.stanbol.commons.solr.utils.ServiceReferenceRankingComparator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Tracks the {@link CoreContainer} of the {@link SolrCore} referenced by the
* parsed {@link IndexReference}. All getService** and getServiceReference**
* methods do consider {@link Constants#SERVICE_RANKING}. <p>
*
* @author Rupert Westenthaler
*
*/
public class RegisteredSolrServerTracker extends ServiceTracker {
private final Logger log = LoggerFactory.getLogger(RegisteredSolrServerTracker.class);
/**
* In case <code>{@link IndexReference#isPath()} == true</code> than we need
* to track registered {@link SolrCore}s, because we do not know the
* {@link CoreContainer} in advance. In all other cases the
* {@link CoreContainer} is tracked. This variable avoids instanceof checks
*/
private final boolean trackingSolrCore;
/**
* needed to create {@link EmbeddedSolrServer} instances
*/
private final String coreName;
private final IndexReference reference;
/**
* Creates a new Tracker for the parsed {@link IndexReference}
* @param context the BundleContext used for tracking
* @param reference the index reference
* @throws InvalidSyntaxException if the {@link Filter} could not be
* created for the parsed {@link IndexReference}.
* @throws IllegalArgumentException if the parsed {@link IndexReference} is
* <code>null</code>
*/
public RegisteredSolrServerTracker(BundleContext context, IndexReference reference) throws InvalidSyntaxException{
this(context,reference,null);
}
/**
* Creates a new Tracker for the parsed {@link IndexReference}
* @param context the BundleContext used for tracking
* @param reference the index reference
* @param customizer Customizer parsed to the parent instance. Note that
* the {@link ServiceTrackerCustomizer#addingService(ServiceReference)}
* method of this instance is expected to directly return the
* {@link SolrCore} or {@link CoreContainer} referenced by the parsed
* {@link IndexReference}. Service Objects parsed to the
* {@link ServiceTrackerCustomizer#modifiedService(ServiceReference, Object)}
* will be of type {@link EmbeddedSolrServer}.
* @throws InvalidSyntaxException if the {@link Filter} could not be
* created for the parsed {@link IndexReference}.
* @throws IllegalArgumentException if the parsed {@link IndexReference} is
* <code>null</code>
*/
public RegisteredSolrServerTracker(BundleContext context, IndexReference reference,ServiceTrackerCustomizer customizer) throws InvalidSyntaxException {
super(context,
reference != null ?
reference.isPath() ? context.createFilter(reference.getIndexFilter()) :
context.createFilter(reference.getIndexFilter()) :
null,customizer);
if(reference == null){
throw new IllegalArgumentException("The parsed IndexReference MUST NOT be NULL!");
}
this.reference = reference;
if(reference.isPath()){
trackingSolrCore = true;
coreName = null;
} else {
trackingSolrCore = true;
coreName = reference.getIndex();
}
}
@Override
public void open() {
super.open(true); //track all services by default
}
@Override
public SolrServer addingService(ServiceReference reference) {
log.info(" ... in addingService for {} (ref: {})",
this.reference,reference);
String coreName;
CoreContainer server;
Object service = super.addingService(reference);
if(service == null){
log.warn("addingService({}) returned null -> unable to create " +
"EmbeddedSolrServer for IndexReference {}",reference,this.reference);
}
if(trackingSolrCore){
SolrCore core;
//as we (might) track all services the Class of the returned service
//might not be the same as for this classloader
if(service instanceof SolrCore){
core = (SolrCore)service;
} else {
log.warn("SolrCore fitting to IndexReference {} is incompatible to the" +
"classloader of bundle [{}]{} - Service [{}] ignored!",
new Object[]{reference,context.getBundle().getBundleId(),
context.getBundle().getSymbolicName()},
reference.getProperty(Constants.SERVICE_ID));
context.ungetService(reference);
return null;
}
coreName = core.getName();
CoreDescriptor descriptor = core.getCoreDescriptor();
if(descriptor == null){ //core not registered with a container!
context.ungetService(reference);
return null; //ignore
} else {
server = descriptor.getCoreContainer();
}
} else {
if(service instanceof CoreContainer){
server = (CoreContainer)service;
} else {
log.warn("Solr CoreContainer fitting to IndexReference {} is incompatible to the" +
"classloader of bundle [{}]{} - Service [{}] ignored!",
new Object[]{reference,context.getBundle().getBundleId(),
context.getBundle().getSymbolicName()},
reference.getProperty(Constants.SERVICE_ID));
context.ungetService(reference);
return null;
}
coreName = this.coreName;
}
return new EmbeddedSolrServer(server, coreName);
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
log.info(" ... in modifiedService for {} (ref: {}, service {})",
new Object[]{this.reference,reference,service});
super.modifiedService(reference, service);
}
@Override
public void removedService(ServiceReference reference, Object service) {
log.info(" ... in removedService for {} (ref: {}, service {})",
new Object[]{this.reference,reference,service});
super.removedService(reference, service);
}
/**
* Overrides to provides a Array sorted by {@link Constants#SERVICE_RANKING}
* @see ServiceTracker#getServiceReferences()
*/
@Override
public ServiceReference[] getServiceReferences() {
ServiceReference[] refs = super.getServiceReferences();
if(refs != null && refs.length > 1){
Arrays.sort(refs,ServiceReferenceRankingComparator.INSTANCE);
}
return refs;
}
/**
* Overrides to provide the {@link ServiceReference} with the highest
* {@link Constants#SERVICE_RANKING}.
* @see ServiceTracker#getServiceReference()
*/
@Override
public ServiceReference getServiceReference() {
ServiceReference[] refs = super.getServiceReferences();
if(refs != null && refs.length > 0){
return refs[0];
} else {
return null;
}
}
/**
* Overrides to provide the SolrServer with the highest
* {@link Constants#SERVICE_RANKING}.
* @see ServiceTracker#getService()
*/
@Override
public SolrServer getService() {
ServiceReference ref = getServiceReference();
return ref == null ? null : getService(ref);
}
/**
* Overrides to provide a {@link SolrServer} instead of {@link Object}
* @see ServiceTracker#getService(ServiceReference)
*/
@Override
public SolrServer getService(ServiceReference reference) {
return reference == null ? null : (SolrServer)super.getService(reference);
}
/**
* Overrides to provide a array of {@link SolrServer} that is sorted by
* {@link Constants#SERVICE_RANKING}.
* @see ServiceTracker#getServices()
*/
@Override
public SolrServer[] getServices() {
ServiceReference[] refs = getServiceReferences();
Collection<SolrServer> servers = new ArrayList<SolrServer>(refs.length);
if(refs != null){
for(ServiceReference ref : refs){
SolrServer server = getService(ref);
if(server != null){
servers.add(server);
} //else null ... ignore
}
}
return servers.isEmpty() ? null : servers.toArray(new SolrServer[servers.size()]);
}
}