blob: d80a676119f74758e5c8f81262273e3c483e125b [file] [log] [blame]
/*
* 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.sling.rewriter.impl;
import java.util.Arrays;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.TransformerFactory;
import org.apache.sling.rewriter.impl.FactoryCache.ServiceReferenceComparator;
import org.apache.sling.rewriter.impl.FactoryCache.TransformerFactoryEntry;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class TransformerFactoryServiceTracker<T> extends HashingServiceTrackerCustomizer<T> {
private final Logger LOGGER = LoggerFactory.getLogger(TransformerFactoryServiceTracker.class);
private String getMode(final ServiceReference ref) {
final String mode = (String) ref.getProperty(FactoryCache.PROPERTY_MODE);
return mode;
}
private boolean isGlobal(final ServiceReference ref) {
return FactoryCache.MODE_GLOBAL.equalsIgnoreCase(this.getMode(ref));
}
public static final TransformerFactoryEntry[] EMPTY_ENTRY_ARRAY = new TransformerFactoryEntry[0];
public static final TransformerFactoryEntry[][] EMPTY_DOUBLE_ENTRY_ARRAY = new TransformerFactoryEntry[][] {EMPTY_ENTRY_ARRAY, EMPTY_ENTRY_ARRAY};
public static final TransformerFactory[] EMPTY_FACTORY_ARRAY = new TransformerFactory[0];
public static final TransformerFactory[][] EMPTY_DOUBLE_FACTORY_ARRAY = new TransformerFactory[][] {EMPTY_FACTORY_ARRAY, EMPTY_FACTORY_ARRAY};
private TransformerFactoryEntry[][] cached = EMPTY_DOUBLE_ENTRY_ARRAY;
/** flag for cache. */
private volatile boolean cacheIsValid = true;
public TransformerFactoryServiceTracker(final BundleContext bc, final String serviceClassName) {
super(bc, serviceClassName);
}
/**
* @see org.osgi.util.tracker.ServiceTracker#addingService(org.osgi.framework.ServiceReference)
*/
@Override
public Object addingService(ServiceReference reference) {
final boolean isGlobal = isGlobal(reference);
LOGGER.debug("Adding service {}, isGlobal={}", reference.getClass(), isGlobal);
Object obj = null;
synchronized (this) {
if ( isGlobal ) {
this.cacheIsValid = false;
}
obj = super.addingService(reference);
}
if ( obj == null && isGlobal ) {
obj = this.context.getService(reference);
}
return obj;
}
/**
* @see org.osgi.util.tracker.ServiceTracker#removedService(org.osgi.framework.ServiceReference, java.lang.Object)
*/
@Override
public void removedService(ServiceReference reference, Object service) {
final boolean isGlobal = isGlobal(reference);
LOGGER.debug("Removing service {}, isGlobal={}", reference.getClass(), isGlobal);
synchronized (this) {
if ( isGlobal ) {
this.cacheIsValid = false;
}
super.removedService(reference, service);
}
}
/**
* Get all global transformer factories.
* @return Two arrays of transformer factories
*/
public TransformerFactoryEntry[][] getGlobalTransformerFactoryEntries() {
if ( !this.cacheIsValid ) {
synchronized ( this ) {
if ( !this.cacheIsValid ) {
final ServiceReference[] refs = this.getServiceReferences();
LOGGER.debug("Found {} service references", refs.length);
if ( refs == null || refs.length == 0 ) {
this.cached = EMPTY_DOUBLE_ENTRY_ARRAY;
} else {
Arrays.sort(refs, ServiceReferenceComparator.INSTANCE);
int preCount = 0;
int postCount = 0;
for(final ServiceReference ref : refs) {
if ( isGlobal(ref) ) {
final Object r = ref.getProperty(Constants.SERVICE_RANKING);
int ranking = (r instanceof Integer ? (Integer)r : 0);
if ( ranking < 0 ) {
preCount++;
} else {
postCount++;
}
}
}
final TransformerFactoryEntry[][] globalFactories = new TransformerFactoryEntry[2][];
if ( preCount == 0 ) {
globalFactories[0] = EMPTY_ENTRY_ARRAY;
} else {
globalFactories[0] = new TransformerFactoryEntry[preCount];
}
if ( postCount == 0) {
globalFactories[1] = EMPTY_ENTRY_ARRAY;
} else {
globalFactories[1] = new TransformerFactoryEntry[postCount];
}
int index = 0;
for(final ServiceReference ref : refs) {
if ( isGlobal(ref) ) {
if ( index < preCount ) {
LOGGER.debug("Initializing pre global TransformerFactory for service ref: {}", ref.getClass());
globalFactories[0][index] = new TransformerFactoryEntry((TransformerFactory) this.getService(ref), ref);
} else {
LOGGER.debug("Initializing post global TransformerFactory for service ref: {}", ref.getClass());
globalFactories[1][index - preCount] = new TransformerFactoryEntry((TransformerFactory) this.getService(ref), ref);
}
index++;
}
}
this.cached = globalFactories;
}
}
this.cacheIsValid = true;
}
}
return this.cached;
}
/**
* Get all global transformer factories that apply to the current request.
* @param context The current processing context.
* @return Two arrays containing the transformer factories.
*/
public TransformerFactory[][] getGlobalTransformerFactories(final ProcessingContext context) {
final TransformerFactoryEntry[][] globalFactoryEntries = this.getGlobalTransformerFactoryEntries();
// quick check
if ( globalFactoryEntries == EMPTY_DOUBLE_ENTRY_ARRAY ) {
LOGGER.debug("No TransformerFactory found");
return EMPTY_DOUBLE_FACTORY_ARRAY;
}
final TransformerFactory[][] factories = new TransformerFactory[2][];
for(int i=0; i<2; i++) {
if ( globalFactoryEntries[i] == EMPTY_ENTRY_ARRAY ) {
LOGGER.debug("No {} TransformerFactory found for context {}", i == 0 ? "pre" : "post", context);
factories[i] = EMPTY_FACTORY_ARRAY;
} else {
factories[i] = new TransformerFactory[globalFactoryEntries[i].length];
for(int m=0; m<globalFactoryEntries[i].length; m++) {
final TransformerFactoryEntry entry = globalFactoryEntries[i][m];
if ( entry.match(context) ) {
factories[i][m] = entry.factory;
}
}
LOGGER.debug("Found {} Transformer factories {} for context {}", i == 0 ? "pre" : "post", factories[i], context);
}
}
return factories;
}
}