/* * 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; final class TransformerFactoryServiceTracker<T> extends HashingServiceTrackerCustomizer<T> { 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 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); if ( isGlobal ) { this.cacheIsValid = false; } Object 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) { if ( isGlobal(reference) ) { 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(); 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 ) { globalFactories[0][index] = new TransformerFactoryEntry((TransformerFactory) this.getService(ref), ref); } else { 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 ) { return EMPTY_DOUBLE_FACTORY_ARRAY; } final TransformerFactory[][] factories = new TransformerFactory[2][]; for(int i=0; i<2; i++) { if ( globalFactoryEntries[i] == EMPTY_ENTRY_ARRAY ) { 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; } } } } return factories; } }