/* * 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.web.dispatch; import java.util.Arrays; import java.util.Comparator; import org.apache.solr.core.CoreContainer; import org.apache.stanbol.commons.solr.SolrConstants; import org.apache.stanbol.commons.solr.utils.ServiceReferenceRankingComparator; import org.apache.stanbol.commons.solr.web.impl.SolrDispatchFilterComponent; 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; /** * Rather than using directly a {@link ServiceReference} to parse the * {@link CoreContainer} to be used for the dispatch filter this allows to * parse the {@link SolrConstants#PROPERTY_CORE_NAME name} or an own * {@link Filter} that is used to {@link ServiceTracker track} {@link CoreContainer} * instances registered in the OSGI environment. In case of the empty * Constructor a simple Class filter is used to track for CoreContainer services.<p> * The CoreContainer to be used for the dispatch filter is searched during the * the execution of the Servlets * {@link javax.servlet.Filter#init(javax.servlet.FilterConfig)}.<p> * This implementation does NOT remove the Filter or change the {@link CoreContainer} * on any change in the OSGI environment. See {@link SolrDispatchFilterComponent} * if you need this functionality. * @author Rupert Westenthaler */ public class SolrServiceDispatchFilter extends DelegatingSolrDispatchFilter { private static final Comparator<ServiceReference> SERVICE_REFERENCE_COMPARATOR = ServiceReferenceRankingComparator.INSTANCE; private BundleContext context; private ServiceReference coreContainerRef; private Filter filter; /** * Creates a tracking Solr dispatch filter for the CoreContainer with the * parsed {@link SolrConstants#PROPERTY_SERVER_NAME} value * @param context the context * @param solrServerName the name of the CoreContainer (value of the {@link SolrConstants#PROPERTY_SERVER_NAME}) * @param stc An optional {@link ServiceTrackerCustomizer} used for the tracking * the {@link CoreContainer} * @throws InvalidSyntaxException if the created {@link Filter} for the parsed name is invalid */ public SolrServiceDispatchFilter(BundleContext context, String solrServerName,ServiceTrackerCustomizer stc) throws InvalidSyntaxException{ super(); if(context == null){ throw new IllegalArgumentException("The parsed BundleContext MUST NOT be NULL!"); } this.context = context; if(solrServerName == null || solrServerName.isEmpty()){ throw new IllegalArgumentException("The parsed SolrServer name MUST NOT be NULL nor empty!"); } String filterString = String.format("(&(%s=%s)(%s=%s))", Constants.OBJECTCLASS,CoreContainer.class.getName(), SolrConstants.PROPERTY_SERVER_NAME,solrServerName); filter = context.createFilter(filterString); } /** * Creates a tracking Solr dispatch filter using the parsed filter to select * services. Note that the filter MUST assure that all tracked services are * {@link CoreContainer} instances! * @param context the context * @param filter the Filter that selects the {@link CoreContainer} service * to be used for Request dispatching. * the {@link CoreContainer} */ public SolrServiceDispatchFilter(BundleContext context, Filter filter){ super(); if(context == null){ throw new IllegalArgumentException("The parsed BundleContext MUST NOT be NULL!"); } this.context = context; if(filter == null){ throw new IllegalArgumentException("The parsed Filter for tracking CoreContainer instances MUST NOT be NULL!"); } this.filter = filter; } /** * Creates a Dispatch filter for CoreContainer registered as OSGI services. * In case more than one {@link CoreContainer} is available the one with the * highest {@link Constants#SERVICE_RANKING} will be used. Instances with * no or the same Service rank are not sorted. * @param context the context used to look for the CoreContainer */ public SolrServiceDispatchFilter(BundleContext context){ super(); if(context == null){ throw new IllegalArgumentException("The parsed BundleContext MUST NOT be NULL!"); } this.context = context; this.filter = null; } @Override protected CoreContainer getCoreContainer() { ungetCoreContainer(); //unget the previouse used service ServiceReference[] references; try { references = filter == null ? context.getServiceReferences(CoreContainer.class.getName(), null) : context.getServiceReferences((String)null, filter.toString()); } catch (InvalidSyntaxException e) { references = null; //can not be happen, because we created the filter already in the //constructor and only need to parse it again because BundleContext //is missing a Method to parse a Filter object when getting //ServiceReferences } if(references == null || references.length == 0){ throw new IllegalStateException("Unable to find CoreContainer instance "+ (filter != null ? ("for filter"+filter.toString()) : "")+"!"); } else { if(references.length > 1){ Arrays.sort(references, ServiceReferenceRankingComparator.INSTANCE); } this.coreContainerRef = references[0]; } Object service = context.getService(coreContainerRef); if(service instanceof CoreContainer){ return (CoreContainer)service; } else { throw new IllegalStateException("The parsed Filter '"+ filter.toString()+" selected a service '"+service+"'(class: "+ service.getClass().getName()+") that is not compatiple with "+ CoreContainer.class.getName()+"!"); } } @Override protected void ungetCoreContainer() { if(coreContainerRef != null){ context.ungetService(coreContainerRef); } coreContainerRef = null; } }