| /* |
| * 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.Comparator; |
| |
| import org.apache.sling.commons.osgi.OsgiUtil; |
| import org.apache.sling.rewriter.Generator; |
| import org.apache.sling.rewriter.GeneratorFactory; |
| import org.apache.sling.rewriter.ProcessingContext; |
| import org.apache.sling.rewriter.Processor; |
| import org.apache.sling.rewriter.ProcessorConfiguration; |
| import org.apache.sling.rewriter.ProcessorFactory; |
| import org.apache.sling.rewriter.Serializer; |
| import org.apache.sling.rewriter.SerializerFactory; |
| import org.apache.sling.rewriter.Transformer; |
| import org.apache.sling.rewriter.TransformerFactory; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * This is an utility class for accessing the various pipeline components. |
| * it also acts like a cache for the factories. |
| */ |
| public class FactoryCache { |
| |
| /** The required property containing the component type. */ |
| static final String PROPERTY_TYPE = "pipeline.type"; |
| |
| /** The optional property for the pipeline mode (global) */ |
| static final String PROPERTY_MODE = "pipeline.mode"; |
| |
| /** The global mode. */ |
| static final String MODE_GLOBAL = "global"; |
| |
| /** The optional property for the paths the component should apply to */ |
| private static final String PROPERTY_PATHS = "pipeline.paths"; |
| |
| /** The optional property for the extensions the component should apply to */ |
| private static final String PROPERTY_EXTENSIONS = "pipeline.extensions"; |
| |
| /** The optional property for the content types the component should apply to */ |
| private static final String PROPERTY_CONTENT_TYPES = "pipeline.contentTypes"; |
| |
| /** The optional property for the selectors the component should apply to */ |
| private static final String PROPERTY_SELECTORS = "pipeline.selectors"; |
| |
| /** The optional property for the resource types the component should apply to */ |
| private static final String PROPERTY_RESOURCE_TYPES = "pipeline.resourceTypes"; |
| |
| /** The logger. */ |
| static final Logger LOGGER = LoggerFactory.getLogger(FactoryCache.class); |
| |
| /** The tracker for generator factories. */ |
| private final HashingServiceTrackerCustomizer<GeneratorFactory> generatorTracker; |
| |
| /** The tracker for serializers factories. */ |
| private final HashingServiceTrackerCustomizer<SerializerFactory> serializerTracker; |
| |
| /** The tracker for transformer factories. */ |
| private final TransformerFactoryServiceTracker<TransformerFactory> transformerTracker; |
| |
| /** The tracker for processor factories. */ |
| private final HashingServiceTrackerCustomizer<ProcessorFactory> processorTracker; |
| |
| public FactoryCache(final BundleContext context) |
| throws InvalidSyntaxException { |
| this.generatorTracker = new HashingServiceTrackerCustomizer<GeneratorFactory>(context, |
| GeneratorFactory.class.getName()); |
| this.serializerTracker = new HashingServiceTrackerCustomizer<SerializerFactory>(context, |
| SerializerFactory.class.getName()); |
| this.transformerTracker = new TransformerFactoryServiceTracker<TransformerFactory>(context, |
| TransformerFactory.class.getName()); |
| this.processorTracker = new HashingServiceTrackerCustomizer<ProcessorFactory>(context, |
| ProcessorFactory.class.getName()); |
| } |
| |
| /** |
| * Start tracking |
| */ |
| public void start() { |
| this.generatorTracker.open(); |
| this.serializerTracker.open(); |
| this.transformerTracker.open(); |
| this.processorTracker.open(); |
| } |
| |
| /** |
| * Stop tracking |
| */ |
| public void stop() { |
| this.generatorTracker.close(); |
| this.serializerTracker.close(); |
| this.transformerTracker.close(); |
| this.processorTracker.close(); |
| } |
| |
| /** |
| * Get the generator of the given type. |
| * @param type The generator type. |
| * @return The generator or null if the generator is not available. |
| */ |
| public Generator getGenerator(final String type) { |
| final GeneratorFactory factory = this.generatorTracker.getFactory(type); |
| if ( factory == null ) { |
| LOGGER.debug("Requested generator factory for type '{}' not found.", type); |
| return null; |
| } |
| return factory.createGenerator(); |
| } |
| |
| /** |
| * Get the serializer of the given type. |
| * @param type The serializer type. |
| * @return The serializer or null if the serializer is not available. |
| */ |
| public Serializer getSerializer(final String type) { |
| final SerializerFactory factory = this.serializerTracker.getFactory(type); |
| if ( factory == null ) { |
| LOGGER.debug("Requested serializer factory for type '{}' not found.", type); |
| return null; |
| } |
| return factory.createSerializer(); |
| } |
| |
| /** |
| * Get the transformer of the given type. |
| * @param type The transformer type. |
| * @return The transformer or null if the transformer is not available. |
| */ |
| public Transformer getTransformer(final String type) { |
| final TransformerFactory factory = this.transformerTracker.getFactory(type); |
| if ( factory == null ) { |
| LOGGER.debug("Requested transformer factory for type '{}' not found.", type); |
| return null; |
| } |
| return factory.createTransformer(); |
| } |
| |
| /** |
| * Get the processor of the given type. |
| * @param type The processor type. |
| * @return The processor or null if the processor is not available. |
| */ |
| public Processor getProcessor(final String type) { |
| final ProcessorFactory factory = this.processorTracker.getFactory(type); |
| if ( factory == null ) { |
| LOGGER.debug("Requested processor factory for type '{}' not found.", type); |
| return null; |
| } |
| return factory.createProcessor(); |
| } |
| |
| private static final Transformer[] EMPTY_ARRAY = new Transformer[0]; |
| private static final Transformer[][] EMPTY_DOUBLE_ARRAY = new Transformer[][] {EMPTY_ARRAY, EMPTY_ARRAY}; |
| |
| /** |
| * Lookup all global transformers that apply to the current request and return |
| * the transformer instances in two arrays. |
| * The first array contains all pre transformers and the second one contains |
| * all post transformers. |
| * @param context The current processing context. |
| */ |
| public Transformer[][] getGlobalTransformers(final ProcessingContext context) { |
| final TransformerFactory[][] factories = this.transformerTracker.getGlobalTransformerFactories(context); |
| return createTransformers(factories); |
| } |
| |
| /** |
| * Create new instances from the factories |
| * @param factories The transformer factories |
| * @return The transformer instances |
| */ |
| private Transformer[][] createTransformers(final TransformerFactory[][] factories) { |
| if ( factories == EMPTY_DOUBLE_ARRAY ) { |
| return FactoryCache.EMPTY_DOUBLE_ARRAY; |
| } |
| final Transformer[][] transformers = new Transformer[2][]; |
| for(int arrayIndex = 0; arrayIndex < 2; arrayIndex++) { |
| int count = factories[arrayIndex].length; |
| for(final TransformerFactory factory : factories[arrayIndex]) { |
| if ( factory == null ) count--; |
| } |
| if ( count == 0 ) { |
| transformers[arrayIndex] = FactoryCache.EMPTY_ARRAY; |
| } else { |
| transformers[arrayIndex] = new Transformer[count]; |
| for(int i=0; i < factories[arrayIndex].length; i++) { |
| final TransformerFactory factory = factories[arrayIndex][i]; |
| if ( factory != null ) { |
| transformers[arrayIndex][i] = factory.createTransformer(); |
| } |
| } |
| } |
| } |
| |
| return transformers; |
| } |
| |
| /** |
| * Comparator for service references. |
| */ |
| static final class ServiceReferenceComparator implements Comparator<ServiceReference> { |
| public static ServiceReferenceComparator INSTANCE = new ServiceReferenceComparator(); |
| |
| @Override |
| public int compare(ServiceReference o1, ServiceReference o2) { |
| return o1.compareTo(o2); |
| } |
| } |
| |
| static final class TransformerFactoryEntry { |
| public final TransformerFactory factory; |
| |
| private final ProcessorConfiguration configuration; |
| |
| public TransformerFactoryEntry(final TransformerFactory factory, final ServiceReference ref) { |
| this.factory = factory; |
| final String[] paths = OsgiUtil.toStringArray(ref.getProperty(PROPERTY_PATHS), null); |
| final String[] extensions = OsgiUtil.toStringArray(ref.getProperty(PROPERTY_EXTENSIONS), null); |
| final String[] contentTypes = OsgiUtil.toStringArray(ref.getProperty(PROPERTY_CONTENT_TYPES), null); |
| final String[] resourceTypes = OsgiUtil.toStringArray(ref.getProperty(PROPERTY_RESOURCE_TYPES), null); |
| final String[] selectors = OsgiUtil.toStringArray(ref.getProperty(PROPERTY_SELECTORS), null); |
| final boolean noCheckRequired = (paths == null || paths.length == 0) && |
| (extensions == null || extensions.length == 0) && |
| (contentTypes == null || contentTypes.length == 0) && |
| (resourceTypes == null || resourceTypes.length == 0) && |
| (selectors == null || selectors.length == 0); |
| if ( !noCheckRequired ) { |
| this.configuration = new ProcessorConfigurationImpl(contentTypes, paths, extensions, resourceTypes, selectors); |
| } else { |
| this.configuration = null; |
| } |
| } |
| |
| public boolean match(final ProcessingContext context) { |
| if ( configuration == null ) { |
| return true; |
| } |
| return configuration.match(context); |
| } |
| } |
| } |