/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 - 2015 GeoSolutions
* Licensed 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 it.geosolutions.jaiext;
import it.geosolutions.jaiext.interpolators.InterpolationBicubic;
import it.geosolutions.jaiext.interpolators.InterpolationBilinear;
import it.geosolutions.jaiext.interpolators.InterpolationNearest;
import java.awt.image.renderable.ParameterBlock;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.OutputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptor;
import javax.media.jai.OperationNode;
import javax.media.jai.OperationRegistry;
import javax.media.jai.PropertyGenerator;
import javax.media.jai.PropertySource;
import javax.media.jai.RegistryElementDescriptor;
import javax.media.jai.registry.RenderedRegistryMode;
import javax.media.jai.util.ImagingException;
import javax.media.jai.util.ImagingListener;
import com.sun.media.jai.util.PropertyUtil;
/**
* A thread safe implementation of OperationRegistry using Java 5 Concurrent {@link ReadWriteLock}
* Also it is able to substitute JAI operations with JAI-EXT ones and vice versa.
*
* @author Andrea Aime - GeoSolutions
* @author Nicola Lagomarsini - GeoSolutions
*/
public final class ConcurrentOperationRegistry extends OperationRegistry {
/** Path to the JAI default registryfile.jai */
static String JAI_REGISTRY_FILE = "META-INF/javax.media.jai.registryFile.jai";
/** Name of the other registryfile.jai */
static String USR_REGISTRY_FILE = "META-INF/registryFile.jaiext";
/** String associated to the vendor key */
static final String VENDOR_NAME = "Vendor";
/** String associated to the JAIEXT product */
static final String JAIEXT_PRODUCT = "it.geosolutions.jaiext";
/** String associated to the JAI product */
static final String JAI_PRODUCT = "com.sun.media.jai";
/** String associated to the JAI product when the operation is "Null" */
static final String JAI_PRODUCT_NULL = "javax.media.jai";
/** Logger associated to the class*/
private static final Logger LOGGER = Logger.getLogger(ConcurrentOperationRegistry.class.toString());
public static OperationRegistry initializeRegistry() {
return initializeRegistry(true);
}
public static OperationRegistry initializeRegistry(boolean useJaiExtOps) {
try {
// URL associated to the default JAI registryfile.jai
InputStream url = PropertyUtil.getFileFromClasspath(JAI_REGISTRY_FILE);
if (url == null) {
throw new RuntimeException("Could not find the main registry file");
}
// Creation of a new registry
ConcurrentOperationRegistry registry = new ConcurrentOperationRegistry();
// Registration of the JAI operations
if (url != null) {
registry.updateFromStream(url);
}
// Registration of the operation defined in any registryFile.jai file
registry.registerServices(null);
// Listing of all the registered operations
List<OperationDescriptor> descriptors = registry
.getDescriptors(RenderedRegistryMode.MODE_NAME);
// Creation of a new OperationCollection object
OperationCollection input = new OperationCollection(registry);
input.createMapFromDescriptors(descriptors);
// Saving of the all initial operations
Map<String, OperationItem> map = input.copy().filter(JAI_PRODUCT).map;
map.put("Null", input.get("Null"));
registry.jaiMap = map;
// First load all the REGISTRY_FILEs that are found in
// the specified class loader.
ClassLoader loader = registry.getClass().getClassLoader();
Enumeration<URL> en = loader.getResources(USR_REGISTRY_FILE);
// Creation of another OperationCollection instance to use for storing all the
OperationCollection changed = new OperationCollection(registry);
// Loop on all the registryFile.jai files
while (en.hasMoreElements()) {
URL url1 = en.nextElement();
changed.add(RegistryFileParser.parseFile(null, url1));
}
// Filter only the JAIEXT operations
changed = changed.filter(JAIEXT_PRODUCT);
// Copy the available JAIEXT operations
registry.jaiExtMap = changed.copy().map;
// Substitute the JAIEXT operations only if required
if (useJaiExtOps) {
input.substituteOperations(changed);
} else {
OperationCollection uniqueOperations = input.getUniqueOperations(changed);
input.substituteOperations(uniqueOperations);
}
// Set the Collection inside the registry file
registry.setOperationCollection(input);
// Return the registry
return registry;
} catch (IOException ioe) {
ImagingListener listener = JAI.getDefaultInstance().getImagingListener();
String message = "Error occurred while initializing JAI";
listener.errorOccurred(message, new ImagingException(message, ioe),
OperationRegistry.class, false);
return null;
}
}
/** The reader/writer lock for this class. */
private ReadWriteLock lock;
/** Collection of the registered Operations */
OperationCollection collection;
/** Map of the JAI operations */
private Map<String, OperationItem> jaiMap;
/** Map of the JAI-EXT operations */
private Map<String, OperationItem> jaiExtMap;
public ConcurrentOperationRegistry() {
super();
// Create a concurrent RW lock.
lock = new ReentrantReadWriteLock();
}
public String toString() {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.toString();
} finally {
readLock.unlock();
}
}
public void writeToStream(OutputStream out) throws IOException {
Lock readLock = lock.readLock();
try {
readLock.lock();
super.writeToStream(out);
} finally {
readLock.unlock();
}
}
public void initializeFromStream(InputStream in) throws IOException {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.initializeFromStream(in);
} finally {
writeLock.unlock();
}
}
public void updateFromStream(InputStream in) throws IOException {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.updateFromStream(in);
} finally {
writeLock.unlock();
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.readExternal(in);
} finally {
writeLock.unlock();
}
}
public void writeExternal(ObjectOutput out) throws IOException {
Lock readLock = lock.readLock();
try {
readLock.lock();
super.writeExternal(out);
} finally {
readLock.unlock();
}
}
public void removeRegistryMode(String modeName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.removeRegistryMode(modeName);
} finally {
writeLock.unlock();
}
}
public String[] getRegistryModes() {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getRegistryModes();
} finally {
readLock.unlock();
}
}
public void registerDescriptor(RegistryElementDescriptor descriptor) {
Lock writeLock = lock.writeLock();
boolean changed = false;
try {
writeLock.lock();
super.registerDescriptor(descriptor);
changed = true;
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Registered descriptor for the operation: "
+ descriptor.getName());
}
// If the collection is present, then it is updated
if(collection != null && changed && descriptor instanceof OperationDescriptor){
OperationItem item = new OperationItem((OperationDescriptor) descriptor);
collection.substituteSingleOp(item);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Added descriptor for the operation: "
+ descriptor.getName() + " to the registry operation list");
}
}
}catch(Exception e){
// Remove logging for OperationDescriptor registration
if(e.getMessage().contains("A descriptor is already registered against the name")){
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, e.getMessage());
}
} else {
throw new RuntimeException(e);
}
}finally {
writeLock.unlock();
}
}
public void unregisterDescriptor(RegistryElementDescriptor descriptor) {
Lock writeLock = lock.writeLock();
boolean changed = false;
try {
writeLock.lock();
super.unregisterDescriptor(descriptor);
changed = true;
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Unregistered descriptor for the operation: "
+ descriptor.getName());
}
// If the collection is present, then it is updated
if(collection != null && changed && descriptor instanceof OperationDescriptor){
OperationItem item = new OperationItem((OperationDescriptor) descriptor);
collection.removeSingleOp(item);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Removed descriptor for the operation: "
+ descriptor.getName() + " from the registry operation list");
}
}
} finally {
writeLock.unlock();
}
}
public RegistryElementDescriptor getDescriptor(Class descriptorClass, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptor(descriptorClass, descriptorName);
} finally {
readLock.unlock();
}
}
public List getDescriptors(Class descriptorClass) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptors(descriptorClass);
} finally {
readLock.unlock();
}
}
public String[] getDescriptorNames(Class descriptorClass) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptorNames(descriptorClass);
} finally {
readLock.unlock();
}
}
public RegistryElementDescriptor getDescriptor(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptor(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public List getDescriptors(String modeName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptors(modeName);
} finally {
readLock.unlock();
}
}
public String[] getDescriptorNames(String modeName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getDescriptorNames(modeName);
} finally {
readLock.unlock();
}
}
public void setProductPreference(String modeName, String descriptorName,
String preferredProductName, String otherProductName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.setProductPreference(modeName, descriptorName, preferredProductName,
otherProductName);
} finally {
writeLock.unlock();
}
}
public void unsetProductPreference(String modeName, String descriptorName,
String preferredProductName, String otherProductName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.unsetProductPreference(modeName, descriptorName, preferredProductName,
otherProductName);
} finally {
writeLock.unlock();
}
}
public void clearProductPreferences(String modeName, String descriptorName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.clearProductPreferences(modeName, descriptorName);
} finally {
writeLock.unlock();
}
}
public String[][] getProductPreferences(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getProductPreferences(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public Vector getOrderedProductList(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getOrderedProductList(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public void registerFactory(String modeName, String descriptorName, String productName,
Object factory) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.registerFactory(modeName, descriptorName, productName, factory);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Registered factory for the operation: "
+ descriptorName);
}
// If the collection is present, then it is updated
if(collection != null && modeName.equalsIgnoreCase(RenderedRegistryMode.MODE_NAME)){
collection.substituteFactory(factory, descriptorName, productName);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Added factory for the operation: "
+ descriptorName + " to the registry operation list");
}
}
} finally {
writeLock.unlock();
}
}
public void unregisterFactory(String modeName, String descriptorName, String productName,
Object factory) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.unregisterFactory(modeName, descriptorName, productName, factory);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Unregistered factory for the operation: "
+ descriptorName);
}
// If the collection is present, then it is updated
if(collection != null && modeName.equalsIgnoreCase(RenderedRegistryMode.MODE_NAME)){
collection.removeFactory(factory, descriptorName, productName);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Removed factory for the operation: "
+ descriptorName + " from the registry operation list");
}
}
} finally {
writeLock.unlock();
}
}
public void setFactoryPreference(String modeName, String descriptorName, String productName,
Object preferredOp, Object otherOp) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.setFactoryPreference(modeName, descriptorName, productName, preferredOp, otherOp);
} finally {
writeLock.unlock();
}
}
public void unsetFactoryPreference(String modeName, String descriptorName, String productName,
Object preferredOp, Object otherOp) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.unsetFactoryPreference(modeName, descriptorName, productName, preferredOp,
otherOp);
} finally {
writeLock.unlock();
}
}
public void clearFactoryPreferences(String modeName, String descriptorName, String productName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.clearFactoryPreferences(modeName, descriptorName, productName);
} finally {
writeLock.unlock();
}
}
public Object[][] getFactoryPreferences(String modeName, String descriptorName,
String productName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getFactoryPreferences(modeName, descriptorName, productName);
} finally {
readLock.unlock();
}
}
public List getOrderedFactoryList(String modeName, String descriptorName, String productName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getOrderedFactoryList(modeName, descriptorName, productName);
} finally {
readLock.unlock();
}
}
public Iterator getFactoryIterator(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getFactoryIterator(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public Object getFactory(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getFactory(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public Object invokeFactory(String modeName, String descriptorName, Object[] args) {
Lock readLock = lock.readLock();
try {
readLock.lock();
// For Rendered Mode, a check on the interpolations objects is made
// in order to convert each eventual JAI-EXT interpolation class
// if the Factory belongs to the JAI API
if(modeName.equalsIgnoreCase(RenderedRegistryMode.MODE_NAME)){
checkInterpolation(descriptorName, args);
}
return super.invokeFactory(modeName, descriptorName, args);
} finally {
readLock.unlock();
}
}
public void addPropertyGenerator(String modeName, String descriptorName,
PropertyGenerator generator) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.addPropertyGenerator(modeName, descriptorName, generator);
} finally {
writeLock.unlock();
}
}
public void removePropertyGenerator(String modeName, String descriptorName,
PropertyGenerator generator) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.removePropertyGenerator(modeName, descriptorName, generator);
} finally {
writeLock.unlock();
}
}
public void copyPropertyFromSource(String modeName, String descriptorName, String propertyName,
int sourceIndex) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.copyPropertyFromSource(modeName, descriptorName, propertyName, sourceIndex);
} finally {
writeLock.unlock();
}
}
public void suppressProperty(String modeName, String descriptorName, String propertyName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.suppressProperty(modeName, descriptorName, propertyName);
} finally {
writeLock.unlock();
}
}
public void suppressAllProperties(String modeName, String descriptorName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.suppressAllProperties(modeName, descriptorName);
} finally {
writeLock.unlock();
}
}
public void clearPropertyState(String modeName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.clearPropertyState(modeName);
} finally {
writeLock.unlock();
}
}
public String[] getGeneratedPropertyNames(String modeName, String descriptorName) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getGeneratedPropertyNames(modeName, descriptorName);
} finally {
readLock.unlock();
}
}
public PropertySource getPropertySource(String modeName, String descriptorName, Object op,
Vector sources) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getPropertySource(modeName, descriptorName, op, sources);
} finally {
readLock.unlock();
}
}
public PropertySource getPropertySource(OperationNode op) {
Lock readLock = lock.readLock();
try {
readLock.lock();
return super.getPropertySource(op);
} finally {
readLock.unlock();
}
}
public void registerServices(ClassLoader cl) throws IOException {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.registerServices(cl);
} finally {
writeLock.unlock();
}
}
public void unregisterOperationDescriptor(String operationName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.unregisterOperationDescriptor(operationName);
} finally {
writeLock.unlock();
}
}
public void clearOperationPreferences(String operationName, String productName) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
super.clearOperationPreferences(operationName, productName);
} finally {
writeLock.unlock();
}
}
/**
* Sets the {@link OperationCollection} containing the list of all the operations contained by the registry.
*
* @param coll
*/
public void setOperationCollection(OperationCollection coll) {
Lock writeLock = lock.writeLock();
try {
writeLock.lock();
this.collection = coll;
} finally {
writeLock.unlock();
}
}
/**
* This method returns an {@link OperationCollection} object containing all the registered operations.
*
* @return
*/
OperationCollection getOperationCollection() {
Lock readLock = lock.readLock();
try {
readLock.lock();
return collection;
} finally {
readLock.unlock();
}
}
/**
* Returns a {@link Collection} object containing a view of the {@link OperationCollection} inside the registry.
*
* @return
*/
public Collection<OperationItem> getOperations() {
Lock readLock = lock.readLock();
try {
readLock.lock();
return collection.getOperations();
} finally {
readLock.unlock();
}
}
/**
* Returns a Map containing the {@link OperationItem} objects for each operation. The jai parameter indicates whether must be returned the map of
* the jai operations or of the Jai-ext ones.
*
* @param jai
* @return
*/
public Map<String, OperationItem> getOperationMap(boolean jai) {
Lock readLock = lock.readLock();
try {
readLock.lock();
if (jai) {
return jaiMap;
} else {
return jaiExtMap;
}
} finally {
readLock.unlock();
}
}
/**
* This method internally check if the descriptor used is a
*
* @param descriptorName
* @param args
*/
void checkInterpolation(String descriptorName, Object[] args) {
// First check if the collection is present and then get the OperationItem associated
OperationItem item = null;
if (collection != null) {
item = collection.get(descriptorName);
}
// By default we do not change the Interpolation
boolean jaiext = true;
// If the item is present we check if it belongs to jaiext
if (item != null) {
jaiext = item.isJAIEXTProduct();
} else {
// Else we check the Descriptor vendor parameter
OperationDescriptor op = (OperationDescriptor) getDescriptor(
RenderedRegistryMode.MODE_NAME, descriptorName);
String vendor = op.getResourceBundle(null).getString(VENDOR_NAME);
jaiext = vendor.equalsIgnoreCase(JAIEXT_PRODUCT);
}
// If the operation is not a JAI-EXT one then we start to check if there is any Interpolation
// instance
if (!jaiext) {
// Cycle on the parameterBlock parameters
ParameterBlock block = (ParameterBlock) args[0];
Vector<Object> params = block.getParameters();
int index = 0;
for (Object param : params) {
if (param instanceof Interpolation) {
Interpolation interp = null;
// If the parameter is an instance of one of the JAI-EXT Interpolation classes
// then it is transformed into the related JAI Interpolation class.
if (param instanceof InterpolationNearest) {
interp = new javax.media.jai.InterpolationNearest();
} else if (param instanceof InterpolationBilinear) {
InterpolationBilinear bil = (InterpolationBilinear) param;
interp = new javax.media.jai.InterpolationBilinear(bil.getSubsampleBitsH());
} else if (param instanceof InterpolationBicubic) {
InterpolationBicubic bic = (InterpolationBicubic) param;
if (bic.isBicubic2()) {
interp = new javax.media.jai.InterpolationBicubic2(
bic.getSubsampleBitsH());
} else {
interp = new javax.media.jai.InterpolationBicubic(
bic.getSubsampleBitsH());
}
}
if (interp != null) {
block.set(interp, index);
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Converted JAI-EXT Interpolation object to JAI one");
}
}
break;
}
index++;
}
}
}
/**
* The {@link OperationItem} class is a wrapper for the {@link OperationDescriptor} class which can store informations about the operations and
* the associated factory.
*
* @author Nicola Lagomarsini GeoSolutions S.A.S.
*
*/
public static class OperationItem {
/** {@link OperationDescriptor} instance associated to the operation */
private OperationDescriptor op;
/** Descriptor vendor name */
private String vendor;
/** Operation Name */
private String opName;
/** Factory object (May be null) */
private Object factory;
/** MediaLib Factory object, used by JAI. (May be null) */
private Object mlibFactory;
/** Boolean indicating if the MediaLib acceleration must be used. By default is set to false */
private boolean isMediaLibPreferred;
public OperationItem(OperationDescriptor op) {
this.op = op;
this.opName = op.getName();
this.vendor = op.getResourceBundle(null).getString(VENDOR_NAME);
this.isMediaLibPreferred = false;
}
public OperationItem(OperationItem item) {
this.op = item.getDescriptor();
this.opName = item.getName();
this.vendor = item.getVendor();
this.factory = item.getFactory();
this.mlibFactory = item.getMlibFactory();
this.isMediaLibPreferred = item.isMediaLibPreferred;
}
public String getVendor() {
return vendor;
}
public String getName() {
return opName;
}
public OperationDescriptor getDescriptor() {
return op;
}
/***
* Returns the factory defined by the user. If medialib is preferred, then the MediaLib factory is returned, otherwise the JAI default factory
* is returned.
*
* @return
*/
public Object getCurrentFactory() {
if (mlibFactory != null && isMediaLibPreferred) {
return mlibFactory;
}
return factory;
}
public Object getFactory() {
return factory;
}
public Object getMlibFactory() {
return mlibFactory;
}
public OperationDescriptor getOp() {
return op;
}
public boolean isMediaLibPreferred() {
return isMediaLibPreferred;
}
public void setFactory(Object factory) {
this.factory = factory;
}
public void setMlibFactory(Object factory) {
this.mlibFactory = factory;
}
public void setMlibPreference(boolean preferred) {
this.isMediaLibPreferred = preferred;
}
/**
* Indicates if the {@link OperationItem} operation is a JAI-EXT one
*
* @return
*/
public boolean isJAIEXTProduct() {
return vendor.equalsIgnoreCase(JAIEXT_PRODUCT);
}
}
/**
* This class is a container class which stores internally all the {@link OperationItem}s, each one for an {@link OperationDescriptor}. This class
* contains all the operations inside an inner map and provides some utility methods for using it.
*
* @author Nicola Lagomarsini GeoSolutions S.A.S.
*
*/
static class OperationCollection {
/** Inner Map containing all the {@link OperationItem}s for each operation */
private Map<String, OperationItem> map = new ConcurrentHashMap<String, OperationItem>();
/** {@link OperationRegistry} used by the collection for registering and unregistering operations */
private OperationRegistry registry;
public OperationCollection(OperationRegistry registry, Map<String, OperationItem> map) {
this.map = map;
this.registry = registry;
}
public OperationCollection(OperationRegistry registry) {
this.registry = registry;
}
/**
* This method copies all the values inside a new {@link OperationCollection} instance
*/
public OperationCollection copy() {
Collection<OperationItem> values = map.values();
OperationCollection newColl = new OperationCollection(registry);
for (OperationItem item : values) {
newColl.add(new OperationItem(item));
}
return newColl;
}
/**
* This method populates the inner map with a List of {@link OperationDescriptor}s.
*
* @param listDesc
*/
public void createMapFromDescriptors(List<OperationDescriptor> listDesc) {
for (OperationDescriptor desc : listDesc) {
OperationItem value = createItem(desc);
map.put(desc.getName(), value);
}
}
/**
* This method returns a new {@link OperationCollection} instance filtered by the vendor name.
*
* @param vendor
* @return
*/
public OperationCollection filter(String vendor) {
Collection<OperationItem> values = map.values();
OperationCollection filtered = new OperationCollection(registry);
for (OperationItem item : values) {
if (item.getVendor().equalsIgnoreCase(vendor)) {
filtered.map.put(item.getName(), item);
}
}
return filtered;
}
/**
* Add a new Item to the map.
*
* @param item
*/
public void add(OperationItem item) {
map.put(item.getName(), item);
}
/**
* Add the contents of an external map inside the inner map.
*
* @param items
*/
public void add(Map<String, OperationItem> items) {
map.putAll(items);
}
/**
* Returns the {@link OperationItem} associated to the input operation name.
*
* @param decriptorname
* @return
*/
public OperationItem get(String decriptorname) {
return map.get(decriptorname);
}
/**
* Returns a view of the all the {@link OperationItem}s contained by the map.
*
* @return
*/
public Collection<OperationItem> getOperations() {
return map.values();
}
/**
* Creates a new {@link OperationItem} from an {@link OperationDescriptor}.
*
* @param desc
* @return
*/
public OperationItem createItem(OperationDescriptor desc) {
OperationItem value = new OperationItem(desc);
// Selection of a List of the Factories associated to the operation and the vendor
List<Object> list = registry.getOrderedFactoryList(RenderedRegistryMode.MODE_NAME,
desc.getName(), value.getVendor());
// If the List is not null then we start iterating on it.
if (list != null) {
// If there is the MediaLib factory, it is saved inside the OperationItem
// but it is not used by default
for (Object factory : list) {
if (factory.getClass().getName().contains("Mlib")) {
// Ensure Medialib is present
if(JAIExt.isMedialibavailable()){
value.setMlibFactory(factory);
}
} else {
value.setFactory(factory);
break;
}
}
}
return value;
}
/**
* This method substitutes all the operations contained by an external {@link OperationCollection} inside the current
* {@link OperationCollection}.
*
* @param changedOps
*/
void substituteOperations(OperationCollection changedOps) {
// Selection of all the operations of the external OperationCollection
Map<String, OperationItem> mapChanged = changedOps.map;
Collection<OperationItem> items = mapChanged.values();
// Iteration on all the new operations and registration of them
for (OperationItem item : items) {
substituteDescriptors(item);
// Insert the new Item inside the map
map.put(item.getName(), item);
}
}
/**
* This method returns a new {@link OperationCollection} containing
* operations which are present in this collection but aren't
* available in the external one nor in the operation groups
* (Such as algebric group for add, subtract, divide, multiply,...)
*
* @param external
*/
OperationCollection getUniqueOperations(OperationCollection external) {
Map<String, OperationItem> externalMap = external.map;
// Iteration on all the new operations and registration of them
Collection<OperationItem> externalItems = externalMap.values();
OperationCollection uniqueOperations = new OperationCollection(registry);
Set<String> groupingNames = JAIExt.NAME_MAPPING.keySet();
for (OperationItem item : externalItems) {
String name = item.getName();
if (!map.containsKey(name) && !groupingNames.contains(name)) {
uniqueOperations.add(item);
}
}
return uniqueOperations;
}
/**
* This method substitute an old {@link OperationItem} object with a new one, if not already present.
*
* @param changedOp
*/
private void substituteDescriptors(OperationItem changedOp) {
// Selection of the old OperationItem
OperationItem operationItem = map.get(changedOp.getName());
// Check if the item is present
boolean present = operationItem != null
&& !operationItem.getVendor().equalsIgnoreCase(changedOp.getVendor());
// Selection of the new factory
Object factory = changedOp.getCurrentFactory();
// If the OperationItem is already present, then it is unregistered and the new item is registered.
if (present) {
// Unregistering Descriptor and Factory
Object currentFactory = operationItem.getCurrentFactory();
boolean registerFactory = factory == null
|| (currentFactory != null && !currentFactory.getClass().isAssignableFrom(factory.getClass()));
if (currentFactory != null && registerFactory) {
//registry.unregisterFactory(RenderedRegistryMode.MODE_NAME, operationItem
//.getDescriptor().getName(), operationItem.getVendor(), currentFactory);
}
registry.unregisterDescriptor(operationItem.getDescriptor());
// registering descriptor
registry.registerDescriptor(changedOp.getDescriptor());
// registering factory
if (factory != null) {
registry.registerFactory(RenderedRegistryMode.MODE_NAME, changedOp
.getDescriptor().getName(), changedOp.getVendor(), changedOp
.getCurrentFactory());
//registry.setFactoryPreference(RenderedRegistryMode.MODE_NAME,
//changedOp.getDescriptor().getName(),
//changedOp.getVendor(),
//factory,
//currentFactory);
}
} else {
// If the operationItem is null then it is registered
if (operationItem == null) {
// registering descriptor
registry.registerDescriptor(changedOp.getDescriptor());
// registering factory
if (changedOp.getCurrentFactory() != null) {
registry.registerFactory(RenderedRegistryMode.MODE_NAME, changedOp
.getDescriptor().getName(), changedOp.getVendor(), changedOp
.getCurrentFactory());
}
}
}
}
/**
* This method add a new {@link OperationItem} inside the map, replacing an old one if present.
*
* @param changedOp
*/
public void substituteSingleOp(OperationItem changedOp) {
map.put(changedOp.getName(), changedOp);
}
/**
* This method substitute the factory associated to the operation
*
* @param factory
* @param descriptorName
* @param vendor
*/
public void substituteFactory(Object factory, String descriptorName, String vendor) {
OperationItem item = map.get(descriptorName);
// Check if the Operation descriptor is present
boolean present = item != null && item.getVendor().equalsIgnoreCase(vendor);
// If present, the factory is set.
if (present) {
if (factory.getClass().getName().contains("Mlib")) {
item.setMlibFactory(factory);
item.setMlibPreference(true);
} else {
item.setFactory(factory);
item.setMlibPreference(false);
}
} else {
// Create a new Item and set it in the map
RegistryElementDescriptor desc = registry.getDescriptor(
RenderedRegistryMode.MODE_NAME, descriptorName);
// The new item is added
if (desc != null && desc instanceof OperationDescriptor) {
try {
OperationItem itemNew = new OperationItem((OperationDescriptor) desc);
if (factory.getClass().getName().contains("Mlib")) {
itemNew.setMlibFactory(factory);
itemNew.setMlibPreference(true);
} else {
itemNew.setFactory(factory);
itemNew.setMlibPreference(false);
}
map.put(descriptorName, itemNew);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
"Unable to register the Factory for the following descriptor: "
+ descriptorName, e);
}
} else {
throw new IllegalArgumentException(
"Unable to register the Factory for the following descriptor: "
+ descriptorName);
}
}
}
/**
* Removes an {@link OperationItem} from the inner map
*
* @param operationItem
*/
public void removeSingleOp(OperationItem operationItem) {
map.remove(operationItem.getName());
}
/**
* Removes the factory from the map.
*
* @param factory
* @param descriptorName
* @param productName
*/
public void removeFactory(Object factory, String descriptorName, String productName) {
OperationItem item = map.get(descriptorName);
// Check if the Operation descriptor is present
boolean present = item != null && item.getVendor().equalsIgnoreCase(productName);
if (present) {
item.setFactory(null);
item.setMlibFactory(null);
item.setMlibPreference(false);
} else {
// Create a new Item and set it in the map without defining the factory
RegistryElementDescriptor desc = registry.getDescriptor(
RenderedRegistryMode.MODE_NAME, descriptorName);
if (desc != null && desc instanceof OperationDescriptor) {
OperationItem itemNew = new OperationItem((OperationDescriptor) desc);
map.put(descriptorName, itemNew);
} else {
throw new IllegalArgumentException(
"Unable to unregister the Factory for the following descriptor: "
+ descriptorName);
}
}
}
}
}